Skip to content

Commit

Permalink
draw_last and server settings
Browse files Browse the repository at this point in the history
TODO: fix barrage of past notifications
  • Loading branch information
benjajaja committed Mar 17, 2024
1 parent 29592ab commit 09ea5ad
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 44 deletions.
7 changes: 7 additions & 0 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -761,6 +761,9 @@ pub struct RoomInfo {

/// The display names for users in this room.
pub display_names: HashMap<OwnedUserId, String>,

/// The last time the room was rendered, used to detect if it is currently open.
pub draw_last: Option<Instant>,
}

impl RoomInfo {
Expand Down Expand Up @@ -1192,6 +1195,9 @@ pub struct ChatStore {

/// Image preview "protocol" picker.
pub picker: Option<Picker>,

/// Last draw time, used to match with RoomInfo's draw_last.
pub draw_curr: Option<Instant>,
}

impl ChatStore {
Expand All @@ -1212,6 +1218,7 @@ impl ChatStore {
verifications: Default::default(),
need_load: Default::default(),
sync_info: Default::default(),
draw_curr: None,
}
}

Expand Down
26 changes: 3 additions & 23 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -393,28 +393,8 @@ pub enum UserDisplayStyle {

#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
pub struct Notifications {
pub one_to_one: NotificationProcessing,
pub group_chats: NotificationProcessing,
// TODO: separate displayname, username, @room, and keywords.
pub mentions: NotificationProcessing,
// TODO: invitations, call-invitation, bots, and room-upgrades.
}

impl Notifications {
pub fn any(&self) -> bool {
self.one_to_one != NotificationProcessing::Off &&
self.group_chats != NotificationProcessing::Off &&
self.mentions != NotificationProcessing::Off
}
}

#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq)]
#[serde(rename_all = "lowercase")]
pub enum NotificationProcessing {
#[default]
Off,
On,
Noisy,
pub enabled: bool,
pub show_message: Option<bool>,
}

#[derive(Clone)]
Expand Down Expand Up @@ -567,7 +547,7 @@ impl Tunables {
message_user_color: self.message_user_color.unwrap_or(false),
default_room: self.default_room,
open_command: self.open_command,
notifications: self.notifications.unwrap_or(Notifications::default()),
notifications: self.notifications.unwrap_or_default(),
image_preview: self.image_preview.map(ImagePreview::values),
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::ops::DerefMut;
use std::process;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use std::time::Duration;
use std::time::{Duration, Instant};

use clap::Parser;
use matrix_sdk::crypto::encrypt_room_key_export;
Expand Down Expand Up @@ -305,6 +305,7 @@ impl Application {
// Don't show terminal cursor when we show a dialog.
let hide_cursor = !dialogstr.is_empty();

store.application.draw_curr = Some(Instant::now());
let screen = Screen::new(store)
.show_dialog(dialogstr)
.show_mode(modestr)
Expand Down
105 changes: 87 additions & 18 deletions src/notifications.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,66 @@
use matrix_sdk::{
notification_settings::{IsEncrypted, IsOneToOne, NotificationSettings, RoomNotificationMode},
room::Room as MatrixRoom,
ruma::{
api::client::push::get_notifications::v3::Notification,
events::{room::message::MessageType, AnyMessageLikeEventContent, AnySyncTimelineEvent},
RoomId,
},
Client,
};

use crate::{
base::{IambError, IambResult},
base::{AsyncProgramStore, IambError, IambResult},
config::ApplicationSettings,
};

pub async fn register_notifications(client: &Client, settings: &ApplicationSettings) {
if !settings.tunables.notifications.any() {
pub async fn register_notifications(
client: &Client,
settings: &ApplicationSettings,
store: &AsyncProgramStore,
) {
if !settings.tunables.notifications.enabled {
return;
}
let show_message = settings.tunables.notifications.show_message;
let server_settings = client.notification_settings().await;

let store = store.clone();
client
.register_notification_handler(|notification, room: MatrixRoom, _: Client| {
// TODO: check if room is one-to-one or group against settings.
.register_notification_handler(move |notification, room: MatrixRoom, client: Client| {
let store = store.clone();
let server_settings = server_settings.clone();
async move {
match parse_notification(notification, room).await {
Ok((summary, body)) => {
// TODO: check if mention against settings.
let Some(body) = body else {
// Never show without a body?
return;
};
let mode = global_or_room_mode(&server_settings, &room).await;
if mode == RoomNotificationMode::Mute {
return;
}

if is_open(&store, room.room_id()).await {
eprintln!("is open");
return;
}

// TODO: never show if room is currently open.
eprintln!("notify...");

if let Err(err) = notify_rust::Notification::new()
match parse_notification(notification, room).await {
Ok((summary, body)) => {
let mut notification = notify_rust::Notification::new();
notification
.summary(&summary)
.body(&body)
.appname("iamb")
.timeout(notify_rust::Timeout::Milliseconds(3000))
.action("default", "default")
.show()
{
.action("default", "default");

if is_missing_mention(&body, mode, &client) {
return;
}
if show_message != Some(false) {
if let Some(body) = body {
notification.body(&body);
}
}
if let Err(err) = notification.show() {
tracing::error!("Failed to send notification: {err}")
}
},
Expand All @@ -51,12 +74,58 @@ pub async fn register_notifications(client: &Client, settings: &ApplicationSetti
return;
}

async fn global_or_room_mode(
settings: &NotificationSettings,
room: &MatrixRoom,
) -> RoomNotificationMode {
let room_mode = settings.get_user_defined_room_notification_mode(room.room_id()).await;
if let Some(mode) = room_mode {
return mode;
}
let is_one_to_one = match room.is_direct().await {
Ok(true) => IsOneToOne::Yes,
_ => IsOneToOne::No,
};
let is_encrypted = match room.is_encrypted().await {
Ok(true) => IsEncrypted::Yes,
_ => IsEncrypted::No,
};
settings
.get_default_room_notification_mode(is_encrypted, is_one_to_one)
.await
}

fn is_missing_mention(body: &Option<String>, mode: RoomNotificationMode, client: &Client) -> bool {
if let Some(body) = body {
if mode == RoomNotificationMode::MentionsAndKeywordsOnly {
let mentioned = match client.user_id() {
Some(user_id) => body.contains(user_id.localpart()),
_ => false,
};
return !mentioned;
}
}
false
}

async fn is_open(store: &AsyncProgramStore, room_id: &RoomId) -> bool {
let mut locked = store.lock().await;
if let Some(draw_curr) = locked.application.draw_curr {
let info = locked.application.get_room_info(room_id.to_owned());
if info.draw_last.is_some() && info.draw_last.unwrap() == draw_curr {
return true;
}
}
false
}

pub async fn parse_notification(
notification: Notification,
room: MatrixRoom,
) -> IambResult<(String, Option<String>)> {
let event = notification.event.deserialize().map_err(IambError::from)?;

let _event_id = event.event_id();
let sender_id = event.sender();
let sender = room.get_member_no_sync(sender_id).await.map_err(IambError::from)?;

Expand Down
4 changes: 3 additions & 1 deletion src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::{
user_style_from_color,
ApplicationSettings,
DirectoryValues,
Notifications,
ProfileConfig,
SortOverrides,
TunableValues,
Expand Down Expand Up @@ -164,6 +165,7 @@ pub fn mock_room() -> RoomInfo {
fetch_last: None,
users_typing: None,
display_names: HashMap::new(),
draw_last: None,
}
}

Expand Down Expand Up @@ -198,7 +200,7 @@ pub fn mock_tunables() -> TunableValues {
open_command: None,
username_display: UserDisplayStyle::Username,
message_user_color: false,
notifications: false,
notifications: Notifications { enabled: false, show_message: None },
image_preview: None,
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/windows/room/scrollback.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1437,6 +1437,8 @@ impl<'a> StatefulWidget for Scrollback<'a> {
.need_load
.insert(state.room_id.to_owned(), Need::MESSAGES);
}

info.draw_last = self.store.application.draw_curr;
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/worker.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1249,7 +1249,7 @@ impl ClientWorker {
let load = load_older_forever(&client, &store);
let rcpt = send_receipts_forever(&client, &store);
let room = refresh_rooms_forever(&client, &store);
let notifications = register_notifications(&client, &settings);
let notifications = register_notifications(&client, &settings, &store);

let ((), (), (), _) = tokio::join!(load, rcpt, room, notifications);
}
Expand Down

0 comments on commit 09ea5ad

Please sign in to comment.