Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 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
1 change: 1 addition & 0 deletions Cargo.lock

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

3 changes: 3 additions & 0 deletions bindings/matrix-sdk-ffi/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ All notable changes to this project will be documented in this file.
This is primarily for Element X to give a dedicated error message in case
it connects a homeserver with only this method available.
([#5222](https://github.com/matrix-org/matrix-rust-sdk/pull/5222))
- Add `Action::NotifyInApp` and a new field `notify_in_app` in `RoomNotificationMode::MentionsAndKeywordsOnly`
behind a new feature `unstable-msc3768`.
([#5441](https://github.com/matrix-org/matrix-rust-sdk/pull/5441))

### Breaking changes:

Expand Down
1 change: 1 addition & 0 deletions bindings/matrix-sdk-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ crate-type = [
[features]
default = ["bundled-sqlite", "unstable-msc4274"]
bundled-sqlite = ["matrix-sdk/bundled-sqlite"]
unstable-msc3768 = ["matrix-sdk-ui/unstable-msc3768"]
unstable-msc4274 = ["matrix-sdk-ui/unstable-msc4274"]
# Required when targeting a Javascript environment, like Wasm in a browser.
js = ["matrix-sdk-ui/js"]
Expand Down
38 changes: 32 additions & 6 deletions bindings/matrix-sdk-ffi/src/notification_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -322,8 +322,13 @@ impl TryFrom<Tweak> for SdkTweak {
#[derive(Clone, uniffi::Enum)]
/// Enum representing the push notification actions for a rule.
pub enum Action {
/// Causes matching events to generate a notification.
/// Causes matching events to generate a notification (both in-app and
/// remote / push).
Notify,
/// Causes matching events to generate an in-app notification but no remote
/// / push notification.
#[cfg(feature = "unstable-msc3768")]
NotifyInApp,
/// Sets an entry in the 'tweaks' dictionary sent to the push gateway.
SetTweak { value: Tweak },
}
Expand All @@ -334,6 +339,8 @@ impl TryFrom<SdkAction> for Action {
fn try_from(value: SdkAction) -> Result<Self, Self::Error> {
Ok(match value {
SdkAction::Notify => Self::Notify,
#[cfg(feature = "unstable-msc3768")]
SdkAction::NotifyInApp => Self::NotifyInApp,
SdkAction::SetTweak(tweak) => Self::SetTweak {
value: tweak.try_into().map_err(|e| format!("Failed to convert tweak: {e}"))?,
},
Expand All @@ -348,6 +355,8 @@ impl TryFrom<Action> for SdkAction {
fn try_from(value: Action) -> Result<Self, Self::Error> {
Ok(match value {
Action::Notify => Self::Notify,
#[cfg(feature = "unstable-msc3768")]
Action::NotifyInApp => Self::NotifyInApp,
Action::SetTweak { value } => Self::SetTweak(
value.try_into().map_err(|e| format!("Failed to convert tweak: {e}"))?,
),
Expand All @@ -358,10 +367,15 @@ impl TryFrom<Action> for SdkAction {
/// Enum representing the push notification modes for a room.
#[derive(Clone, uniffi::Enum)]
pub enum RoomNotificationMode {
/// Receive notifications for all messages.
/// Receive remote and in-app notifications for all messages.
AllMessages,
/// Receive notifications for mentions and keywords only.
MentionsAndKeywordsOnly,
/// Receive remote and in-app notifications for mentions and keywords only.
MentionsAndKeywordsOnly {
/// If true, receive in-app-only notifications (no pushes) for other
/// room messages. Otherwise, mute all other room messages.
#[cfg(feature = "unstable-msc3768")]
notify_in_app: bool,
},
/// Do not receive any notifications.
Mute,
}
Expand All @@ -370,7 +384,13 @@ impl From<SdkRoomNotificationMode> for RoomNotificationMode {
fn from(value: SdkRoomNotificationMode) -> Self {
match value {
SdkRoomNotificationMode::AllMessages => Self::AllMessages,
SdkRoomNotificationMode::MentionsAndKeywordsOnly => Self::MentionsAndKeywordsOnly,
SdkRoomNotificationMode::MentionsAndKeywordsOnly {
#[cfg(feature = "unstable-msc3768")]
notify_in_app,
} => Self::MentionsAndKeywordsOnly {
#[cfg(feature = "unstable-msc3768")]
notify_in_app,
},
SdkRoomNotificationMode::Mute => Self::Mute,
}
}
Expand All @@ -380,7 +400,13 @@ impl From<RoomNotificationMode> for SdkRoomNotificationMode {
fn from(value: RoomNotificationMode) -> Self {
match value {
RoomNotificationMode::AllMessages => Self::AllMessages,
RoomNotificationMode::MentionsAndKeywordsOnly => Self::MentionsAndKeywordsOnly,
RoomNotificationMode::MentionsAndKeywordsOnly {
#[cfg(feature = "unstable-msc3768")]
notify_in_app,
} => Self::MentionsAndKeywordsOnly {
#[cfg(feature = "unstable-msc3768")]
notify_in_app,
},
RoomNotificationMode::Mute => Self::Mute,
}
}
Expand Down
3 changes: 3 additions & 0 deletions crates/matrix-sdk-base/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ All notable changes to this project will be documented in this file.
`RoomInfo::invite_details` method returns both the timestamp and the
inviter.
([#5390](https://github.com/matrix-org/matrix-rust-sdk/pull/5390))
- Add a new field `notify_in_app` in `RoomNotificationMode::MentionsAndKeywordsOnly`
behind a new feature `unstable-msc3768`.
([#5441](https://github.com/matrix-org/matrix-rust-sdk/pull/5441

### Refactor
- [**breaking**] `RelationalLinkedChunk::items` now takes a `RoomId` instead of an
Expand Down
1 change: 1 addition & 0 deletions crates/matrix-sdk-base/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ qrcode = ["matrix-sdk-crypto?/qrcode"]
automatic-room-key-forwarding = ["matrix-sdk-crypto?/automatic-room-key-forwarding"]
experimental-send-custom-to-device = ["matrix-sdk-crypto?/experimental-send-custom-to-device"]
uniffi = ["dep:uniffi", "matrix-sdk-crypto?/uniffi", "matrix-sdk-common/uniffi"]
unstable-msc3768 = ["ruma/unstable-msc3768"]

# Private feature, see
# https://github.com/matrix-org/matrix-rust-sdk/pull/3749#issuecomment-2312939823 for the gory
Expand Down
11 changes: 8 additions & 3 deletions crates/matrix-sdk-base/src/notification_settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,15 @@ use serde::{Deserialize, Serialize};
/// Enum representing the push notification modes for a room.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum RoomNotificationMode {
/// Receive notifications for all messages.
/// Receive remote and in-app notifications for all messages.
AllMessages,
/// Receive notifications for mentions and keywords only.
MentionsAndKeywordsOnly,
/// Receive remote and in-app notifications for mentions and keywords only.
MentionsAndKeywordsOnly {
/// If true, receive in-app-only notifications (no pushes) for other
/// room messages. Otherwise, mute all other room messages.
#[cfg(feature = "unstable-msc3768")]
notify_in_app: bool,
},
/// Do not receive any notifications.
Mute,
}
11 changes: 11 additions & 0 deletions crates/matrix-sdk-base/src/read_receipts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,17 @@ mod tests {
assert_eq!(receipts.num_mentions, 1);
assert_eq!(receipts.num_notifications, 1);

// NotifyInApp is treated like Notify
#[cfg(feature = "unstable-msc3768")]
{
let event = make_event(user_id!("@bob:example.org"), vec![Action::NotifyInApp]);
let mut receipts = RoomReadReceipts::default();
receipts.process_event(&event, user_id, ThreadingSupport::Disabled);
assert_eq!(receipts.num_unread, 1);
assert_eq!(receipts.num_mentions, 0);
assert_eq!(receipts.num_notifications, 1);
}

// Technically this `push_actions` set would be a bug somewhere else, but let's
// make sure to resist against it.
let event = make_event(user_id!("@bob:example.org"), vec![Action::Notify, Action::Notify]);
Expand Down
4 changes: 4 additions & 0 deletions crates/matrix-sdk-ui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ rustls-tls = ["matrix-sdk/rustls-tls"]
js = ["matrix-sdk/js"]
uniffi = ["dep:uniffi", "matrix-sdk/uniffi", "matrix-sdk-base/uniffi"]

# Add support for in-app only notifications
unstable-msc3768 = ["matrix-sdk/unstable-msc3768"]

# Add support for encrypted extensible events.
unstable-msc3956 = ["ruma/unstable-msc3956"]

Expand Down Expand Up @@ -58,6 +61,7 @@ tracing = { workspace = true, features = ["attributes"] }
unicode-normalization.workspace = true
uniffi = { workspace = true, optional = true }

cfg-if = "1.0.0"
emojis = "0.6.4"
unicode-segmentation = "1.12.0"

Expand Down
16 changes: 14 additions & 2 deletions crates/matrix-sdk-ui/src/notification_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ use std::{
time::Duration,
};

use cfg_if::cfg_if;
use futures_util::{StreamExt as _, pin_mut};
use matrix_sdk::{
Client, ClientBuildError, SlidingSyncList, SlidingSyncMode, room::Room, sleep::sleep,
Expand Down Expand Up @@ -677,7 +678,7 @@ impl NotificationClient {

let should_notify = push_actions
.as_ref()
.is_some_and(|actions| actions.iter().any(|a| a.should_notify()));
.is_some_and(|actions| actions.iter().any(should_action_notify_remote));

if !should_notify {
// The event has been filtered out by the user's push rules.
Expand Down Expand Up @@ -749,7 +750,7 @@ impl NotificationClient {
}

if let Some(actions) = timeline_event.push_actions()
&& !actions.iter().any(|a| a.should_notify())
&& !actions.iter().any(should_action_notify_remote)
{
return Ok(NotificationStatus::EventFilteredOut);
}
Expand All @@ -771,6 +772,17 @@ impl NotificationClient {
}
}

fn should_action_notify_remote(action: &Action) -> bool {
cfg_if! {
if #[cfg(feature = "unstable-msc3768")] {
action.should_notify_remote()
} else {
// Before MSC3768 only combined remote/local notifications existed
action.should_notify()
}
}
}

fn is_event_encrypted(event_type: TimelineEventType) -> bool {
let is_still_encrypted = matches!(event_type, TimelineEventType::RoomEncrypted);

Expand Down
3 changes: 3 additions & 0 deletions crates/matrix-sdk/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ experimental-widgets = ["dep:uuid", "experimental-send-custom-to-device"]

docsrs = ["e2e-encryption", "sqlite", "indexeddb", "sso-login", "qrcode"]

# Add support for in-app only notifications
unstable-msc3768 = ["matrix-sdk-base/unstable-msc3768"]

# Add support for inline media galleries via msgtypes
unstable-msc4274 = ["ruma/unstable-msc4274", "matrix-sdk-base/unstable-msc4274"]

Expand Down
43 changes: 30 additions & 13 deletions crates/matrix-sdk/src/notification_settings/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use crate::NotificationSettingsError;
#[derive(Clone, Debug)]
pub(crate) enum Command {
/// Set a new `Room` push rule
SetRoomPushRule { room_id: OwnedRoomId, notify: bool },
SetRoomPushRule { room_id: OwnedRoomId, notify: Notify },
/// Set a new `Override` push rule matching a `RoomId`
SetOverridePushRule { rule_id: String, room_id: OwnedRoomId, notify: bool },
SetOverridePushRule { rule_id: String, room_id: OwnedRoomId, notify: Notify },
/// Set a new push rule for a keyword.
SetKeywordPushRule { keyword: String },
/// Set whether a push rule is enabled
Expand All @@ -29,21 +29,13 @@ pub(crate) enum Command {
SetCustomPushRule { rule: NewPushRule },
}

fn get_notify_actions(notify: bool) -> Vec<Action> {
if notify {
vec![Action::Notify, Action::SetTweak(Tweak::Sound("default".into()))]
} else {
vec![]
}
}

impl Command {
/// Tries to create a push rule corresponding to this command
pub(crate) fn to_push_rule(&self) -> Result<NewPushRule, NotificationSettingsError> {
match self {
Self::SetRoomPushRule { room_id, notify } => {
// `Room` push rule for this `room_id`
let new_rule = NewSimplePushRule::new(room_id.clone(), get_notify_actions(*notify));
let new_rule = NewSimplePushRule::new(room_id.clone(), notify.get_actions());
Ok(NewPushRule::Room(new_rule))
}

Expand All @@ -55,7 +47,7 @@ impl Command {
key: "room_id".to_owned(),
pattern: room_id.to_string(),
}],
get_notify_actions(*notify),
notify.get_actions(),
);
Ok(NewPushRule::Override(new_rule))
}
Expand All @@ -65,7 +57,7 @@ impl Command {
let new_rule = NewPatternedPushRule::new(
keyword.clone(),
keyword.clone(),
get_notify_actions(true),
Notify::All.get_actions(),
);
Ok(NewPushRule::Content(new_rule))
}
Expand All @@ -80,3 +72,28 @@ impl Command {
}
}
}

/// Enum describing if and how to deliver a notification.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub(crate) enum Notify {
/// Generate a notification both in-app and remote / push.
All,

/// Only generate an in-app notification but no remote / push notification.
#[cfg(feature = "unstable-msc3768")]
InAppOnly,

/// Don't notify at all.
None,
}

impl Notify {
fn get_actions(&self) -> Vec<Action> {
match self {
Self::All => vec![Action::Notify, Action::SetTweak(Tweak::Sound("default".into()))],
#[cfg(feature = "unstable-msc3768")]
Self::InAppOnly => vec![Action::NotifyInApp],
Self::None => Vec::new(),
}
}
}
Loading
Loading