From fa357527fe43e06fea97b1b608cc514e44c221b9 Mon Sep 17 00:00:00 2001 From: Konstantin Kuznetsov Date: Tue, 12 Mar 2024 11:30:39 +0300 Subject: [PATCH] Add button to fetch MAM history for conversation --- libdino/src/service/history_sync.vala | 25 +++++++++ main/CMakeLists.txt | 1 + main/meson.build | 1 + .../ui/contact_details/history_provider.vala | 52 +++++++++++++++++++ main/src/ui/conversation_details.vala | 1 + 5 files changed, 80 insertions(+) create mode 100644 main/src/ui/contact_details/history_provider.vala diff --git a/libdino/src/service/history_sync.vala b/libdino/src/service/history_sync.vala index 8ab6d7bb..eb24c7e2 100644 --- a/libdino/src/service/history_sync.vala +++ b/libdino/src/service/history_sync.vala @@ -120,6 +120,31 @@ public class Dino.HistorySync { } } + public async void fetch_history(Account account, Jid target, Cancellable? cancellable = null) { + debug("Fetch history for %s", target.to_string()); + + RowOption latest_row_opt = db.mam_catchup.select() + .with(db.mam_catchup.account_id, "=", account.id) + .with(db.mam_catchup.server_jid, "=", target.to_string()) + .with(db.mam_catchup.to_time, ">=", (long) new DateTime.from_unix_utc(0).to_unix()) + .order_by(db.mam_catchup.to_time, "DESC") + .single().row(); + Row? latest_row = latest_row_opt.is_present() ? latest_row_opt.inner : null; + + if (latest_row == null) { + warning("Failed to fetch history for %s, no mam catchup data", target.to_string()); + return; + } + + DateTime latest_time = new DateTime.now(); + string latest_id = latest_row[db.mam_catchup.from_id]; + + Xmpp.MessageArchiveManagement.V2.MamQueryParams query_params; + query_params = new Xmpp.MessageArchiveManagement.V2.MamQueryParams.query_before(target, latest_time, latest_id); + + yield fetch_query(account, query_params, latest_row[db.mam_catchup.id], cancellable); + } + public async void fetch_everything(Account account, Jid mam_server, Cancellable? cancellable = null, DateTime until_earliest_time = new DateTime.from_unix_utc(0)) { debug("Fetch everything for %s %s", mam_server.to_string(), until_earliest_time != null ? @"(until $until_earliest_time)" : ""); RowOption latest_row_opt = db.mam_catchup.select() diff --git a/main/CMakeLists.txt b/main/CMakeLists.txt index 8e4e811c..b27944d0 100644 --- a/main/CMakeLists.txt +++ b/main/CMakeLists.txt @@ -203,6 +203,7 @@ SOURCES src/ui/contact_details/settings_provider.vala src/ui/contact_details/permissions_provider.vala + src/ui/contact_details/history_provider.vala src/ui/conversation_details.vala diff --git a/main/meson.build b/main/meson.build index 1b5abcfc..e9b37878 100644 --- a/main/meson.build +++ b/main/meson.build @@ -39,6 +39,7 @@ sources = files( 'src/ui/chat_input/view.vala', 'src/ui/contact_details/permissions_provider.vala', 'src/ui/contact_details/settings_provider.vala', + 'src/ui/contact_details/history_provider.vala', 'src/ui/conversation_content_view/call_widget.vala', 'src/ui/conversation_content_view/chat_state_populator.vala', 'src/ui/conversation_content_view/content_populator.vala', diff --git a/main/src/ui/contact_details/history_provider.vala b/main/src/ui/contact_details/history_provider.vala new file mode 100644 index 00000000..558ce3fd --- /dev/null +++ b/main/src/ui/contact_details/history_provider.vala @@ -0,0 +1,52 @@ +using Gee; +using Gtk; + +using Dino.Entities; + +using Xmpp; + +namespace Dino.Ui.ContactDetails { + +public class HistoryProvider : Plugins.ContactDetailsProvider, Object { + public string id { get { return "history_settings"; } } + + private StreamInteractor stream_interactor; + + private HashMap> sync_cancellables = new HashMap>(Account.hash_func, Account.equals_func); + + public HistoryProvider(StreamInteractor stream_interactor) { + this.stream_interactor = stream_interactor; + } + + public void populate(Conversation conversation, Plugins.ContactDetails contact_details, Plugins.WidgetType type) { + if (type != Plugins.WidgetType.GTK4) return; + + EntityInfo entity_info = stream_interactor.get_module(EntityInfo.IDENTITY); + + string RESYNC_LABEL = _("Resync"); + string RESYNC_DESC_LABEL = _("Fetch a complete MAM history for this chat"); + entity_info.has_feature.begin(conversation.account, conversation.counterpart, Xmpp.MessageArchiveManagement.NS_URI, (_, res) => { + bool can_do_mam = entity_info.has_feature.end(res); + if (can_do_mam) { + Button resync_button = new Button.with_label(RESYNC_LABEL); + contact_details.add("Permissions", RESYNC_DESC_LABEL, "", resync_button); + resync_button.clicked.connect(() => { + if (!sync_cancellables.has_key(conversation.account)) { + sync_cancellables[conversation.account] = new HashMap(); + } + + if (!sync_cancellables[conversation.account].has_key(conversation.counterpart.bare_jid)) { + sync_cancellables[conversation.account][conversation.counterpart.bare_jid] = new Cancellable(); + var history_sync = stream_interactor.get_module(MessageProcessor.IDENTITY).history_sync; + history_sync.fetch_history.begin(conversation.account, conversation.counterpart.bare_jid, sync_cancellables[conversation.account][conversation.counterpart.bare_jid], (_, res) => { + history_sync.fetch_everything.end(res); + sync_cancellables[conversation.account].unset(conversation.counterpart.bare_jid); + }); + } + }); + } + }); + } +} + +} \ No newline at end of file diff --git a/main/src/ui/conversation_details.vala b/main/src/ui/conversation_details.vala index 82d6ae54..a7942d4f 100644 --- a/main/src/ui/conversation_details.vala +++ b/main/src/ui/conversation_details.vala @@ -152,6 +152,7 @@ namespace Dino.Ui.ConversationDetails { Application app = GLib.Application.get_default() as Application; app.plugin_registry.register_contact_details_entry(new ContactDetails.SettingsProvider(stream_interactor)); app.plugin_registry.register_contact_details_entry(new ContactDetails.PermissionsProvider(stream_interactor)); + app.plugin_registry.register_contact_details_entry(new ContactDetails.HistoryProvider(stream_interactor)); foreach (Plugins.ContactDetailsProvider provider in app.plugin_registry.contact_details_entries) { provider.populate(conversation, contact_details, Plugins.WidgetType.GTK4);