atagen

macltok

public
Star0
Watch0

Commit 5b585cd970fd

tarball

atagen <boss@atagen.co>2026-10-25 10:27 UTC

1 file changed+62-3
notifications: make keyword rules highlight

The sdk builds keyword content rules with only notify and a default sound, so a keyword never highlighted and the mentions inbox could not tell it from ordinary noise. add_notification_keyword now sets the actions Element uses for loud keywords through the push rule actions endpoint, and upgrades an existing rule for the pattern that lacks the highlight, which keeps the change out of the sdk fork.
Modified file: src/engine/commands.rs+62 additions−3 deletions
@@ -4,10 +4,14 @@ use futures_util::FutureExt;
44 use matrix_sdk::encryption::verification::VerificationRequest;
55 use matrix_sdk::{
66 Client,
7- notification_settings::{IsEncrypted, IsOneToOne, RoomNotificationMode as SdkMode},
7+ notification_settings::{
8+ IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode as SdkMode,
9+ },
810 ruma::{
911 OwnedDeviceId, OwnedEventId, OwnedMxcUri, RoomId, TransactionId,
10- api::client::receipt::create_receipt::v3::ReceiptType, events::receipt::ReceiptThread,
12+ api::client::{push::set_pushrule_actions, receipt::create_receipt::v3::ReceiptType},
13+ events::receipt::ReceiptThread,
14+ push::{Action, HighlightTweakValue, RuleKind, SoundTweakValue, Tweak},
1115 },
1216 send_queue::{LocalEchoContent, SendHandle},
1317 };
@@ -134,7 +138,12 @@ async fn notification(client: &Client, command: NotificationCommand) -> Result<(
134138 )
135139 .await
136140 }
137- NotificationCommand::AddKeyword(keyword) => settings.add_keyword(keyword).await,
141+ NotificationCommand::AddKeyword(keyword) => {
142+ match settings.add_keyword(keyword.clone()).await {
143+ Ok(()) => return highlight_keyword(client, &settings, &keyword).await,
144+ Err(error) => Err(error),
145+ }
146+ }
138147 NotificationCommand::RemoveKeyword(keyword) => settings.remove_keyword(&keyword).await,
139148 }
140149 .map_err(|source| {
@@ -146,6 +155,56 @@ async fn notification(client: &Client, command: NotificationCommand) -> Result<(
146155 })
147156 }
148157
158+/// sdk keyword rules carry only notify and a sound, while Element's loud keywords also
159+/// highlight, which is what lets the inbox keep them as mentions
160+async fn highlight_keyword(
161+ client: &Client,
162+ settings: &NotificationSettings,
163+ keyword: &str,
164+) -> Result<(), Error> {
165+ let ruleset = settings.ruleset().await;
166+ for rule in ruleset
167+ .content
168+ .iter()
169+ .filter(|rule| !rule.default && rule.pattern == keyword)
170+ .filter(|rule| !rule.actions.iter().any(Action::is_highlight))
171+ {
172+ client
173+ .send(set_pushrule_actions::v3::Request::new(
174+ RuleKind::Content,
175+ rule.rule_id.clone(),
176+ keyword_actions(&rule.actions),
177+ ))
178+ .await
179+ .map_err(|source| {
180+ Error::from_sdk("highlighting a notification keyword failed", source.into())
181+ })?;
182+ }
183+ Ok(())
184+}
185+
186+fn keyword_actions(existing: &[Action]) -> Vec<Action> {
187+ let mut actions: Vec<_> = existing
188+ .iter()
189+ .filter(|action| !matches!(action, Action::SetTweak(Tweak::Highlight(_))))
190+ .cloned()
191+ .collect();
192+ if !actions
193+ .iter()
194+ .any(|action| matches!(action, Action::Notify))
195+ {
196+ actions.insert(0, Action::Notify);
197+ }
198+ if !actions
199+ .iter()
200+ .any(|action| matches!(action, Action::SetTweak(Tweak::Sound(_))))
201+ {
202+ actions.push(Action::SetTweak(Tweak::Sound(SoundTweakValue::Default)));
203+ }
204+ actions.push(Action::SetTweak(Tweak::Highlight(HighlightTweakValue::Yes)));
205+ actions
206+}
207+
149208 const fn sdk_mode(mode: RoomNotificationMode) -> SdkMode {
150209 match mode {
151210 RoomNotificationMode::AllMessages => SdkMode::AllMessages,