Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 8 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,15 @@ use makepad_widgets::{makepad_micro_serde::*, *};
use matrix_sdk::ruma::{OwnedRoomId, RoomId};
use crate::{
avatar_cache::clear_avatar_cache, home::{
main_desktop_ui::MainDesktopUiAction, new_message_context_menu::NewMessageContextMenuWidgetRefExt, room_screen::{clear_timeline_states, MessageAction}, rooms_list::{clear_all_invited_rooms, enqueue_rooms_list_update, RoomsListAction, RoomsListRef, RoomsListUpdate}
main_desktop_ui::MainDesktopUiAction, new_message_context_menu::NewMessageContextMenuWidgetRefExt, room_screen::{MessageAction, clear_timeline_states}, rooms_list::{RoomsListAction, RoomsListRef, RoomsListUpdate, clear_all_invited_rooms, enqueue_rooms_list_update}
}, join_leave_room_modal::{
JoinLeaveModalKind, JoinLeaveRoomModalAction, JoinLeaveRoomModalWidgetRefExt
}, login::login_screen::LoginAction, logout::logout_confirm_modal::{LogoutAction, LogoutConfirmModalAction, LogoutConfirmModalWidgetRefExt}, persistence, profile::user_profile_cache::clear_user_profile_cache, room::BasicRoomDetails, shared::callout_tooltip::{
CalloutTooltipOptions,
CalloutTooltipWidgetRefExt,
TooltipAction,
}, sliding_sync::current_user_id, utils::{
room_name_or_id,
OwnedRoomIdRon,
OwnedRoomIdRon, room_name_or_id
}, verification::VerificationAction, verification_modal::{
VerificationModalAction,
VerificationModalWidgetRefExt,
Expand Down Expand Up @@ -630,20 +629,26 @@ pub enum SelectedRoom {
room_id: OwnedRoomIdRon,
room_name: Option<String>,
},
PreviewedRoom {
room_id: OwnedRoomIdRon,
room_name: Option<String>,
},
}

impl SelectedRoom {
pub fn room_id(&self) -> &OwnedRoomId {
match self {
SelectedRoom::JoinedRoom { room_id, .. } => room_id,
SelectedRoom::InvitedRoom { room_id, .. } => room_id,
SelectedRoom::PreviewedRoom { room_id, .. } => room_id,
}
}

pub fn room_name(&self) -> Option<&String> {
match self {
SelectedRoom::JoinedRoom { room_name, .. } => room_name.as_ref(),
SelectedRoom::InvitedRoom { room_name, .. } => room_name.as_ref(),
SelectedRoom::PreviewedRoom { room_name, .. } => room_name.as_ref(),
}
}

Expand Down
91 changes: 90 additions & 1 deletion src/home/main_desktop_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use matrix_sdk::ruma::OwnedRoomId;
use tokio::sync::Notify;
use std::{collections::HashMap, sync::Arc};

use crate::{app::{AppState, AppStateAction, SelectedRoom}, utils::room_name_or_id};
use crate::{app::{AppState, AppStateAction, SelectedRoom}, room::{BasicRoomDetails, FetchedRoomPreview, RoomPreviewAction, can_not_preview_screen::{CanNotPreviewDetails, CanNotPreviewScreenWidgetRefExt}}, shared::popup_list::{PopupItem, PopupKind, enqueue_popup_notification}, utils::room_name_or_id};
use super::{invite_screen::InviteScreenWidgetRefExt, room_screen::RoomScreenWidgetRefExt, rooms_list::RoomsListAction};

live_design! {
Expand All @@ -17,6 +17,7 @@ live_design! {
use crate::home::welcome_screen::WelcomeScreen;
use crate::home::room_screen::RoomScreen;
use crate::home::invite_screen::InviteScreen;
use crate::room::can_not_preview_screen::CanNotPreviewScreen;

pub MainDesktopUI = {{MainDesktopUI}} {
dock = <Dock> {
Expand Down Expand Up @@ -54,6 +55,7 @@ live_design! {
welcome_screen = <WelcomeScreen> {}
room_screen = <RoomScreen> {}
invite_screen = <InviteScreen> {}
can_not_preview_screen = <CanNotPreviewScreen> {}
}
}
}
Expand Down Expand Up @@ -138,6 +140,7 @@ impl MainDesktopUI {
id!(invite_screen),
room_name_or_id(room_name.as_ref(), room_id),
),
_ => return
};
let new_tab_widget = dock.create_and_select_tab(
cx,
Expand Down Expand Up @@ -168,6 +171,7 @@ impl MainDesktopUI {
room.room_name().cloned()
);
}
_ => {}
}
cx.action(MainDesktopUiAction::SaveDockIntoAppState);
} else {
Expand All @@ -178,6 +182,77 @@ impl MainDesktopUI {
self.most_recently_selected_room = Some(room);
}

fn focus_or_crate_preview_screen_tab(&mut self, cx: &mut Cx, preview_info: &FetchedRoomPreview) {
let room_id = preview_info.room_id.clone();
let room_name = preview_info.name.clone();
let is_world_readable = preview_info.room_preview.is_world_readable.unwrap_or(false);

let dock = self.view.dock(ids!(dock));
let selected_room = SelectedRoom::PreviewedRoom { room_id: room_id.to_owned().into(), room_name: room_name.clone() };

// Do nothing if the room to select is already created and focused.
if self.most_recently_selected_room.as_ref().is_some_and(|r| r == &selected_room) {
return;
}

// If the room is already open, select (jump to) its existing tab
let room_id_as_live_id = LiveId::from_str(room_id.as_str());
if self.open_rooms.contains_key(&room_id_as_live_id) {
dock.select_tab(cx, room_id_as_live_id);
self.most_recently_selected_room = Some(selected_room);
return;
}


// Create a new tab for the room preview
let (tab_bar, _pos) = dock.find_tab_bar_of_tab(id!(home_tab)).unwrap();
let (kind, name) = if is_world_readable {
(id!(room_screen), room_name_or_id(room_name.as_ref(), &room_id))
} else {
(id!(can_not_preview_screen), room_name_or_id(room_name.as_ref(), &room_id))
};

let new_tab_widget = dock.create_and_select_tab(
cx,
tab_bar,
room_id_as_live_id,
kind,
name,
id!(CloseableTab),
None,
);

if let Some(new_widget) = new_tab_widget {
self.room_order.push(selected_room.clone());
if is_world_readable {
new_widget.as_room_screen().set_displayed_room(
cx,
room_id.clone().into(),
selected_room.room_name().cloned(),
);
} else {
new_widget.as_can_not_preview_screen().set_displayed(
cx,
room_id.clone().into(),
selected_room.room_name().cloned(),
CanNotPreviewDetails {
room_basic_details: BasicRoomDetails {
room_id: room_id.clone(),
room_name: room_name.clone(),
room_avatar: preview_info.room_avatar.clone(),
},
join_rule: preview_info.room_preview.join_rule.clone(),
},
);
}
cx.action(MainDesktopUiAction::SaveDockIntoAppState);
} else {
error!("BUG: failed to create tab for {selected_room:?}");
}
self.open_rooms.insert(room_id_as_live_id, selected_room.clone());
self.most_recently_selected_room = Some(selected_room);
}

/// Closes a tab in the dock and focuses on the latest open room.
fn close_tab(&mut self, cx: &mut Cx, tab_id: LiveId) {
let dock = self.view.dock(ids!(dock));
Expand Down Expand Up @@ -282,6 +357,20 @@ impl WidgetMatchEvent for MainDesktopUI {
continue;
}

if let Some(RoomPreviewAction::Fetched(res)) = action.downcast_ref() {
match res {
Ok(room_preview) => self.focus_or_crate_preview_screen_tab(cx, room_preview),
Err(err) => {
error!("Failed to fetch room preview: {}", err);
enqueue_popup_notification(PopupItem {
message: "This room preview is not available.".to_string(),
kind: PopupKind::Error,
auto_dismissal_duration: None
});
},
}
}

// Handle actions emitted by the dock within the MainDesktopUI
match widget_action.cast() { // TODO: don't we need to call `widget_uid_eq(dock.widget_uid())` here?
// Whenever a tab (except for the home_tab) is pressed, notify the app state.
Expand Down
2 changes: 1 addition & 1 deletion src/home/main_mobile_ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ impl Widget for MainMobileUI {
.invite_screen(ids!(invite_screen))
.set_displayed_invite(cx, room_id.clone().into(), room_name.clone());
}
None => {
None | _ => {
show_welcome = true;
show_room = false;
show_invite = false;
Expand Down
109 changes: 87 additions & 22 deletions src/home/room_screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,34 +7,32 @@ use bytesize::ByteSize;
use imbl::Vector;
use makepad_widgets::{image_cache::ImageBuffer, *};
use matrix_sdk::{
room::RoomMember, ruma::{
events::{
OwnedServerName, RoomState, room::RoomMember, ruma::{
EventId, MatrixToUri, MatrixUri, OwnedEventId, OwnedMxcUri, OwnedRoomId, UserId, events::{
receipt::Receipt,
room::{
message::{
ImageInfo, MediaSource, message::{
AudioMessageEventContent, EmoteMessageEventContent, FileMessageEventContent, FormattedBody, ImageMessageEventContent, KeyVerificationRequestEventContent, LocationMessageEventContent, MessageFormat, MessageType, NoticeMessageEventContent, TextMessageEventContent, VideoMessageEventContent
},
ImageInfo, MediaSource
}
},
sticker::{StickerEventContent, StickerMediaSource},
},
matrix_uri::MatrixId, uint, EventId, MatrixToUri, MatrixUri, OwnedEventId, OwnedMxcUri, OwnedRoomId, UserId
}, OwnedServerName
}, matrix_uri::MatrixId, uint
}
};
use matrix_sdk_ui::timeline::{
self, EmbeddedEvent, EncryptedMessage, EventTimelineItem, InReplyToDetails, MemberProfileChange, MsgLikeContent, MsgLikeKind, OtherMessageLike, PollState, RoomMembershipChange, TimelineDetails, TimelineEventItemId, TimelineItem, TimelineItemContent, TimelineItemKind, VirtualTimelineItem
};

use crate::{
app::AppStateAction, avatar_cache, event_preview::{plaintext_body_of_timeline_item, text_preview_of_encrypted_message, text_preview_of_member_profile_change, text_preview_of_other_message_like, text_preview_of_other_state, text_preview_of_redacted_message, text_preview_of_room_membership_change, text_preview_of_timeline_item}, home::{edited_indicator::EditedIndicatorWidgetRefExt, link_preview::{LinkPreviewCache, LinkPreviewRef, LinkPreviewWidgetRefExt}, loading_pane::{LoadingPaneState, LoadingPaneWidgetExt}, rooms_list::RoomsListRef, tombstone_footer::SuccessorRoomDetails}, media_cache::{MediaCache, MediaCacheEntry}, profile::{
app::{AppStateAction, SelectedRoom}, avatar_cache, event_preview::{plaintext_body_of_timeline_item, text_preview_of_encrypted_message, text_preview_of_member_profile_change, text_preview_of_other_message_like, text_preview_of_other_state, text_preview_of_redacted_message, text_preview_of_room_membership_change, text_preview_of_timeline_item}, home::{edited_indicator::EditedIndicatorWidgetRefExt, link_preview::{LinkPreviewCache, LinkPreviewRef, LinkPreviewWidgetRefExt}, loading_pane::{LoadingPaneState, LoadingPaneWidgetExt}, rooms_list::{RoomsListAction, RoomsListRef}, tombstone_footer::SuccessorRoomDetails}, media_cache::{MediaCache, MediaCacheEntry}, profile::{
user_profile::{AvatarState, ShowUserProfileAction, UserProfile, UserProfileAndRoomId, UserProfilePaneInfo, UserProfileSlidingPaneRef, UserProfileSlidingPaneWidgetExt},
user_profile_cache,
},
room::{room_input_bar::RoomInputBarState, typing_notice::TypingNoticeWidgetExt},
shared::{
avatar::AvatarWidgetRefExt, callout_tooltip::TooltipAction, html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt, RobrixHtmlLinkAction}, jump_to_bottom_button::{JumpToBottomButtonWidgetExt, UnreadMessageCount}, popup_list::{enqueue_popup_notification, PopupItem, PopupKind}, restore_status_view::RestoreStatusViewWidgetExt, styles::*, text_or_image::{TextOrImageRef, TextOrImageWidgetRefExt}, timestamp::TimestampWidgetRefExt
avatar::AvatarWidgetRefExt, callout_tooltip::TooltipAction, html_or_plaintext::{HtmlOrPlaintextRef, HtmlOrPlaintextWidgetRefExt, RobrixHtmlLinkAction}, jump_to_bottom_button::{JumpToBottomButtonWidgetExt, UnreadMessageCount}, popup_list::{PopupItem, PopupKind, enqueue_popup_notification}, restore_status_view::RestoreStatusViewWidgetExt, styles::*, text_or_image::{TextOrImageRef, TextOrImageWidgetRefExt}, timestamp::TimestampWidgetRefExt
},
sliding_sync::{get_client, submit_async_request, take_timeline_endpoints, BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels}, utils::{self, room_name_or_id, unix_time_millis_to_datetime, ImageFormat, MEDIA_THUMBNAIL_FORMAT}
sliding_sync::{BackwardsPaginateUntilEventRequest, MatrixRequest, PaginationDirection, TimelineEndpoints, TimelineRequestSender, UserPowerLevels, get_client, submit_async_request, take_timeline_endpoints}, utils::{self, ImageFormat, MEDIA_THUMBNAIL_FORMAT, room_name_or_id, unix_time_millis_to_datetime}
};
use crate::home::event_reaction_list::ReactionListWidgetRefExt;
use crate::home::room_read_receipt::AvatarRowWidgetRefExt;
Expand Down Expand Up @@ -1435,9 +1433,10 @@ impl RoomScreen {
action: &Action,
pane: &UserProfileSlidingPaneRef,
) -> bool {
let uid = self.widget_uid();
// A closure that handles both MatrixToUri and MatrixUri links,
// and returns whether the link was handled.
let mut handle_matrix_link = |id: &MatrixId, _via: &[OwnedServerName]| -> bool {
let mut handle_matrix_link = |id: &MatrixId, via: &[OwnedServerName]| -> bool {
match id {
MatrixId::User(user_id) => {
// There is no synchronous way to get the user's full profile info
Expand Down Expand Up @@ -1474,20 +1473,86 @@ impl RoomScreen {
});
return true;
}
if let Some(_known_room) = get_client().and_then(|c| c.get_room(room_id)) {
log!("TODO: jump to known room {}", room_id);
if let Some(known_room) = get_client().and_then(|c| c.get_room(room_id)) {
if known_room.is_space() {
// TODO: Show space home page
enqueue_popup_notification(PopupItem {
message: "Showing a space's home page is not yet supported.".into(),
kind: PopupKind::Warning,
auto_dismissal_duration: Some(3.0)
});
}

if known_room.is_tombstoned() {
// TODO: To join the successor room, we need to: known_room.tombstone_content()
enqueue_popup_notification(PopupItem {
message: "This room has been replaced by another room. You must join the new room.".into(),
kind: PopupKind::Warning,
auto_dismissal_duration: None
});
}

match known_room.state() {
RoomState::Joined => {
cx.widget_action(
uid,
&Scope::empty().path,
RoomsListAction::Selected(
SelectedRoom::JoinedRoom {
room_id: known_room.room_id().to_owned().into(),
room_name: known_room.name(),
}
)
);
}
RoomState::Invited => {
cx.widget_action(
uid,
&Scope::empty().path,
RoomsListAction::Selected(
SelectedRoom::InvitedRoom {
room_id: known_room.room_id().to_owned().into(),
room_name: known_room.name(),
}
)
);
}
RoomState::Knocked => {
enqueue_popup_notification(PopupItem {
message: "Already knocked. Waiting for approval.".into(),
kind: PopupKind::Info,
auto_dismissal_duration: None
});
}
RoomState::Banned => {
enqueue_popup_notification(PopupItem {
message: "You are banned from that room. You cannot join. Unless the admin lifts the ban.".into(),
kind: PopupKind::Error,
auto_dismissal_duration: None
});
}
RoomState::Left => {
enqueue_popup_notification(PopupItem {
message: "You have left that room. You must be re-invited to join again.".into(),
kind: PopupKind::Info,
auto_dismissal_duration: None
});
}
}
} else {
log!("TODO: fetch and display room preview for room {}", room_id);
submit_async_request(MatrixRequest::GetRoomPreview {
room_or_alias_id: room_id.to_owned().into(),
via: via.to_owned(),
});
}
false
true
}
MatrixId::RoomAlias(room_alias) => {
log!("TODO: open room alias {}", room_alias);
// TODO: open a room loading screen that shows a spinner
// while our background async task calls Client::resolve_room_alias()
// and then either jumps to the room if known, or fetches and displays
// a room preview for that room.
false
submit_async_request(MatrixRequest::GetRoomPreview {
room_or_alias_id: room_alias.to_owned().into(),
via: via.to_owned(),
});
true
}
MatrixId::Event(room_id, event_id) => {
log!("TODO: open event {} in room {}", event_id, room_id);
Expand Down
3 changes: 2 additions & 1 deletion src/persistence/app_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ pub fn save_app_state(
for (tab_id, room) in &app_state.saved_dock_state.open_rooms {
match room {
SelectedRoom::JoinedRoom { room_id, .. }
| SelectedRoom::InvitedRoom { room_id, .. } => {
| SelectedRoom::InvitedRoom { room_id, .. }
| SelectedRoom::PreviewedRoom { room_id, .. } => {
if !app_state.saved_dock_state.dock_items.contains_key(tab_id) {
error!("Room id: {} already in dock state", room_id);
}
Expand Down
Loading
Loading