|
|
|
@ -1,13 +1,6 @@ |
|
|
|
use gtk::{ |
|
|
|
use gtk::{gio, glib, prelude::*, subclass::prelude::*}; |
|
|
|
gio, |
|
|
|
use matrix_sdk::{sync::Notification, Room as MatrixRoom}; |
|
|
|
glib::{self, clone}, |
|
|
|
use ruma::{EventId, OwnedRoomId, RoomId}; |
|
|
|
prelude::*, |
|
|
|
|
|
|
|
subclass::prelude::*, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
use ruma::{ |
|
|
|
|
|
|
|
api::client::push::get_notifications::v3::Notification, EventId, OwnedEventId, OwnedRoomId, |
|
|
|
|
|
|
|
RoomId, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
use tracing::{debug, error, warn}; |
|
|
|
use tracing::{debug, error, warn}; |
|
|
|
|
|
|
|
|
|
|
|
mod notifications_settings; |
|
|
|
mod notifications_settings; |
|
|
|
@ -17,7 +10,11 @@ pub use self::notifications_settings::{ |
|
|
|
}; |
|
|
|
}; |
|
|
|
use super::{Room, Session}; |
|
|
|
use super::{Room, Session}; |
|
|
|
use crate::{ |
|
|
|
use crate::{ |
|
|
|
intent, prelude::*, spawn, spawn_tokio, utils::matrix::get_event_body, Application, Window, |
|
|
|
intent, |
|
|
|
|
|
|
|
prelude::*, |
|
|
|
|
|
|
|
spawn_tokio, |
|
|
|
|
|
|
|
utils::matrix::{get_event_body, AnySyncOrStrippedTimelineEvent}, |
|
|
|
|
|
|
|
Application, Window, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
mod imp { |
|
|
|
mod imp { |
|
|
|
@ -31,9 +28,8 @@ mod imp { |
|
|
|
/// The current session.
|
|
|
|
/// The current session.
|
|
|
|
#[property(get, set = Self::set_session, explicit_notify, nullable)] |
|
|
|
#[property(get, set = Self::set_session, explicit_notify, nullable)] |
|
|
|
pub session: glib::WeakRef<Session>, |
|
|
|
pub session: glib::WeakRef<Session>, |
|
|
|
/// A map of room ID to list of event IDs for which a notification was
|
|
|
|
/// A map of room ID to list of notification IDs.
|
|
|
|
/// sent to the system.
|
|
|
|
pub list: RefCell<HashMap<OwnedRoomId, Vec<String>>>, |
|
|
|
pub list: RefCell<HashMap<OwnedRoomId, Vec<OwnedEventId>>>, |
|
|
|
|
|
|
|
/// The notifications settings for this session.
|
|
|
|
/// The notifications settings for this session.
|
|
|
|
#[property(get)] |
|
|
|
#[property(get)] |
|
|
|
pub settings: NotificationsSettings, |
|
|
|
pub settings: NotificationsSettings, |
|
|
|
@ -77,13 +73,7 @@ impl Notifications { |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// The notification won't be shown if the application is active and this
|
|
|
|
/// The notification won't be shown if the application is active and this
|
|
|
|
/// session is displayed.
|
|
|
|
/// session is displayed.
|
|
|
|
pub fn show(&self, matrix_notification: Notification) { |
|
|
|
pub async fn show(&self, matrix_notification: Notification, matrix_room: MatrixRoom) { |
|
|
|
spawn!(clone!(@weak self as obj => async move { |
|
|
|
|
|
|
|
obj.show_inner(matrix_notification).await; |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async fn show_inner(&self, matrix_notification: Notification) { |
|
|
|
|
|
|
|
let Some(session) = self.session() else { |
|
|
|
let Some(session) = self.session() else { |
|
|
|
return; |
|
|
|
return; |
|
|
|
}; |
|
|
|
}; |
|
|
|
@ -96,6 +86,7 @@ impl Notifications { |
|
|
|
let app = Application::default(); |
|
|
|
let app = Application::default(); |
|
|
|
let window = app.active_window().and_downcast::<Window>(); |
|
|
|
let window = app.active_window().and_downcast::<Window>(); |
|
|
|
let session_id = session.session_id(); |
|
|
|
let session_id = session.session_id(); |
|
|
|
|
|
|
|
let room_id = matrix_room.room_id(); |
|
|
|
|
|
|
|
|
|
|
|
// Don't show notifications for the current room in the current session if the
|
|
|
|
// Don't show notifications for the current room in the current session if the
|
|
|
|
// window is active.
|
|
|
|
// window is active.
|
|
|
|
@ -104,32 +95,27 @@ impl Notifications { |
|
|
|
&& w.current_session_id().as_deref() == Some(session_id) |
|
|
|
&& w.current_session_id().as_deref() == Some(session_id) |
|
|
|
&& w.session_view() |
|
|
|
&& w.session_view() |
|
|
|
.selected_room() |
|
|
|
.selected_room() |
|
|
|
.is_some_and(|r| r.room_id() == matrix_notification.room_id) |
|
|
|
.is_some_and(|r| r.room_id() == room_id) |
|
|
|
}) { |
|
|
|
}) { |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
let Some(room) = session.room_list().get(&matrix_notification.room_id) else { |
|
|
|
let Some(room) = session.room_list().get(room_id) else { |
|
|
|
warn!( |
|
|
|
warn!("Could not display notification for missing room {room_id}",); |
|
|
|
"Could not display notification for missing room {}", |
|
|
|
|
|
|
|
matrix_notification.room_id |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
return; |
|
|
|
return; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let event = match matrix_notification.event.deserialize() { |
|
|
|
let event = match AnySyncOrStrippedTimelineEvent::from_raw(&matrix_notification.event) { |
|
|
|
Ok(event) => event, |
|
|
|
Ok(event) => event, |
|
|
|
Err(error) => { |
|
|
|
Err(error) => { |
|
|
|
warn!( |
|
|
|
warn!( |
|
|
|
"Could not display notification for unrecognized event in room {}: {error}", |
|
|
|
"Could not display notification for unrecognized event in room {room_id}: {error}", |
|
|
|
matrix_notification.room_id |
|
|
|
|
|
|
|
); |
|
|
|
); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
let is_direct = room.direct_member().is_some(); |
|
|
|
let is_direct = room.direct_member().is_some(); |
|
|
|
let matrix_room = room.matrix_room().clone(); |
|
|
|
|
|
|
|
let sender_id = event.sender(); |
|
|
|
let sender_id = event.sender(); |
|
|
|
let owned_sender_id = sender_id.to_owned(); |
|
|
|
let owned_sender_id = sender_id.to_owned(); |
|
|
|
let handle = |
|
|
|
let handle = |
|
|
|
@ -148,7 +134,7 @@ impl Notifications { |
|
|
|
.and_then(|m| m.display_name()) |
|
|
|
.and_then(|m| m.display_name()) |
|
|
|
.unwrap_or_else(|| sender_id.localpart()); |
|
|
|
.unwrap_or_else(|| sender_id.localpart()); |
|
|
|
|
|
|
|
|
|
|
|
let body = match get_event_body(&event, sender_name, !is_direct) { |
|
|
|
let body = match get_event_body(&event, sender_name, session.user_id(), !is_direct) { |
|
|
|
Some(body) => body, |
|
|
|
Some(body) => body, |
|
|
|
None => { |
|
|
|
None => { |
|
|
|
debug!("Received notification for event of unexpected type {event:?}",); |
|
|
|
debug!("Received notification for event of unexpected type {event:?}",); |
|
|
|
@ -183,7 +169,7 @@ impl Notifications { |
|
|
|
.borrow_mut() |
|
|
|
.borrow_mut() |
|
|
|
.entry(room_id) |
|
|
|
.entry(room_id) |
|
|
|
.or_default() |
|
|
|
.or_default() |
|
|
|
.push(event_id.to_owned()); |
|
|
|
.push(id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Ask the system to remove the known notifications for the given room.
|
|
|
|
/// Ask the system to remove the known notifications for the given room.
|
|
|
|
@ -191,16 +177,11 @@ impl Notifications { |
|
|
|
/// Only the notifications that were shown since the application's startup
|
|
|
|
/// Only the notifications that were shown since the application's startup
|
|
|
|
/// are known, older ones might still be present.
|
|
|
|
/// are known, older ones might still be present.
|
|
|
|
pub fn withdraw_all_for_room(&self, room: &Room) { |
|
|
|
pub fn withdraw_all_for_room(&self, room: &Room) { |
|
|
|
let Some(session) = self.session() else { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let room_id = room.room_id(); |
|
|
|
let room_id = room.room_id(); |
|
|
|
if let Some(notifications) = self.imp().list.borrow_mut().remove(room_id) { |
|
|
|
if let Some(notifications) = self.imp().list.borrow_mut().remove(room_id) { |
|
|
|
let app = Application::default(); |
|
|
|
let app = Application::default(); |
|
|
|
|
|
|
|
|
|
|
|
for event_id in notifications { |
|
|
|
for id in notifications { |
|
|
|
let id = notification_id(session.session_id(), room_id, &event_id); |
|
|
|
|
|
|
|
app.withdraw_notification(&id); |
|
|
|
app.withdraw_notification(&id); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -211,17 +192,10 @@ impl Notifications { |
|
|
|
/// Only the notifications that were shown since the application's startup
|
|
|
|
/// Only the notifications that were shown since the application's startup
|
|
|
|
/// are known, older ones might still be present.
|
|
|
|
/// are known, older ones might still be present.
|
|
|
|
pub fn clear(&self) { |
|
|
|
pub fn clear(&self) { |
|
|
|
let Some(session) = self.session() else { |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let app = Application::default(); |
|
|
|
let app = Application::default(); |
|
|
|
|
|
|
|
|
|
|
|
for (room_id, notifications) in self.imp().list.take() { |
|
|
|
for id in self.imp().list.take().values().flatten() { |
|
|
|
for event_id in notifications { |
|
|
|
app.withdraw_notification(id); |
|
|
|
let id = notification_id(session.session_id(), &room_id, &event_id); |
|
|
|
|
|
|
|
app.withdraw_notification(&id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
@ -232,6 +206,11 @@ impl Default for Notifications { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fn notification_id(session_id: &str, room_id: &RoomId, event_id: &EventId) -> String { |
|
|
|
fn notification_id(session_id: &str, room_id: &RoomId, event_id: Option<&EventId>) -> String { |
|
|
|
format!("{session_id}//{room_id}//{event_id}") |
|
|
|
if let Some(event_id) = event_id { |
|
|
|
|
|
|
|
format!("{session_id}//{room_id}//{event_id}") |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
let random_id = glib::uuid_string_random(); |
|
|
|
|
|
|
|
format!("{session_id}//{room_id}//{random_id}") |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|