Skip to content

Commit 3a2daf1

Browse files
committed
Add room loading screen and loading tabs
Introduce RoomLoadingScreen with tab actions, and use it in room, invite, and space lobby screens to replace the old restore status UI.
1 parent 0eccb92 commit 3a2daf1

File tree

6 files changed

+324
-27
lines changed

6 files changed

+324
-27
lines changed

src/home/invite_screen.rs

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use std::ops::Deref;
88
use makepad_widgets::*;
99
use matrix_sdk::ruma::OwnedRoomId;
1010

11-
use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, FetchedRoomAvatar}, shared::{avatar::AvatarWidgetRefExt, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt}, sliding_sync::{submit_async_request, MatrixRequest}, utils::{self, RoomNameId}};
11+
use crate::{app::AppStateAction, home::rooms_list::RoomsListRef, join_leave_room_modal::{JoinLeaveModalKind, JoinLeaveRoomModalAction}, room::{BasicRoomDetails, FetchedRoomAvatar, loading_screen::RoomLoadingScreenWidgetExt}, shared::{avatar::AvatarWidgetRefExt, popup_list::{PopupItem, PopupKind, enqueue_popup_notification}}, sliding_sync::{MatrixRequest, submit_async_request}, utils::{self, RoomNameId}};
1212

1313
use super::rooms_list::{InviteState, InviterInfo};
1414

@@ -22,7 +22,7 @@ live_design! {
2222
use crate::shared::styles::*;
2323
use crate::shared::avatar::*;
2424
use crate::shared::icon_button::*;
25-
use crate::shared::restore_status_view::*;
25+
use crate::room::loading_screen::RoomLoadingScreen;
2626

2727
pub InviteScreen = {{InviteScreen}}<ScrollXYView> {
2828
width: Fill,
@@ -36,7 +36,7 @@ live_design! {
3636
draw_bg: {
3737
color: (COLOR_PRIMARY_DARKER),
3838
}
39-
restore_status_view = <RestoreStatusView> {}
39+
loading_screen = <RoomLoadingScreen> { visible: false }
4040

4141
// This view is only shown if `inviter` is Some.
4242
inviter_view = <View> {
@@ -394,11 +394,14 @@ impl Widget for InviteScreen {
394394

395395
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
396396
if !self.is_loaded {
397-
let mut restore_status_view = self.view.restore_status_view(ids!(restore_status_view));
398-
if let Some(room_name) = &self.room_name_id {
399-
restore_status_view.set_content(cx, self.all_rooms_loaded, room_name);
400-
}
401-
return restore_status_view.draw(cx, scope);
397+
let mut loading_screen = self.view.room_loading_screen(ids!(loading_screen));
398+
let (title, details) = if let Some(room_name) = &self.room_name_id {
399+
self.loading_screen_content(room_name)
400+
} else {
401+
("Loading...".to_string(), None)
402+
};
403+
loading_screen.show(cx, Some(&title), details.as_deref());
404+
return loading_screen.draw(cx, scope);
402405
}
403406
let Some(info) = self.info.as_ref() else {
404407
// If we don't have any info, just return.
@@ -534,16 +537,28 @@ impl InviteScreen {
534537
self.redraw(cx);
535538
}
536539

537-
let restore_status_view = self.view.restore_status_view(ids!(restore_status_view));
540+
let loading_screen = self.view.room_loading_screen(ids!(loading_screen));
538541
if !self.is_loaded {
539-
restore_status_view.set_content(
540-
cx,
541-
self.all_rooms_loaded,
542-
room_name_id,
543-
);
544-
restore_status_view.set_visible(cx, true);
542+
let (title, details) = self.loading_screen_content(room_name_id);
543+
loading_screen.show(cx, Some(&title), details.as_deref());
544+
} else {
545+
loading_screen.hide(cx);
546+
}
547+
}
548+
549+
fn loading_screen_content(&self, room_name: &RoomNameId) -> (String, Option<String>) {
550+
if self.all_rooms_loaded {
551+
(
552+
format!(
553+
"Room {room_name} was not found in the homeserver's list of all rooms."
554+
),
555+
Some("You may close this screen.".to_owned()),
556+
)
545557
} else {
546-
restore_status_view.set_visible(cx, false);
558+
(
559+
"Waiting for this room to be loaded from the homeserver".to_owned(),
560+
None,
561+
)
547562
}
548563
}
549564
}

src/home/main_desktop_ui.rs

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use ruma::OwnedRoomId;
33
use tokio::sync::Notify;
44
use std::{collections::HashMap, sync::Arc};
55

6-
use crate::{app::{AppState, AppStateAction, SavedDockState, SelectedRoom}, home::{navigation_tab_bar::{NavigationBarAction, SelectedTab}, rooms_list::RoomsListRef, space_lobby::SpaceLobbyScreenWidgetRefExt}, utils::RoomNameId};
6+
use crate::{app::{AppState, AppStateAction, SavedDockState, SelectedRoom}, home::{navigation_tab_bar::{NavigationBarAction, SelectedTab}, rooms_list::RoomsListRef, space_lobby::SpaceLobbyScreenWidgetRefExt}, room::loading_screen::{RoomLoadingScreenAction, RoomLoadingScreenWidgetRefExt, get_room_loading_screen_actions, loading_tab_live_id}, utils::RoomNameId};
77
use super::{invite_screen::InviteScreenWidgetRefExt, room_screen::RoomScreenWidgetRefExt, rooms_list::RoomsListAction};
88

99
live_design! {
@@ -18,6 +18,7 @@ live_design! {
1818
use crate::home::room_screen::RoomScreen;
1919
use crate::home::invite_screen::InviteScreen;
2020
use crate::home::space_lobby::SpaceLobbyScreen;
21+
use crate::room::loading_screen::RoomLoadingScreen;
2122

2223
pub MainDesktopUI = {{MainDesktopUI}} {
2324
dock = <Dock> {
@@ -59,6 +60,7 @@ live_design! {
5960
room_screen = <RoomScreen> {}
6061
invite_screen = <InviteScreen> {}
6162
space_lobby_screen = <SpaceLobbyScreen> {}
63+
loading_screen = <RoomLoadingScreen> { visible: true }
6264
}
6365
}
6466
}
@@ -77,6 +79,9 @@ pub struct MainDesktopUI {
7779
#[rust]
7880
open_rooms: HashMap<LiveId, SelectedRoom>,
7981

82+
#[rust]
83+
loading_tabs: HashMap<LiveId, (Option<String>, Option<String>)>,
84+
8085
/// The tab that should be closed in the next draw event
8186
#[rust]
8287
tab_to_close: Option<LiveId>,
@@ -114,6 +119,19 @@ impl LiveHook for MainDesktopUI {
114119

115120
impl Widget for MainDesktopUI {
116121
fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
122+
if let Event::Signal = event {
123+
for action in get_room_loading_screen_actions() {
124+
match action {
125+
RoomLoadingScreenAction::ShowTab { tab_id, tab_name, title, details } => {
126+
self.show_loading_tab(cx, tab_id, &tab_name, title.as_deref(), details.as_deref());
127+
}
128+
RoomLoadingScreenAction::HideTab { tab_id } => {
129+
self.close_loading_tab(cx, tab_id);
130+
}
131+
}
132+
}
133+
}
134+
117135
self.widget_match_event(cx, event, scope); // invokes `WidgetMatchEvent` impl
118136
self.view.handle_event(cx, event, scope);
119137
}
@@ -143,6 +161,11 @@ impl MainDesktopUI {
143161

144162
let dock = self.view.dock(ids!(dock));
145163

164+
let loading_id = loading_tab_live_id(room.room_id().as_str());
165+
if self.loading_tabs.remove(&loading_id).is_some() {
166+
dock.close_tab(cx, loading_id);
167+
}
168+
146169
// If the room is already open, select (jump to) its existing tab
147170
let room_id_as_live_id = LiveId::from_str(room.room_id().as_str());
148171
if self.open_rooms.contains_key(&room_id_as_live_id) {
@@ -389,6 +412,52 @@ impl MainDesktopUI {
389412
app_state.selected_room = selected_room;
390413
self.redraw(cx);
391414
}
415+
416+
fn show_loading_tab(&mut self, cx: &mut Cx, tab_id: LiveId, tab_name: &str, title: Option<&str>, details: Option<&str>) {
417+
let dock_ref = self.view.dock(ids!(dock));
418+
419+
// If the tab already exists and is a loading tab, just update it and select it.
420+
let mut should_select_existing = false;
421+
if let Some(mut dock) = dock_ref.borrow_mut() {
422+
if let Some((_, widget)) = dock.items().get(&tab_id) {
423+
widget.as_room_loading_screen().show(cx, title, details);
424+
self.loading_tabs.insert(tab_id, (title.map(str::to_owned), details.map(str::to_owned)));
425+
should_select_existing = true;
426+
}
427+
}
428+
429+
if should_select_existing {
430+
dock_ref.select_tab(cx, tab_id);
431+
return;
432+
}
433+
434+
// Otherwise, create a new loading tab at the end.
435+
let (tab_bar, _pos) = dock_ref.find_tab_bar_of_tab(id!(home_tab)).unwrap();
436+
let new_tab_widget = dock_ref.create_and_select_tab(
437+
cx,
438+
tab_bar,
439+
tab_id,
440+
id!(loading_screen),
441+
tab_name.to_string(),
442+
id!(CloseableTab),
443+
None,
444+
);
445+
446+
if let Some(widget) = new_tab_widget {
447+
widget.as_room_loading_screen().show(cx, title, details);
448+
self.loading_tabs.insert(tab_id, (title.map(str::to_owned), details.map(str::to_owned)));
449+
dock_ref.select_tab(cx, tab_id);
450+
} else {
451+
error!("BUG: failed to create loading tab for {tab_name}");
452+
}
453+
454+
}
455+
456+
fn close_loading_tab(&mut self, cx: &mut Cx, tab_id: LiveId) {
457+
if self.loading_tabs.remove(&tab_id).is_some() {
458+
self.view.dock(ids!(dock)).close_tab(cx, tab_id);
459+
}
460+
}
392461
}
393462

394463
impl WidgetMatchEvent for MainDesktopUI {

src/home/room_screen.rs

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,9 @@ use crate::{
2929
user_profile::{ShowUserProfileAction, UserProfile, UserProfileAndRoomId, UserProfilePaneInfo, UserProfileSlidingPaneRef, UserProfileSlidingPaneWidgetExt},
3030
user_profile_cache,
3131
},
32-
room::{BasicRoomDetails, room_input_bar::RoomInputBarState, typing_notice::TypingNoticeWidgetExt},
32+
room::{BasicRoomDetails, loading_screen::RoomLoadingScreenWidgetExt, room_input_bar::RoomInputBarState, typing_notice::TypingNoticeWidgetExt},
3333
shared::{
34-
avatar::{AvatarState, AvatarWidgetRefExt}, callout_tooltip::{CalloutTooltipOptions, TooltipAction, TooltipPosition}, confirmation_modal::ConfirmationModalContent, html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt, RobrixHtmlLinkAction}, image_viewer::{ImageViewerAction, ImageViewerMetaData, LoadState}, jump_to_bottom_button::{JumpToBottomButtonWidgetExt, UnreadMessageCount}, popup_list::{PopupItem, PopupKind, enqueue_popup_notification}, restore_status_view::RestoreStatusViewWidgetExt, styles::*, text_or_image::{TextOrImageAction, TextOrImageRef, TextOrImageWidgetRefExt}, timestamp::TimestampWidgetRefExt
34+
avatar::{AvatarState, AvatarWidgetRefExt}, callout_tooltip::{CalloutTooltipOptions, TooltipAction, TooltipPosition}, confirmation_modal::ConfirmationModalContent, html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt, RobrixHtmlLinkAction}, image_viewer::{ImageViewerAction, ImageViewerMetaData, LoadState}, jump_to_bottom_button::{JumpToBottomButtonWidgetExt, UnreadMessageCount}, popup_list::{PopupItem, PopupKind, enqueue_popup_notification}, styles::*, text_or_image::{TextOrImageAction, TextOrImageRef, TextOrImageWidgetRefExt}, timestamp::TimestampWidgetRefExt
3535
},
3636
sliding_sync::{BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels, get_client, submit_async_request, take_timeline_endpoints}, utils::{self, ImageFormat, MEDIA_THUMBNAIL_FORMAT, RoomNameId, unix_time_millis_to_datetime}
3737
};
@@ -78,7 +78,7 @@ live_design! {
7878
use crate::room::typing_notice::*;
7979
use crate::home::room_read_receipt::*;
8080
use crate::rooms_list::*;
81-
use crate::shared::restore_status_view::*;
81+
use crate::room::loading_screen::RoomLoadingScreen;
8282
use crate::home::link_preview::LinkPreview;
8383
use link::tsp_link::TspSignIndicator;
8484

@@ -516,7 +516,7 @@ live_design! {
516516
color: (COLOR_PRIMARY_DARKER)
517517
}
518518

519-
restore_status_view = <RestoreStatusView> {}
519+
loading_screen = <RoomLoadingScreen> { visible: false }
520520

521521
// Widgets within this view will get shifted upwards when the on-screen keyboard is shown.
522522
keyboard_view = <KeyboardView> {
@@ -976,15 +976,16 @@ impl Widget for RoomScreen {
976976

977977

978978
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
979-
// If the room isn't loaded yet, we show the restore status label only.
979+
// If the room isn't loaded yet, we show the loading screen only.
980980
if !self.is_loaded {
981981
let Some(room_name) = &self.room_name_id else {
982982
// No room selected yet, nothing to show.
983983
return DrawStep::done();
984984
};
985-
let mut restore_status_view = self.view.restore_status_view(ids!(restore_status_view));
986-
restore_status_view.set_content(cx, self.all_rooms_loaded, room_name);
987-
return restore_status_view.draw(cx, scope);
985+
let mut loading_screen = self.view.room_loading_screen(ids!(loading_screen));
986+
let (title, details) = self.loading_screen_content(room_name);
987+
loading_screen.show(cx, Some(&title), details.as_deref());
988+
return loading_screen.draw(cx, scope);
988989
}
989990
if self.tl_state.is_none() {
990991
// Tl_state may not be ready after dock loading.
@@ -1166,6 +1167,36 @@ impl RoomScreen {
11661167
self.room_name_id.as_ref().map(|r| r.room_id())
11671168
}
11681169

1170+
fn loading_screen_content(&self, room_name: &RoomNameId) -> (String, Option<String>) {
1171+
if self.all_rooms_loaded {
1172+
(
1173+
format!(
1174+
"Room {room_name} was not found in the homeserver's list of all rooms."
1175+
),
1176+
Some("You may close this screen.".to_owned()),
1177+
)
1178+
} else {
1179+
(
1180+
"Waiting for this room to be loaded from the homeserver".to_owned(),
1181+
None,
1182+
)
1183+
}
1184+
}
1185+
1186+
fn update_loading_screen(&mut self, cx: &mut Cx) {
1187+
let loading_screen = self.view.room_loading_screen(ids!(loading_screen));
1188+
if self.is_loaded {
1189+
loading_screen.hide(cx);
1190+
return;
1191+
}
1192+
let Some(room_name) = &self.room_name_id else {
1193+
loading_screen.hide(cx);
1194+
return;
1195+
};
1196+
let (title, details) = self.loading_screen_content(room_name);
1197+
loading_screen.show(cx, Some(&title), details.as_deref());
1198+
}
1199+
11691200
/// Processes all pending background updates to the currently-shown timeline.
11701201
///
11711202
/// Redraws this RoomScreen view if any updates were applied.
@@ -2154,7 +2185,7 @@ impl RoomScreen {
21542185
self.is_loaded = is_loaded_now;
21552186
}
21562187

2157-
self.view.restore_status_view(ids!(restore_status_view)).set_visible(cx, !self.is_loaded);
2188+
self.update_loading_screen(cx);
21582189

21592190
// Kick off a back pagination request if it's the first time loading this room,
21602191
// because we want to show the user some messages as soon as possible

src/home/space_lobby.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use matrix_sdk_ui::spaces::SpaceRoom;
1414
use ruma::room::JoinRuleSummary;
1515
use tokio::sync::mpsc::UnboundedSender;
1616
use crate::{
17-
home::rooms_list::RoomsListRef, shared::avatar::{AvatarState, AvatarWidgetExt, AvatarWidgetRefExt}, space_service_sync::{SpaceRequest, SpaceRoomExt, SpaceRoomListAction}, utils::{self, RoomNameId}
17+
home::rooms_list::RoomsListRef, room::loading_screen::RoomLoadingScreenWidgetExt, shared::avatar::{AvatarState, AvatarWidgetExt, AvatarWidgetRefExt}, space_service_sync::{SpaceRequest, SpaceRoomExt, SpaceRoomListAction}, utils::{self, RoomNameId}
1818
};
1919

2020

@@ -26,6 +26,7 @@ live_design! {
2626
use crate::shared::styles::*;
2727
use crate::shared::helpers::*;
2828
use crate::shared::avatar::*;
29+
use crate::room::loading_screen::RoomLoadingScreen;
2930

3031
ICON_COLLAPSE = dep("crate://self/resources/icons/triangle_fill.svg")
3132

@@ -378,6 +379,8 @@ live_design! {
378379
color: #fff
379380
}
380381

382+
loading_screen = <RoomLoadingScreen> { visible: false }
383+
381384
// Header with parent space info
382385
header = <View> {
383386
width: Fill,
@@ -739,6 +742,13 @@ impl Widget for SpaceLobbyScreen {
739742
}
740743

741744
fn draw_walk(&mut self, cx: &mut Cx2d, scope: &mut Scope, walk: Walk) -> DrawStep {
745+
if self.is_loading {
746+
let mut loading_screen = self.view.room_loading_screen(ids!(loading_screen));
747+
loading_screen.show(cx, Some("Loading rooms and spaces..."), None);
748+
return loading_screen.draw(cx, scope);
749+
}
750+
self.view.room_loading_screen(ids!(loading_screen)).hide(cx);
751+
742752
while let Some(widget_to_draw) = self.view.draw_walk(cx, scope, walk).step() {
743753
let portal_list_ref = widget_to_draw.as_portal_list();
744754
let Some(mut list) = portal_list_ref.borrow_mut() else { continue };

0 commit comments

Comments
 (0)