Skip to content

Commit 7d43c68

Browse files
committed
Added WaitForRoomOpen
1 parent e6ec086 commit 7d43c68

File tree

7 files changed

+102
-85
lines changed

7 files changed

+102
-85
lines changed

src/app.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ impl MatchEvent for App {
241241
cx.action(MainDesktopUiAction::LoadDockFromAppState);
242242
}
243243

244-
if let RoomsListAction::Selected(selected_room) = action.as_widget_action().cast() {
244+
if let RoomsListAction::Selected(selected_room, _) = action.as_widget_action().cast() {
245245
// A room has been selected, update the app state and navigate to the main content view.
246246
let display_name = room_name_or_id(selected_room.room_name(), selected_room.room_id());
247247
self.app_state.selected_room = Some(selected_room);

src/home/main_desktop_ui.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -338,11 +338,14 @@ impl WidgetMatchEvent for MainDesktopUI {
338338

339339
// Handle RoomsList actions, which are updates from the rooms list.
340340
match widget_action.cast() {
341-
RoomsListAction::Selected(selected_room) => {
341+
RoomsListAction::Selected(selected_room, notify) => {
342342
// Note that this cannot be performed within draw_walk() as the draw flow prevents from
343343
// performing actions that would trigger a redraw, and the Dock internally performs (and expects)
344344
// a redraw to be happening in order to draw the tab content.
345345
self.focus_or_create_tab(cx, selected_room);
346+
if let Some(notify) = notify {
347+
notify.notify_one(); // Notify the waiting task that the room has been focused.
348+
}
346349
}
347350
RoomsListAction::InviteAccepted { room_id, room_name } => {
348351
self.replace_invite_with_joined_room(cx, scope, room_id, room_name);

src/home/main_mobile_ui.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ impl Widget for MainMobileUI {
5454
for action in actions {
5555
match action.as_widget_action().cast() {
5656
// This is currently handled in the top-level App.
57-
RoomsListAction::Selected(_selected_room) => {}
57+
RoomsListAction::Selected(_selected_room, _) => {}
5858
// Because the MainMobileUI is drawn based on the AppState only,
5959
// all we need to do is update the AppState here.
6060
RoomsListAction::InviteAccepted { room_id, .. } => {

src/home/room_screen.rs

Lines changed: 67 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,10 @@ use matrix_sdk::{
2626
use matrix_sdk_ui::timeline::{
2727
self, EmbeddedEvent, EncryptedMessage, EventTimelineItem, InReplyToDetails, MemberProfileChange, MsgLikeContent, MsgLikeKind, PollState, RoomMembershipChange, TimelineDetails, TimelineEventItemId, TimelineItem, TimelineItemContent, TimelineItemKind, VirtualTimelineItem
2828
};
29+
use tokio::sync::Notify;
2930

3031
use crate::{
31-
app::{AppState, 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_state, text_preview_of_redacted_message, text_preview_of_room_membership_change, text_preview_of_timeline_item}, home::{edited_indicator::EditedIndicatorWidgetRefExt, editing_pane::EditingPaneState, loading_pane::{LoadingPaneState, LoadingPaneWidgetExt}, rooms_list::{RoomsListRef, RoomsListAction}}, location::init_location_subscriber, media_cache::{MediaCache, MediaCacheEntry}, profile::{
32+
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_state, text_preview_of_redacted_message, text_preview_of_room_membership_change, text_preview_of_timeline_item}, home::{edited_indicator::EditedIndicatorWidgetRefExt, editing_pane::EditingPaneState, loading_pane::{LoadingPaneState, LoadingPaneWidgetExt}, rooms_list::{RoomsListRef, RoomsListAction}}, location::init_location_subscriber, media_cache::{MediaCache, MediaCacheEntry}, profile::{
3233
user_profile::{AvatarState, ShowUserProfileAction, UserProfile, UserProfileAndRoomId, UserProfilePaneInfo, UserProfileSlidingPaneRef, UserProfileSlidingPaneWidgetExt},
3334
user_profile_cache,
3435
}, shared::{
@@ -1402,6 +1403,7 @@ impl Widget for RoomScreen {
14021403
TimelineItemContent::MsgLike(msg_like_content) => match &msg_like_content.kind {
14031404
MsgLikeKind::Message(_) | MsgLikeKind::Sticker(_) => {
14041405
let prev_event = tl_idx.checked_sub(1).and_then(|i| tl_items.get(i));
1406+
println!("msg_like_content {:?}", msg_like_content.as_message().unwrap().body());
14051407
populate_message_view(
14061408
cx,
14071409
list,
@@ -1531,6 +1533,7 @@ impl RoomScreen {
15311533
fn process_timeline_updates(&mut self, cx: &mut Cx, portal_list: &PortalListRef) {
15321534
let top_space = self.view(id!(top_space));
15331535
let jump_to_bottom = self.jump_to_bottom_button(id!(jump_to_bottom));
1536+
let loading_pane = self.loading_pane(id!(loading_pane));
15341537
let curr_first_id = portal_list.first_id();
15351538
let ui = self.widget_uid();
15361539
let Some(tl) = self.tl_state.as_mut() else { return };
@@ -1799,6 +1802,61 @@ impl RoomScreen {
17991802
TimelineUpdate::OwnUserReadReceipt(receipt) => {
18001803
tl.latest_own_user_receipt = Some(receipt);
18011804
}
1805+
TimelineUpdate::ScrollToMessage { event_id } => {
1806+
// Search through the timeline to find the message with the given event_id
1807+
let mut num_items_searched = 0;
1808+
let target_msg_tl_index = tl.items
1809+
.focus()
1810+
.into_iter()
1811+
.position(|item| {
1812+
num_items_searched += 1;
1813+
item.as_event()
1814+
.and_then(|e| e.event_id())
1815+
.is_some_and(|ev_id| ev_id == event_id)
1816+
});
1817+
if let Some(index) = target_msg_tl_index {
1818+
let current_first_index = portal_list.first_id();
1819+
let speed = index.saturating_sub(1).abs_diff(current_first_index) as f64 / (SMOOTH_SCROLL_TIME.get() as f64 * 0.001);
1820+
portal_list.smooth_scroll_to(
1821+
cx,
1822+
index.saturating_sub(1),
1823+
//index.saturating_sub(1).abs_diff(current_first_index) as f64 / (SMOOTH_SCROLL_TIME as f64 * 0.001),
1824+
speed,
1825+
None,
1826+
);
1827+
// start highlight animation.
1828+
tl.message_highlight_animation_state = MessageHighlightAnimationState::Pending {
1829+
item_id: index
1830+
};
1831+
} else {
1832+
log!("essage not found - trigger backwards pagination to find it");
1833+
// Message not found - trigger backwards pagination to find it
1834+
loading_pane.set_state(
1835+
cx,
1836+
LoadingPaneState::BackwardsPaginateUntilEvent {
1837+
target_event_id: event_id.clone(),
1838+
events_paginated: 0,
1839+
request_sender: tl.request_sender.clone(),
1840+
},
1841+
);
1842+
loading_pane.show(cx);
1843+
1844+
tl.request_sender.send_if_modified(|requests| {
1845+
if let Some(existing) = requests.iter_mut().find(|r| r.room_id == tl.room_id) {
1846+
// Re-use existing request
1847+
existing.target_event_id = event_id.clone();
1848+
} else {
1849+
requests.push(BackwardsPaginateUntilEventRequest {
1850+
room_id: tl.room_id.clone(),
1851+
target_event_id: event_id.clone(),
1852+
starting_index: 0, // Search from the beginning since we don't know where it is
1853+
current_tl_len: tl.items.len(),
1854+
});
1855+
}
1856+
true
1857+
});
1858+
}
1859+
}
18021860
}
18031861
}
18041862

@@ -2850,7 +2908,10 @@ pub enum TimelineUpdate {
28502908
UserPowerLevels(UserPowerLevels),
28512909
/// An update to the currently logged-in user's own read receipt for this room.
28522910
OwnUserReadReceipt(Receipt),
2853-
2911+
/// Scroll the timeline to the given event.
2912+
ScrollToMessage {
2913+
event_id: OwnedEventId,
2914+
}
28542915
}
28552916

28562917
thread_local! {
@@ -3578,6 +3639,7 @@ pub fn populate_text_message_content(
35783639
if let Some(fb) = formatted_body.as_ref()
35793640
.and_then(|fb| (fb.format == MessageFormat::Html).then_some(fb))
35803641
{
3642+
println!("fb.body {:?}", fb.body);
35813643
message_content_widget.show_html(
35823644
cx,
35833645
utils::linkify(
@@ -4353,8 +4415,6 @@ pub struct Message {
43534415
/// The jump option required for searched messages.
43544416
/// Contains the room ID, event ID for the message, and whether it's from an all-rooms search.
43554417
#[rust] jump_option: Option<JumpToMessageRequest>,
4356-
/// Add a small delay to ensure new room tab is opened before jumping to the message.
4357-
#[rust] jump_delay: Timer,
43584418
}
43594419

43604420
impl Widget for Message {
@@ -4368,18 +4428,6 @@ impl Widget for Message {
43684428
{
43694429
self.animator_play(cx, id!(highlight.off));
43704430
}
4371-
if let Event::Timer(te) = event {
4372-
if let (Some(_), Some(jump_request)) = (self.jump_delay.is_timer(te), &self.jump_option) {
4373-
cx.widget_action(
4374-
self.widget_uid(),
4375-
&scope.path,
4376-
MessageAction::ScrollToMessage {
4377-
room_id: jump_request.room_id.clone(),
4378-
event_id: jump_request.event_id.clone(),
4379-
}
4380-
);
4381-
}
4382-
}
43834431
if let Some(jump_request) = &self.jump_option {
43844432
if let Event::Actions(actions) = event {
43854433
if self.view.button(id!(jump_to_this_message.jump_button)).clicked(actions) {
@@ -4396,58 +4444,16 @@ impl Widget for Message {
43964444
room_id: jump_request.room_id.clone().into(),
43974445
room_name,
43984446
};
4447+
let notify = Arc::new(Notify::new());
43994448
cx.widget_action(
44004449
self.widget_uid(),
44014450
&scope.path,
4402-
RoomsListAction::Selected(target_selected_room)
4451+
RoomsListAction::Selected(target_selected_room, Some(notify.clone()))
44034452
);
4404-
// if let Some(selected_room) = {
4405-
// let app_state = scope.data.get::<AppState>().unwrap();
4406-
// &app_state.selected_room
4407-
// } {
4408-
// cx.widget_action(
4409-
// self.widget_uid(),
4410-
// &Scope::default().path,
4411-
// StackNavigationAction::PopToRoot
4412-
// );
4413-
// println!("selected_room.room_id(){:?}", selected_room.room_id());
4414-
// // If room_id is not the selected room, select the room and open its dock tab
4415-
// if selected_room.room_id() != &jump_request.room_id {
4416-
// let room_name: Option<String> = {
4417-
// let rooms_list_ref = cx.get_global::<RoomsListRef>();
4418-
// rooms_list_ref.get_room_name(&jump_request.room_id)
4419-
// };
4420-
4421-
// let target_selected_room = SelectedRoom::JoinedRoom {
4422-
// room_id: jump_request.room_id.clone().into(),
4423-
// room_name,
4424-
// };
4425-
// println!("Jumping to message in room: {} StackNavigationAction::PopToRoot", target_selected_room.room_id());
4426-
4427-
// // Dispatch action to select the room and open its dock tab
4428-
// cx.widget_action(
4429-
// self.widget_uid(),
4430-
// &scope.path,
4431-
// RoomsListAction::Selected(target_selected_room)
4432-
// );
4433-
// }
4434-
// }
4435-
// Add a jump delay to ensure new room tab is opened before jumping to the message.
4436-
self.jump_delay = cx.start_timeout(1.0);
4453+
submit_async_request(MatrixRequest::WaitForRoomOpenToJump { notify, room_id: jump_request.room_id.clone(), event_id: jump_request.event_id.clone() });
44374454
}
44384455
}
44394456
self.view.handle_event(cx, event, scope);
4440-
let message_view_area = self.view.area();
4441-
match event.hits(cx, message_view_area) {
4442-
Hit::FingerDown(fe) => {
4443-
cx.set_key_focus(message_view_area);
4444-
// A left click to scroll to the message in room screen.
4445-
if fe.device.mouse_button().is_some_and(|b| b.is_primary()) {
4446-
self.jump_delay = cx.start_timeout(0.5);
4447-
}
4448-
}
4449-
_ => {}
4450-
}
44514457
return;
44524458
}
44534459
let Some(details) = self.details.clone() else { return };
@@ -4579,9 +4585,6 @@ impl Message {
45794585
self.jump_option = Some(jump_option);
45804586
self.view.view(id!(jump_to_this_message))
45814587
.set_visible(cx, true);
4582-
self.view.apply_over(cx, live! {
4583-
cursor: Hand
4584-
});
45854588
}
45864589
}
45874590

src/home/rooms_list.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ pub fn enqueue_rooms_list_update(update: RoomsListUpdate) {
159159
#[derive(Debug, Clone, DefaultNone)]
160160
pub enum RoomsListAction {
161161
/// A new room was selected.
162-
Selected(SelectedRoom),
162+
Selected(SelectedRoom, Option<Arc<tokio::sync::Notify>>),
163163
/// A new room was joined from an accepted invite,
164164
/// meaning that the existing `InviteScreen` should be converted
165165
/// to a `RoomScreen` to display now-joined room.
@@ -787,7 +787,7 @@ impl Widget for RoomsList {
787787
cx.widget_action(
788788
self.widget_uid(),
789789
&scope.path,
790-
RoomsListAction::Selected(new_selected_room),
790+
RoomsListAction::Selected(new_selected_room, None),
791791
);
792792
self.redraw(cx);
793793
}

src/right_panel/search_message.rs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -942,7 +942,7 @@ fn populate_message_search_view(
942942
};
943943

944944
let ts_millis = event.origin_server_ts();
945-
945+
946946
// Use precomputed formatted content
947947
let (item, used_cached_item) = if let Some(content) = formatted_content.as_ref() {
948948
match &content.msgtype {
@@ -959,23 +959,9 @@ fn populate_message_search_view(
959959
if existed && item_drawn_status.content_drawn {
960960
(item, true)
961961
} else {
962-
let html_or_plaintext_ref = item.html_or_plaintext(id!(content.message));
963-
html_or_plaintext_ref.apply_over(
964-
cx,
965-
live!(
966-
html_view = {
967-
html = {
968-
font_color: (vec3(0.0,0.0,0.0)),
969-
draw_block: {
970-
code_color: (COLOR_WARNING_YELLOW)
971-
}
972-
}
973-
}
974-
),
975-
);
976962
populate_text_message_content(
977963
cx,
978-
&html_or_plaintext_ref,
964+
&item.html_or_plaintext(id!(content.message)),
979965
body,
980966
formatted.as_ref(),
981967
);

src/sliding_sync.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,15 @@ pub enum MatrixRequest {
405405
next_batch: Option<String>,
406406
/// Abort previous search only when debouncing from typing search term.
407407
abort_previous_search: bool,
408+
},
409+
/// Wait for a room to be opened before jumping to a specific event.
410+
WaitForRoomOpenToJump {
411+
/// A notification that will be triggered when the room is opened.
412+
notify: Arc<Notify>,
413+
/// The ID of the room to jump to.
414+
room_id: OwnedRoomId,
415+
/// The ID of the event to jump to.
416+
event_id: OwnedEventId,
408417
}
409418
}
410419

@@ -1281,6 +1290,22 @@ async fn async_worker(
12811290
});
12821291
search_task_abort_handler = Some(handle.abort_handle());
12831292
}
1293+
MatrixRequest::WaitForRoomOpenToJump { notify, room_id, event_id } => {
1294+
let sender = {
1295+
let mut all_joined_rooms = ALL_JOINED_ROOMS.lock().unwrap();
1296+
let Some(room_info) = all_joined_rooms.get_mut(&room_id) else {
1297+
log!("Skipping pagination request for not-yet-known room {room_id}");
1298+
continue;
1299+
};
1300+
let sender = room_info.timeline_update_sender.clone();
1301+
sender
1302+
};
1303+
Handle::current().spawn(async move {
1304+
notify.notified().await;
1305+
sender.send(TimelineUpdate::ScrollToMessage{event_id}).unwrap();
1306+
SignalToUI::set_ui_signal();
1307+
});
1308+
}
12841309
}
12851310
}
12861311

0 commit comments

Comments
 (0)