@@ -3,7 +3,7 @@ use matrix_sdk::ruma::OwnedRoomId;
33use tokio:: sync:: Notify ;
44use std:: { collections:: HashMap , sync:: Arc } ;
55
6- use crate :: { app:: { AppState , AppStateAction , SelectedRoom } , utils:: room_name_or_id} ;
6+ use crate :: { app:: { AppState , AppStateAction , SelectedRoom } , room :: loading_screen :: { RoomLoadingScreenAction , RoomLoadingScreenWidgetRefExt , drain_room_loading_screen_actions , loading_tab_live_id } , utils:: room_name_or_id} ;
77use super :: { invite_screen:: InviteScreenWidgetRefExt , room_screen:: RoomScreenWidgetRefExt , rooms_list:: RoomsListAction } ;
88
99live_design ! {
@@ -17,6 +17,7 @@ live_design! {
1717 use crate :: home:: welcome_screen:: WelcomeScreen ;
1818 use crate :: home:: room_screen:: RoomScreen ;
1919 use crate :: home:: invite_screen:: InviteScreen ;
20+ use crate :: room:: loading_screen:: RoomLoadingScreen ;
2021
2122 pub MainDesktopUI = { { MainDesktopUI } } {
2223 dock = <Dock > {
@@ -54,6 +55,7 @@ live_design! {
5455 welcome_screen = <WelcomeScreen > { }
5556 room_screen = <RoomScreen > { }
5657 invite_screen = <InviteScreen > { }
58+ loading_screen = <RoomLoadingScreen > { visible: true }
5759 }
5860 }
5961}
@@ -67,6 +69,10 @@ pub struct MainDesktopUI {
6769 #[ rust]
6870 open_rooms : HashMap < LiveId , SelectedRoom > ,
6971
72+ /// Tabs that are currently showing a loading screen (tab_id -> last message).
73+ #[ rust]
74+ loading_tabs : HashMap < LiveId , ( Option < String > , Option < String > ) > ,
75+
7076 /// The tab that should be closed in the next draw event
7177 #[ rust]
7278 tab_to_close : Option < LiveId > ,
@@ -92,6 +98,20 @@ pub struct MainDesktopUI {
9298
9399impl Widget for MainDesktopUI {
94100 fn handle_event ( & mut self , cx : & mut Cx , event : & Event , scope : & mut Scope ) {
101+ // Apply queued loading tab actions when the UI thread is signalled.
102+ if let Event :: Signal = event {
103+ for action in drain_room_loading_screen_actions ( ) {
104+ match action {
105+ RoomLoadingScreenAction :: ShowTab { tab_id, tab_name, message, details } => {
106+ self . show_loading_tab ( cx, tab_id, & tab_name, message. as_deref ( ) , details. as_deref ( ) ) ;
107+ }
108+ RoomLoadingScreenAction :: HideTab { tab_id } => {
109+ self . close_loading_tab ( cx, tab_id) ;
110+ }
111+ }
112+ }
113+ }
114+
95115 self . widget_match_event ( cx, event, scope) ; // invokes `WidgetMatchEvent` impl
96116 self . view . handle_event ( cx, event, scope) ;
97117 }
@@ -121,6 +141,10 @@ impl MainDesktopUI {
121141
122142 // If the room is already open, select (jump to) its existing tab
123143 let room_id_as_live_id = LiveId :: from_str ( room. room_id ( ) . as_str ( ) ) ;
144+ let loading_id = loading_tab_live_id ( room. room_id ( ) . as_str ( ) ) ;
145+ if self . loading_tabs . remove ( & loading_id) . is_some ( ) {
146+ dock. close_tab ( cx, loading_id) ;
147+ }
124148 if self . open_rooms . contains_key ( & room_id_as_live_id) {
125149 dock. select_tab ( cx, room_id_as_live_id) ;
126150 self . most_recently_selected_room = Some ( room) ;
@@ -204,6 +228,8 @@ impl MainDesktopUI {
204228 dock. select_tab ( cx, id ! ( home_tab) ) ;
205229 self . most_recently_selected_room = None ;
206230 }
231+ } else if self . loading_tabs . remove ( & tab_id) . is_some ( ) {
232+ // Nothing else to do; just close the loading tab.
207233 }
208234
209235 dock. close_tab ( cx, tab_id) ;
@@ -226,6 +252,57 @@ impl MainDesktopUI {
226252 self . tab_to_close = None ;
227253 self . room_order . clear ( ) ;
228254 self . most_recently_selected_room = None ;
255+
256+ for tab_id in self . loading_tabs . keys ( ) . copied ( ) . collect :: < Vec < _ > > ( ) {
257+ dock. close_tab ( cx, tab_id) ;
258+ }
259+ self . loading_tabs . clear ( ) ;
260+ }
261+
262+ /// Show or create a loading-only tab.
263+ fn show_loading_tab ( & mut self , cx : & mut Cx , tab_id : LiveId , tab_name : & str , message : Option < & str > , details : Option < & str > ) {
264+ let dock_ref = self . view . dock ( ids ! ( dock) ) ;
265+
266+ // If the tab already exists and is a loading tab, just update it and select it.
267+ let mut should_select_existing = false ;
268+ if let Some ( mut dock) = dock_ref. borrow_mut ( ) {
269+ if let Some ( ( _, widget) ) = dock. items ( ) . get ( & tab_id) {
270+ widget. as_room_loading_screen ( ) . show ( cx, message, details) ;
271+ self . loading_tabs . insert ( tab_id, ( message. map ( str:: to_owned) , details. map ( str:: to_owned) ) ) ;
272+ should_select_existing = true ;
273+ }
274+ }
275+ if should_select_existing {
276+ dock_ref. select_tab ( cx, tab_id) ;
277+ return ;
278+ }
279+
280+ // Otherwise, create a new loading tab at the end.
281+ let ( tab_bar, _pos) = dock_ref. find_tab_bar_of_tab ( id ! ( home_tab) ) . unwrap ( ) ;
282+ let new_tab_widget = dock_ref. create_and_select_tab (
283+ cx,
284+ tab_bar,
285+ tab_id,
286+ id ! ( loading_screen) ,
287+ tab_name. to_string ( ) ,
288+ id ! ( CloseableTab ) ,
289+ None ,
290+ ) ;
291+
292+ if let Some ( widget) = new_tab_widget {
293+ widget. as_room_loading_screen ( ) . show ( cx, message, details) ;
294+ self . loading_tabs . insert ( tab_id, ( message. map ( str:: to_owned) , details. map ( str:: to_owned) ) ) ;
295+ dock_ref. select_tab ( cx, tab_id) ;
296+ } else {
297+ error ! ( "BUG: failed to create loading tab for {tab_name}" ) ;
298+ }
299+ }
300+
301+ /// Close a loading-only tab if it exists.
302+ fn close_loading_tab ( & mut self , cx : & mut Cx , tab_id : LiveId ) {
303+ if self . loading_tabs . remove ( & tab_id) . is_some ( ) {
304+ self . view . dock ( ids ! ( dock) ) . close_tab ( cx, tab_id) ;
305+ }
229306 }
230307
231308 /// Replaces an invite with a joined room in the dock.
0 commit comments