feat(sdk): save the unsubscribed status in the store, and use it to return something more precise than unknown when fetching a subscription
This commit is contained in:
@@ -1129,22 +1129,29 @@ impl Room {
|
||||
pub async fn fetch_thread_subscription(
|
||||
&self,
|
||||
thread_root_event_id: String,
|
||||
) -> Result<Option<ThreadSubscription>, ClientError> {
|
||||
) -> Result<Option<ThreadStatus>, ClientError> {
|
||||
let thread_root = EventId::parse(thread_root_event_id)?;
|
||||
Ok(self
|
||||
.inner
|
||||
.fetch_thread_subscription(thread_root)
|
||||
.await?
|
||||
.map(|sub| ThreadSubscription { automatic: sub.automatic }))
|
||||
Ok(self.inner.fetch_thread_subscription(thread_root).await?.map(|sub| match sub {
|
||||
matrix_sdk::room::ThreadStatus::Subscribed { automatic } => {
|
||||
ThreadStatus::Subscribed { automatic }
|
||||
}
|
||||
matrix_sdk::room::ThreadStatus::Unsubscribed => ThreadStatus::Unsubscribed,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
/// Status of a thread subscription (MSC4306).
|
||||
#[derive(uniffi::Record)]
|
||||
pub struct ThreadSubscription {
|
||||
/// Whether the thread subscription happened automatically (e.g. after a
|
||||
/// mention) or if it was manually requested by the user.
|
||||
automatic: bool,
|
||||
#[derive(uniffi::Enum)]
|
||||
pub enum ThreadStatus {
|
||||
/// The thread is subscribed to.
|
||||
Subscribed {
|
||||
/// Whether the thread subscription happened automatically (e.g. after a
|
||||
/// mention) or if it was manually requested by the user.
|
||||
automatic: bool,
|
||||
},
|
||||
|
||||
/// The thread is not subscribed to.
|
||||
Unsubscribed,
|
||||
}
|
||||
|
||||
/// A listener for receiving new live location shares in a room.
|
||||
|
||||
@@ -34,6 +34,7 @@ use http::StatusCode;
|
||||
pub use identity_status_changes::IdentityStatusChanges;
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
use matrix_sdk_base::crypto::{IdentityStatusChange, RoomIdentityProvider, UserIdentity};
|
||||
pub use matrix_sdk_base::store::ThreadStatus;
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
use matrix_sdk_base::{crypto::RoomEventDecryptionResult, deserialized_responses::EncryptionInfo};
|
||||
use matrix_sdk_base::{
|
||||
@@ -3657,10 +3658,21 @@ impl Room {
|
||||
self.client
|
||||
.send(subscribe_thread::unstable::Request::new(
|
||||
self.room_id().to_owned(),
|
||||
thread_root,
|
||||
thread_root.clone(),
|
||||
automatic,
|
||||
))
|
||||
.await?;
|
||||
|
||||
// Immediately save the result into the database.
|
||||
self.client
|
||||
.state_store()
|
||||
.upsert_thread_subscription(
|
||||
self.room_id(),
|
||||
&thread_root,
|
||||
ThreadStatus::Subscribed { automatic },
|
||||
)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3679,9 +3691,16 @@ impl Room {
|
||||
self.client
|
||||
.send(unsubscribe_thread::unstable::Request::new(
|
||||
self.room_id().to_owned(),
|
||||
thread_root,
|
||||
thread_root.clone(),
|
||||
))
|
||||
.await?;
|
||||
|
||||
// Immediately save the result into the database.
|
||||
self.client
|
||||
.state_store()
|
||||
.upsert_thread_subscription(self.room_id(), &thread_root, ThreadStatus::Unsubscribed)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -3695,8 +3714,8 @@ impl Room {
|
||||
///
|
||||
/// # Returns
|
||||
///
|
||||
/// - An `Ok` result with `Some(ThreadSubscription)` if the subscription
|
||||
/// exists.
|
||||
/// - An `Ok` result with `Some(ThreadStatus)` if we have some subscription
|
||||
/// information.
|
||||
/// - An `Ok` result with `None` if the subscription does not exist, or the
|
||||
/// event couldn't be found, or the event isn't a thread.
|
||||
/// - An error if the request fails for any other reason, such as a network
|
||||
@@ -3704,33 +3723,48 @@ impl Room {
|
||||
pub async fn fetch_thread_subscription(
|
||||
&self,
|
||||
thread_root: OwnedEventId,
|
||||
) -> Result<Option<ThreadSubscription>> {
|
||||
) -> Result<Option<ThreadStatus>> {
|
||||
let result = self
|
||||
.client
|
||||
.send(get_thread_subscription::unstable::Request::new(
|
||||
self.room_id().to_owned(),
|
||||
thread_root,
|
||||
thread_root.clone(),
|
||||
))
|
||||
.await;
|
||||
|
||||
match result {
|
||||
Ok(response) => Ok(Some(ThreadSubscription { automatic: response.automatic })),
|
||||
Ok(response) => Ok(Some(ThreadStatus::Subscribed { automatic: response.automatic })),
|
||||
Err(http_error) => match http_error.as_client_api_error() {
|
||||
Some(error) if error.status_code == StatusCode::NOT_FOUND => Ok(None),
|
||||
Some(error) if error.status_code == StatusCode::NOT_FOUND => {
|
||||
// At this point the server returned no subscriptions, which can mean that the
|
||||
// endpoint doesn't exist (not enabled/implemented yet on the server), or that
|
||||
// the thread doesn't exist, or that the user has unsubscribed from it
|
||||
// previously.
|
||||
//
|
||||
// If we had any information about prior unsubscription, we can use it here to
|
||||
// return something slightly more precise than what the server returned.
|
||||
let stored_status = self
|
||||
.client
|
||||
.state_store()
|
||||
.load_thread_subscription(self.room_id(), &thread_root)
|
||||
.await?;
|
||||
|
||||
if let Some(ThreadStatus::Unsubscribed) = stored_status {
|
||||
// The thread was unsubscribed from before, so maintain this information.
|
||||
Ok(Some(ThreadStatus::Unsubscribed))
|
||||
} else {
|
||||
// We either have stale information (the thread was marked as subscribed
|
||||
// to, but the server said it wasn't), or we didn't have any information.
|
||||
// Return unknown.
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
_ => Err(http_error.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Status of a thread subscription.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct ThreadSubscription {
|
||||
/// Whether the subscription was made automatically by a client, not by
|
||||
/// manual user choice.
|
||||
pub automatic: bool,
|
||||
}
|
||||
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
impl RoomIdentityProvider for Room {
|
||||
fn is_member<'a>(&'a self, user_id: &'a UserId) -> BoxFuture<'a, bool> {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use matrix_sdk::test_utils::mocks::MatrixMockServer;
|
||||
use assert_matches2::assert_matches;
|
||||
use matrix_sdk::{room::ThreadStatus, test_utils::mocks::MatrixMockServer};
|
||||
use matrix_sdk_test::async_test;
|
||||
use ruma::{owned_event_id, room_id};
|
||||
|
||||
@@ -35,7 +36,7 @@ async fn test_subscribe_thread() {
|
||||
|
||||
// I can get the subscription status for that same thread.
|
||||
let subscription = room.fetch_thread_subscription(root_id.clone()).await.unwrap().unwrap();
|
||||
assert!(subscription.automatic);
|
||||
assert_matches!(subscription, ThreadStatus::Subscribed { automatic: true });
|
||||
|
||||
// If I try to get a subscription for a thread event that's unknown, I get no
|
||||
// `ThreadSubscription`, not an error.
|
||||
@@ -53,5 +54,10 @@ async fn test_subscribe_thread() {
|
||||
.mount()
|
||||
.await;
|
||||
|
||||
room.unsubscribe_thread(root_id).await.unwrap();
|
||||
room.unsubscribe_thread(root_id.clone()).await.unwrap();
|
||||
|
||||
// Now, if I retry to get the subscription status for this thread, it's
|
||||
// unsubscribed.
|
||||
let subscription = room.fetch_thread_subscription(root_id).await.unwrap();
|
||||
assert_matches!(subscription, Some(ThreadStatus::Unsubscribed));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use matrix_sdk::{
|
||||
api::client::receipt::create_receipt::v3::ReceiptType,
|
||||
events::room::message::RoomMessageEventContent,
|
||||
},
|
||||
store::ThreadStatus,
|
||||
};
|
||||
use matrix_sdk_ui::{
|
||||
Timeline,
|
||||
@@ -525,7 +526,16 @@ impl RoomView {
|
||||
Ok(Some(subscription)) => {
|
||||
status_handle.set_message(format!(
|
||||
"Thread subscription status: {}",
|
||||
if subscription.automatic { "automatic" } else { "manual" }
|
||||
match subscription {
|
||||
ThreadStatus::Subscribed { automatic } => {
|
||||
if automatic {
|
||||
"subscribed (automatic)"
|
||||
} else {
|
||||
"subscribed (manual)"
|
||||
}
|
||||
}
|
||||
ThreadStatus::Unsubscribed => "unsubscribed",
|
||||
}
|
||||
));
|
||||
}
|
||||
Ok(None) => {
|
||||
|
||||
Reference in New Issue
Block a user