From bcac03ef6a0f0ea1d3a0547f6bda05f42478c634 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Tue, 19 Mar 2024 11:13:44 +0300 Subject: [PATCH] Fetch MAM pages when scrolling in chats --- libdino/src/entity/conversation.vala | 6 +++++ libdino/src/service/content_item_store.vala | 6 ++--- libdino/src/service/history_sync.vala | 23 +++++++++++++++++-- libdino/src/service/muc_manager.vala | 2 +- .../conversation_view.vala | 22 +++++++++++++++++- 5 files changed, 51 insertions(+), 8 deletions(-) diff --git a/libdino/src/entity/conversation.vala b/libdino/src/entity/conversation.vala index 353daeae..2510f1c7 100644 --- a/libdino/src/entity/conversation.vala +++ b/libdino/src/entity/conversation.vala @@ -2,6 +2,8 @@ using Xmpp; namespace Dino.Entities { +const int HISTORY_SYNC_MAM_PAGES = 10; + public class Conversation : Object { public signal void object_updated(Conversation conversation); @@ -16,6 +18,10 @@ public class Conversation : Object { } } + public int syncSpeed() { + return HISTORY_SYNC_MAM_PAGES; + } + public int id { get; set; } public Type type_ { get; set; } public Account account { get; private set; } diff --git a/libdino/src/service/content_item_store.vala b/libdino/src/service/content_item_store.vala index de050633..e1f3d16b 100644 --- a/libdino/src/service/content_item_store.vala +++ b/libdino/src/service/content_item_store.vala @@ -6,8 +6,6 @@ using Xmpp; namespace Dino { -const int HISTORY_SYNC_MAM_PAGES = 10; - public class ContentItemStore : StreamInteractionModule, Object { public static ModuleIdentity IDENTITY = new ModuleIdentity("content_item_store"); public string id { get { return IDENTITY.id; } } @@ -260,8 +258,8 @@ public class ContentItemStore : StreamInteractionModule, Object { if (items.size == 0 && request_from_server) { // Async request to get earlier messages from the server var history_sync = stream_interactor.get_module(MessageProcessor.IDENTITY).history_sync; - history_sync.fetch_data.begin(conversation.account, conversation.counterpart.bare_jid, item.time, HISTORY_SYNC_MAM_PAGES, (_, res) => { - history_sync.fetch_data.end(res); + history_sync.fetch_conversation_data.begin(conversation, item.time, (_, res) => { + history_sync.fetch_conversation_data.end(res); debug("History loaded"); history_loaded(conversation, item, count); }); diff --git a/libdino/src/service/history_sync.vala b/libdino/src/service/history_sync.vala index 170d97a2..d8604a6e 100644 --- a/libdino/src/service/history_sync.vala +++ b/libdino/src/service/history_sync.vala @@ -143,11 +143,30 @@ public class Dino.HistorySync { return page_result; } - public async void fetch_data(Account account, Jid target, DateTime latest, int pages) { + public async void fetch_data(Account account, Jid target, DateTime latest) { debug("Fetch history for %s", target.to_string()); var query_params = new Xmpp.MessageArchiveManagement.V2.MamQueryParams.query_before(target, latest, null); - yield fetch_pages(account, query_params, pages); + yield fetch_pages(account, query_params, HISTORY_SYNC_MAM_PAGES); + } + + public async void fetch_conversation_data(Conversation? conversation, DateTime latest) { + if (conversation == null) { + warning("Failed to fetch history, conversation is null"); + return; + } + + var target = conversation.counterpart.bare_jid; + var account = conversation.account; + debug("Fetch history for %s", target.to_string()); + + var query_params = new Xmpp.MessageArchiveManagement.V2.MamQueryParams.query_before(target, latest, null); + if (conversation.type_ == Conversation.Type.CHAT) { + query_params.mam_server = account.bare_jid; + query_params.with = target; + } + + yield fetch_pages(account, query_params, conversation.syncSpeed()); } public async void fetch_history(Account account, Jid target, Cancellable? cancellable = null) { diff --git a/libdino/src/service/muc_manager.vala b/libdino/src/service/muc_manager.vala index edfa661e..c849035a 100644 --- a/libdino/src/service/muc_manager.vala +++ b/libdino/src/service/muc_manager.vala @@ -107,7 +107,7 @@ public class MucManager : StreamInteractionModule, Object { var history_sync = stream_interactor.get_module(MessageProcessor.IDENTITY).history_sync; if (conversation == null) { // We never joined the conversation before, fetch latest MAM pages - yield history_sync.fetch_data(account, jid.bare_jid, new DateTime.now(), 10); + yield history_sync.fetch_data(account, jid.bare_jid, new DateTime.now()); } else { // Fetch everything up to the last time the user actively joined if (!mucs_sync_cancellables.has_key(account)) { diff --git a/main/src/ui/conversation_content_view/conversation_view.vala b/main/src/ui/conversation_content_view/conversation_view.vala index 3b502b59..ed8697eb 100644 --- a/main/src/ui/conversation_content_view/conversation_view.vala +++ b/main/src/ui/conversation_content_view/conversation_view.vala @@ -564,11 +564,31 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug private void load_earlier_messages(bool request_from_server = true) { was_value = scrolled.vadjustment.value; debug("loading earlier messages"); + if (!reloading_mutex.trylock()) { return; } - if (content_items.size > 0) { + if (content_items.size == 0) { + // List is empty, try load local data + Gee.List items = content_populator.populate_latest(conversation, 20); + debug("inserting new messages, size: %d", items.size); + foreach (ContentMetaItem item in items) { + do_insert_item(item); + } + + if (request_from_server) { + // If the list is empty also try to load data from the server + var history_sync = stream_interactor.get_module(MessageProcessor.IDENTITY).history_sync; + history_sync.fetch_conversation_data.begin(conversation, new DateTime.now(), (_, res) => { + history_sync.fetch_conversation_data.end(res); + + // Request finished, reload messages + load_earlier_messages(false); + }); + } + } else if (content_items.size > 0) { + // List is not empty, fetch data before the latest available message Gee.List items = content_populator.populate_before(conversation, ((ContentMetaItem) content_items.first()).content_item, 20, request_from_server); debug("inserting new messages, size: %d", items.size); foreach (ContentMetaItem item in items) {