feat(multiverse): add support for subscribing/unsubscribing/showing the current sub status

This commit is contained in:
Benjamin Bouvier
2025-07-23 18:55:47 +02:00
parent 1f33e0f4d1
commit 770f65ede0
3 changed files with 72 additions and 3 deletions
@@ -16,6 +16,8 @@ struct Cli {
pub enum Command {
Invite { user_id: String },
Leave,
Subscribe,
Unsubscribe,
}
pub enum MessageOrCommand {
+69 -2
View File
@@ -9,7 +9,8 @@ use matrix_sdk::{
Client, Room, RoomState,
locks::Mutex,
ruma::{
OwnedRoomId, RoomId, UserId, api::client::receipt::create_receipt::v3::ReceiptType,
OwnedEventId, OwnedRoomId, RoomId, UserId,
api::client::receipt::create_receipt::v3::ReceiptType,
events::room::message::RoomMessageEventContent,
},
};
@@ -52,6 +53,7 @@ enum TimelineKind {
Thread {
room: OwnedRoomId,
thread_root: OwnedEventId,
/// The threaded-focused timeline for this thread.
timeline: Arc<OnceCell<Arc<Timeline>>>,
/// Items in the thread timeline (to avoid recomputing them every single
@@ -145,10 +147,11 @@ impl RoomView {
let i = items.clone();
let t = thread_timeline.clone();
let root = root_event_id;
let cloned_root = root.clone();
let r = room.clone();
let task = spawn(async move {
let timeline = TimelineBuilder::new(&r)
.with_focus(TimelineFocus::Thread { root_event_id: root.clone() })
.with_focus(TimelineFocus::Thread { root_event_id: cloned_root })
.track_read_marker_and_receipts()
.build()
.await
@@ -171,6 +174,7 @@ impl RoomView {
self.timeline_list.unselect();
self.kind = TimelineKind::Thread {
thread_root: root,
room: room.room_id().to_owned(),
timeline: thread_timeline,
items,
@@ -225,6 +229,12 @@ impl RoomView {
self.switch_to_room_timeline(None);
}
// Pressing 'Alt+s' on a threaded timeline will print the current
// subscription status.
(KeyModifiers::ALT, Char('s')) => {
self.print_thread_subscription_status().await;
}
(KeyModifiers::CONTROL, Char('l')) => {
self.toggle_reaction_to_latest_msg().await
}
@@ -477,10 +487,67 @@ impl RoomView {
self.input.clear();
}
async fn subscribe_thread(&mut self) {
if let TimelineKind::Thread { thread_root, .. } = &self.kind {
self.call_with_room(async |room, status_handle| {
if let Err(err) = room.subscribe_thread(thread_root.clone(), false).await {
status_handle.set_message(format!("error when subscribing to a thread: {err}"));
} else {
status_handle.set_message("Subscribed to thread!".to_owned());
}
})
.await;
self.input.clear();
}
}
async fn unsubscribe_thread(&mut self) {
if let TimelineKind::Thread { thread_root, .. } = &self.kind {
self.call_with_room(async |room, status_handle| {
if let Err(err) = room.unsubscribe_thread(thread_root.clone()).await {
status_handle
.set_message(format!("error when unsubscribing to a thread: {err}"));
} else {
status_handle.set_message("Unsubscribed from thread!".to_owned());
}
})
.await;
self.input.clear();
}
}
async fn print_thread_subscription_status(&mut self) {
if let TimelineKind::Thread { thread_root, .. } = &self.kind {
self.call_with_room(async |room, status_handle| {
match room.fetch_thread_subscription(thread_root.clone()).await {
Ok(Some(subscription)) => {
status_handle.set_message(format!(
"Thread subscription status: {}",
if subscription.automatic { "automatic" } else { "manual" }
));
}
Ok(None) => {
status_handle
.set_message("Thread is not subscribed or does not exist".to_owned());
}
Err(err) => {
status_handle
.set_message(format!("Error getting thread subscription: {err}"));
}
}
})
.await;
}
}
async fn handle_command(&mut self, command: input::Command) {
match command {
input::Command::Invite { user_id } => self.invite_member(&user_id).await,
input::Command::Leave => self.leave_room().await,
input::Command::Subscribe => self.subscribe_thread().await,
input::Command::Unsubscribe => self.unsubscribe_thread().await,
}
}
+1 -1
View File
@@ -89,7 +89,7 @@ impl Status {
let status_message = status_message.clone();
async move {
// Clear the status message in 4 seconds.
// Clear the status message after the standard duration.
sleep(MESSAGE_DURATION).await;
status_message.lock().take();
}