Private
Public Access
1
0

Implements mark as read

This commit is contained in:
2025-06-18 15:02:04 -07:00
parent fa6c7c50b7
commit 3b30cb77c8
13 changed files with 172 additions and 13 deletions

View File

@@ -43,6 +43,12 @@
value="Initiates a background sync of a single conversation with the server."/>
</method>
<method name="MarkConversationAsRead">
<arg type="s" name="conversation_id" direction="in"/>
<annotation name="org.freedesktop.DBus.DocString"
value="Marks a conversation as read."/>
</method>
<signal name="ConversationsUpdated">
<annotation name="org.freedesktop.DBus.DocString"
value="Emitted when the list of conversations is updated."/>

View File

@@ -26,6 +26,12 @@ pub enum Event {
/// Asynchronous event for syncing a single conversation with the server.
SyncConversation(String, Reply<()>),
/// Asynchronous event for marking a conversation as read.
MarkConversationAsRead(String, Reply<()>),
/// Asynchronous event for updating the metadata for a conversation.
UpdateConversationMetadata(Conversation, Reply<()>),
/// Sent when the update stream is reconnected after a timeout or configuration change.
UpdateStreamReconnected,

View File

@@ -63,6 +63,7 @@ pub mod target {
pub static SETTINGS: &str = "settings";
pub static UPDATES: &str = "updates";
pub static ATTACHMENTS: &str = "attachments";
pub static DAEMON: &str = "daemon";
}
pub struct Daemon {
@@ -221,6 +222,31 @@ impl Daemon {
reply.send(()).unwrap();
}
Event::MarkConversationAsRead(conversation_id, reply) => {
let mut db_clone = self.database.clone();
self.runtime.spawn(async move {
let result = Self::mark_conversation_as_read_impl(&mut db_clone, conversation_id).await;
if let Err(e) = result {
log::error!(target: target::DAEMON, "Error handling mark conversation as read event: {}", e);
}
});
reply.send(()).unwrap();
}
Event::UpdateConversationMetadata(conversation, reply) => {
let mut db_clone = self.database.clone();
let signal_sender = self.signal_sender.clone();
self.runtime.spawn(async move {
let result = Self::update_conversation_metadata_impl(&mut db_clone, conversation, &signal_sender).await;
if let Err(e) = result {
log::error!(target: target::DAEMON, "Error handling update conversation metadata event: {}", e);
}
});
reply.send(()).unwrap();
}
Event::UpdateStreamReconnected => {
log::info!(target: target::UPDATES, "Update stream reconnected");
@@ -590,6 +616,33 @@ impl Daemon {
Ok(())
}
async fn mark_conversation_as_read_impl(
database: &mut Arc<Mutex<Database>>,
conversation_id: String,
) -> Result<()> {
log::debug!(target: target::DAEMON, "Marking conversation as read: {}", conversation_id);
let mut client = Self::get_client_impl(database).await?;
client.mark_conversation_as_read(&conversation_id).await?;
Ok(())
}
async fn update_conversation_metadata_impl(
database: &mut Arc<Mutex<Database>>,
conversation: Conversation,
signal_sender: &Sender<Signal>,
) -> Result<()> {
log::debug!(target: target::DAEMON, "Updating conversation metadata: {}", conversation.guid);
let updated = database.with_repository(|r| r.merge_conversation_metadata(conversation)).await?;
if updated {
signal_sender
.send(Signal::ConversationsUpdated)
.await?;
}
Ok(())
}
async fn get_settings(&mut self) -> Result<Settings> {
let settings = self.database.with_settings(Settings::from_db).await?;
Ok(settings)

View File

@@ -65,11 +65,19 @@ impl UpdateMonitor {
UpdateEventData::ConversationChanged(conversation) => {
log::info!(target: target::UPDATES, "Conversation changed: {:?}", conversation);
// Explicitly update the unread count, we assume this is fresh from the notification.
let db_conversation: kordophone_db::models::Conversation = conversation.clone().into();
self.send_event(|r| Event::UpdateConversationMetadata(db_conversation, r))
.await
.unwrap_or_else(|e| {
log::error!("Failed to send daemon event: {}", e);
});
// Check if we've synced this conversation recently (within 5 seconds)
// This is currently a hack/workaround to prevent an infinite loop of sync events, because for some reason
// imagent will post a conversation changed notification when we call getMessages.
if let Some(last_sync) = self.last_sync_times.get(&conversation.guid) {
if last_sync.elapsed() < Duration::from_secs(5) {
if last_sync.elapsed() < Duration::from_secs(1) {
log::info!(target: target::UPDATES, "Skipping sync for conversation id: {}. Last sync was {} seconds ago.",
conversation.guid, last_sync.elapsed().as_secs_f64());
return;
@@ -85,7 +93,7 @@ impl UpdateMonitor {
match (&last_message, &conversation.last_message) {
(Some(message), Some(conversation_message)) => {
if message.id == conversation_message.guid {
log::info!(target: target::UPDATES, "Skipping sync for conversation id: {}. We already have this message.", conversation.guid);
log::info!(target: target::UPDATES, "Skipping sync for conversation id: {}. We already have this message.", &conversation.guid);
return;
}
}

View File

@@ -233,6 +233,10 @@ impl DbusRepository for DBusAgent {
self.send_event_sync(|r| Event::SyncConversation(conversation_id, r))
}
fn mark_conversation_as_read(&mut self, conversation_id: String) -> Result<(), MethodErr> {
self.send_event_sync(|r| Event::MarkConversationAsRead(conversation_id, r))
}
fn get_messages(&mut self, conversation_id: String, last_message_id: String) -> Result<Vec<arg::PropMap>, MethodErr> {
let last_message_id_opt = if last_message_id.is_empty() {
None