feat(ui): RoomListService::subscribe_to_rooms calls LatestEvents::listen_to_room.

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).
This commit is contained in:
Ivan Enderlin
2025-07-08 21:00:14 +02:00
parent ea5645869e
commit d7550ec645
5 changed files with 39 additions and 15 deletions
+4 -2
View File
@@ -121,7 +121,7 @@ impl RoomListService {
})))
}
fn subscribe_to_rooms(&self, room_ids: Vec<String>) -> Result<(), RoomListError> {
async fn subscribe_to_rooms(&self, room_ids: Vec<String>) -> Result<(), RoomListError> {
let room_ids = room_ids
.into_iter()
.map(|room_id| {
@@ -129,7 +129,9 @@ impl RoomListService {
})
.collect::<Result<Vec<_>, _>>()?;
self.inner.subscribe_to_rooms(&room_ids.iter().map(AsRef::as_ref).collect::<Vec<_>>());
self.inner
.subscribe_to_rooms(&room_ids.iter().map(AsRef::as_ref).collect::<Vec<_>>())
.await;
Ok(())
}
@@ -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)
}
@@ -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]
+2 -2
View File
@@ -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);
}
+6 -6
View File
@@ -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);
}
}