Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for MSC2867 - Manually marking rooms as unread #3076

Merged
merged 3 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ futures-executor = "0.3.21"
futures-util = { version = "0.3.26", default-features = false, features = ["alloc"] }
http = "0.2.6"
itertools = "0.12.0"
ruma = { git = "https://github.com/ruma/ruma", rev = "684ffc789877355bd25269451b2356817c17cc3f", features = ["client-api-c", "compat-upload-signatures", "compat-user-id", "compat-arbitrary-length-ids", "unstable-msc3401"] }
ruma-common = { git = "https://github.com/ruma/ruma", rev = "684ffc789877355bd25269451b2356817c17cc3f"}
ruma = { git = "https://github.com/ruma/ruma", rev = "68c9bb0930f2195fa8672fbef9633ef62737df5d", features = ["client-api-c", "compat-upload-signatures", "compat-user-id", "compat-arbitrary-length-ids", "unstable-msc3401"] }
ruma-common = { git = "https://github.com/ruma/ruma", rev = "68c9bb0930f2195fa8672fbef9633ef62737df5d"}
once_cell = "1.16.0"
rand = "0.8.5"
serde = "1.0.151"
Expand Down
34 changes: 33 additions & 1 deletion bindings/matrix-sdk-ffi/src/room.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use crate::{
room_info::RoomInfo,
room_member::RoomMember,
ruma::ImageInfo,
timeline::{EventTimelineItem, Timeline},
timeline::{EventTimelineItem, ReceiptType, Timeline},
utils::u64_to_uint,
TaskHandle,
};
Expand Down Expand Up @@ -517,6 +517,38 @@ impl Room {
pub async fn typing_notice(&self, is_typing: bool) -> Result<(), ClientError> {
Ok(self.inner.typing_notice(is_typing).await?)
}

/// Sets a flag on the room to indicate that the user has explicitly marked
/// it as unread
pub async fn mark_as_unread(&self) -> Result<(), ClientError> {
Ok(self.inner.mark_unread(true).await?)
}

/// Reverts a previously set unread flag.
pub async fn mark_as_read(&self) -> Result<(), ClientError> {
Ok(self.inner.mark_unread(false).await?)
}

/// Reverts a previously set unread flag and sends a read receipt to the
/// latest event in the room. Sending read receipts is useful when
/// executing this from the room list but shouldn't be use when entering
/// the room, the timeline should be left to its own devices in that
/// case.
pub async fn mark_as_read_and_send_read_receipt(
&self,
receipt_type: ReceiptType,
) -> Result<(), ClientError> {
let timeline = self.timeline().await?;

if let Some(event) = timeline.latest_event().await {
if let Err(error) = timeline.send_read_receipt(receipt_type, event.event_id().unwrap())
{
error!("Failed to send read receipt: {error}");
}
}

self.mark_as_read().await
}
}

#[uniffi::export(callback_interface)]
Expand Down
3 changes: 3 additions & 0 deletions bindings/matrix-sdk-ffi/src/room_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ pub struct RoomInfo {
user_defined_notification_mode: Option<RoomNotificationMode>,
has_room_call: bool,
active_room_call_participants: Vec<String>,
/// Whether this room has been explicitly marked as unread
is_marked_unread: bool,
/// "Interesting" messages received in that room, independently of the
/// notification settings.
num_unread_messages: u64,
Expand Down Expand Up @@ -84,6 +86,7 @@ impl RoomInfo {
.iter()
.map(|u| u.to_string())
.collect(),
is_marked_unread: room.is_marked_unread(),
num_unread_messages: room.num_unread_messages(),
num_unread_notifications: room.num_unread_notifications(),
num_unread_mentions: room.num_unread_mentions(),
Expand Down
6 changes: 6 additions & 0 deletions bindings/matrix-sdk-ffi/src/timeline/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,12 @@ impl Timeline {
Ok(Arc::new(RoomMessageEventContentWithoutRelation::new(msgtype)))
})
}

pub async fn latest_event(&self) -> Option<Arc<EventTimelineItem>> {
let latest_event = self.inner.latest_event().await;

latest_event.map(|item| Arc::new(EventTimelineItem(item)))
}
}

#[derive(uniffi::Record)]
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ matrix-sdk-crypto = { workspace = true, optional = true }
matrix-sdk-store-encryption = { workspace = true }
matrix-sdk-test = { workspace = true, optional = true }
once_cell = { workspace = true }
ruma = { workspace = true, features = ["canonical-json", "unstable-msc3381"] }
ruma = { workspace = true, features = ["canonical-json", "unstable-msc3381", "unstable-msc2867"] }
serde = { workspace = true, features = ["rc"] }
serde_json = { workspace = true }
tokio = { workspace = true }
Expand Down
16 changes: 15 additions & 1 deletion crates/matrix-sdk-base/src/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,21 @@ impl BaseClient {
) {
for raw_event in events {
if let Ok(event) = raw_event.deserialize() {
changes.add_room_account_data(room_id, event, raw_event.clone());
changes.add_room_account_data(room_id, event.clone(), raw_event.clone());

// Rooms can either appear in the current request or already be
// known to the store. If neither of
// those are true then the room is `unknown` and we cannot
// process its account data
if let AnyRoomAccountDataEvent::MarkedUnread(e) = event {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AnyRoomAccountDataEvent::MarkedUnread exists if and only if the ruma/unstable-msc2867 feature is enabled in the crates/matrix-sdk-base/Cargo.toml file.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've pushed bb3f7ed to solve it.

if let Some(room) = changes.room_infos.get_mut(room_id) {
room.base_info.is_marked_unread = e.content.unread;
} else if let Some(room) = self.store.get_room(room_id) {
let mut info = room.clone_info();
info.base_info.is_marked_unread = e.content.unread;
changes.add_room(info);
}
stefanceriu marked this conversation as resolved.
Show resolved Hide resolved
stefanceriu marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions crates/matrix-sdk-base/src/rooms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ pub struct BaseRoomInfo {
/// memberships.
#[serde(skip_serializing_if = "BTreeMap::is_empty", default)]
pub(crate) rtc_member: BTreeMap<OwnedUserId, MinimalStateEvent<CallMemberEventContent>>,
// Whether this room has been manually marked as unread
#[serde(default)]
pub(crate) is_marked_unread: bool,
}

impl BaseRoomInfo {
Expand Down Expand Up @@ -317,6 +320,7 @@ impl Default for BaseRoomInfo {
tombstone: None,
topic: None,
rtc_member: BTreeMap::new(),
is_marked_unread: false,
}
}
}
Expand Down
7 changes: 7 additions & 0 deletions crates/matrix-sdk-base/src/rooms/normal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -769,6 +769,12 @@ impl Room {
.get_event_room_receipt_events(self.room_id(), receipt_type, thread, event_id)
.await
}

/// Returns a boolean indicating if this room has been manually marked as
/// unread
pub fn is_marked_unread(&self) -> bool {
self.inner.read().base_info.is_marked_unread
}
}

/// The underlying pure data structure for joined and left rooms.
Expand Down Expand Up @@ -1393,6 +1399,7 @@ mod tests {
"encryption": null,
"guest_access": null,
"history_visibility": null,
"is_marked_unread": false,
"join_rules": null,
"max_power_level": 100,
"name": null,
Expand Down
11 changes: 2 additions & 9 deletions crates/matrix-sdk-base/src/sliding_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -219,8 +219,7 @@ impl BaseClient {
.push(raw.clone().cast());
}

// Handles the remaining rooms account data not handled by
// process_sliding_sync_room.
// Handle room account data
for (room_id, raw) in &rooms_account_data {
self.handle_room_account_data(room_id, raw, &mut changes).await;

Expand Down Expand Up @@ -363,13 +362,6 @@ impl BaseClient {
.await?;
}

let room_account_data = if let Some(events) = rooms_account_data.remove(room_id) {
self.handle_room_account_data(room_id, &events, changes).await;
Hywan marked this conversation as resolved.
Show resolved Hide resolved
Some(events)
} else {
None
};

process_room_properties(room_data, &mut room_info);

let timeline = self
Expand Down Expand Up @@ -414,6 +406,7 @@ impl BaseClient {
room_info.update_notification_count(notification_count);

let ambiguity_changes = ambiguity_cache.changes.remove(room_id).unwrap_or_default();
let room_account_data = rooms_account_data.get(room_id).cloned();

match room_info.state() {
RoomState::Joined => {
Expand Down
1 change: 1 addition & 0 deletions crates/matrix-sdk-base/src/store/migration_helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ impl BaseRoomInfoV1 {
tombstone,
topic,
rtc_member: BTreeMap::new(),
is_marked_unread: false,
})
}
}
Expand Down
2 changes: 1 addition & 1 deletion crates/matrix-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ matrix-sdk-sqlite = { workspace = true, optional = true }
mime = "0.3.16"
mime2ext = "0.1.52"
rand = { workspace = true , optional = true }
ruma = { workspace = true, features = ["rand", "unstable-msc2448", "unstable-msc2965", "unstable-msc3930", "unstable-msc3245-v1-compat"] }
ruma = { workspace = true, features = ["rand", "unstable-msc2448", "unstable-msc2965", "unstable-msc3930", "unstable-msc3245-v1-compat", "unstable-msc2867"] }
serde = { workspace = true }
serde_html_form = { workspace = true }
serde_json = { workspace = true }
Expand Down
21 changes: 20 additions & 1 deletion crates/matrix-sdk/src/room/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use ruma::events::{
};
use ruma::{
api::client::{
config::set_global_account_data,
config::{set_global_account_data, set_room_account_data},
context,
error::ErrorKind,
filter::LazyLoadOptions,
Expand All @@ -43,6 +43,7 @@ use ruma::{
assign,
events::{
direct::DirectEventContent,
marked_unread::MarkedUnreadEventContent,
receipt::{Receipt, ReceiptThread, ReceiptType},
room::{
avatar::{self, RoomAvatarEventContent},
Expand Down Expand Up @@ -2394,6 +2395,24 @@ impl Room {
);
Ok(self.client.send(request, None).await?)
}

/// Sets a flag on the room to indicate that the user has explicitly marked
/// it as (un)read
pub async fn mark_unread(&self, unread: bool) -> Result<()> {
stefanceriu marked this conversation as resolved.
Show resolved Hide resolved
let user_id =
self.client.user_id().ok_or_else(|| Error::from(HttpError::AuthenticationRequired))?;

let content = MarkedUnreadEventContent::new(unread);

let request = set_room_account_data::v3::Request::new(
user_id.to_owned(),
self.inner.room_id().to_owned(),
&content,
)?;

self.client.send(request, None).await?;
Ok(())
}
}

/// Details of the (latest) invite.
Expand Down
Loading
Loading