From d7550ec6459440c36fad83337855a5f5a3e793aa Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Tue, 8 Jul 2025 21:00:14 +0200 Subject: [PATCH] feat(ui): `RoomListService::subscribe_to_rooms` calls `LatestEvents::listen_to_room`. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch updates `RoomListService::subscribe_to_rooms` to call `LatestEvents::listen_to_room` automatically. This method becomes async, which propagates to a couple of callers. The idea is that when one is interested by a specific room, a subscription will be applied. This is an opportunity to also “activate” the computation of the `LatestEvent` for this specific room, so that the user doesn't have to do that manually (except if room subscription is never used). --- bindings/matrix-sdk-ffi/src/room_list.rs | 6 +++-- .../src/room_list_service/mod.rs | 26 +++++++++++++++++-- .../tests/integration/room_list_service.rs | 6 ++--- labs/multiverse/src/main.rs | 4 +-- labs/multiverse/src/widgets/room_list.rs | 12 ++++----- 5 files changed, 39 insertions(+), 15 deletions(-) diff --git a/bindings/matrix-sdk-ffi/src/room_list.rs b/bindings/matrix-sdk-ffi/src/room_list.rs index 544e2a87d..e60baa6fc 100644 --- a/bindings/matrix-sdk-ffi/src/room_list.rs +++ b/bindings/matrix-sdk-ffi/src/room_list.rs @@ -121,7 +121,7 @@ impl RoomListService { }))) } - fn subscribe_to_rooms(&self, room_ids: Vec) -> Result<(), RoomListError> { + async fn subscribe_to_rooms(&self, room_ids: Vec) -> Result<(), RoomListError> { let room_ids = room_ids .into_iter() .map(|room_id| { @@ -129,7 +129,9 @@ impl RoomListService { }) .collect::, _>>()?; - self.inner.subscribe_to_rooms(&room_ids.iter().map(AsRef::as_ref).collect::>()); + self.inner + .subscribe_to_rooms(&room_ids.iter().map(AsRef::as_ref).collect::>()) + .await; Ok(()) } diff --git a/crates/matrix-sdk-ui/src/room_list_service/mod.rs b/crates/matrix-sdk-ui/src/room_list_service/mod.rs index 74f0a0a27..2a840c1b2 100644 --- a/crates/matrix-sdk-ui/src/room_list_service/mod.rs +++ b/crates/matrix-sdk-ui/src/room_list_service/mod.rs @@ -72,7 +72,7 @@ use ruma::{ }; pub use state::*; use thiserror::Error; -use tracing::debug; +use tracing::{debug, error}; /// The default `required_state` constant value for sliding sync lists and /// sliding sync room subscriptions. @@ -393,7 +393,15 @@ impl RoomListService { /// /// It means that all events from these rooms will be received every time, /// no matter how the `RoomList` is configured. - pub fn subscribe_to_rooms(&self, room_ids: &[&RoomId]) { + /// + /// [`LatestEvents::listen_to_room`][listen_to_room] will be called for each + /// room in `room_ids`, so that the [`LatestEventValue`] will automatically + /// be calculated and updated for these rooms, for free. + /// + /// [listen_to_room]: matrix_sdk::latest_events::LatestEvents::listen_to_room + /// [`LatestEventValue`]: matrix_sdk::latest_events::LatestEventValue + pub async fn subscribe_to_rooms(&self, room_ids: &[&RoomId]) { + // Calculate the settings for the room subscriptions. let settings = assign!(http::request::RoomSubscription::default(), { required_state: DEFAULT_REQUIRED_STATE.iter().map(|(state_event, value)| { (state_event.clone(), (*value).to_owned()) @@ -407,6 +415,7 @@ impl RoomListService { timeline_limit: UInt::from(DEFAULT_ROOM_SUBSCRIPTION_TIMELINE_LIMIT), }); + // Decide whether the in-flight request (if any) should be cancelled if needed. let cancel_in_flight_request = match self.state_machine.get() { State::Init | State::Recovering | State::Error { .. } | State::Terminated { .. } => { false @@ -414,6 +423,19 @@ impl RoomListService { State::SettingUp | State::Running => true, }; + // Before subscribing, let's listen these rooms to calculate their latest + // events. + let latest_events = self.client.latest_events().await; + + for room_id in room_ids { + if let Err(error) = latest_events.listen_to_room(room_id).await { + // Let's not fail the room subscription. Instead, emit a log because it's very + // unlikely to happen. + error!(?error, ?room_id, "Failed to listen to the latest event for this room"); + } + } + + // Subscribe to the rooms. self.sliding_sync.subscribe_to_rooms(room_ids, Some(settings), cancel_in_flight_request) } diff --git a/crates/matrix-sdk-ui/tests/integration/room_list_service.rs b/crates/matrix-sdk-ui/tests/integration/room_list_service.rs index cbdbaa562..f66d940b9 100644 --- a/crates/matrix-sdk-ui/tests/integration/room_list_service.rs +++ b/crates/matrix-sdk-ui/tests/integration/room_list_service.rs @@ -2247,7 +2247,7 @@ async fn test_room_subscription() -> Result<(), Error> { // Subscribe. - room_list.subscribe_to_rooms(&[room_id_1]); + room_list.subscribe_to_rooms(&[room_id_1]).await; sync_then_assert_request_and_fake_response! { [server, room_list, sync] @@ -2290,7 +2290,7 @@ async fn test_room_subscription() -> Result<(), Error> { // Subscribe to another room. - room_list.subscribe_to_rooms(&[room_id_2]); + room_list.subscribe_to_rooms(&[room_id_2]).await; sync_then_assert_request_and_fake_response! { [server, room_list, sync] @@ -2333,7 +2333,7 @@ async fn test_room_subscription() -> Result<(), Error> { // Subscribe to an already subscribed room. Nothing happens. - room_list.subscribe_to_rooms(&[room_id_1]); + room_list.subscribe_to_rooms(&[room_id_1]).await; sync_then_assert_request_and_fake_response! { [server, room_list, sync] diff --git a/labs/multiverse/src/main.rs b/labs/multiverse/src/main.rs index bfe0729c1..214b24fa4 100644 --- a/labs/multiverse/src/main.rs +++ b/labs/multiverse/src/main.rs @@ -325,7 +325,7 @@ impl App { modifiers: KeyModifiers::CONTROL, .. }) => { - self.room_list.next_room(); + self.room_list.next_room().await; let room_id = self.room_list.get_selected_room_id(); self.room_view.set_selected_room(room_id); } @@ -333,7 +333,7 @@ impl App { Event::Key(KeyEvent { code: Char('k') | Up, modifiers: KeyModifiers::CONTROL, .. }) => { - self.room_list.previous_room(); + self.room_list.previous_room().await; let room_id = self.room_list.get_selected_room_id(); self.room_view.set_selected_room(room_id); } diff --git a/labs/multiverse/src/widgets/room_list.rs b/labs/multiverse/src/widgets/room_list.rs index d17f477cd..2e0433177 100644 --- a/labs/multiverse/src/widgets/room_list.rs +++ b/labs/multiverse/src/widgets/room_list.rs @@ -68,7 +68,7 @@ impl RoomList { /// Focus the list on the next item, wraps around if needs be. /// /// Returns the index only if there was a meaningful change. - pub fn next_room(&mut self) { + pub async fn next_room(&mut self) { let num_items = self.rooms.lock().len(); // If there's no item to select, leave early. @@ -83,14 +83,14 @@ impl RoomList { if prev != Some(new) { self.state.select(Some(new)); - self.subscribe_to_room(new); + self.subscribe_to_room(new).await; } } /// Focus the list on the previous item, wraps around if needs be. /// /// Returns the index only if there was a meaningful change. - pub fn previous_room(&mut self) { + pub async fn previous_room(&mut self) { let num_items = self.rooms.lock().len(); // If there's no item to select, leave early. @@ -105,7 +105,7 @@ impl RoomList { if prev != Some(new) { self.state.select(Some(new)); - self.subscribe_to_room(new); + self.subscribe_to_room(new).await; } } @@ -121,7 +121,7 @@ impl RoomList { } /// Subscribe to room that is shown at the given `index`. - fn subscribe_to_room(&mut self, index: usize) { + async fn subscribe_to_room(&mut self, index: usize) { // Cancel the subscription to the previous room, if any. self.current_room_subscription.take(); @@ -129,7 +129,7 @@ impl RoomList { if let Some(room) = self.get_room_id_of_entry(index).and_then(|room_id| self.client.get_room(&room_id)) { - self.sync_service.room_list_service().subscribe_to_rooms(&[room.room_id()]); + self.sync_service.room_list_service().subscribe_to_rooms(&[room.room_id()]).await; self.current_room_subscription = Some(room); } }