From 7e01ca1ce5e85d0e0bbe704bef7bbd7bcb7aab5a Mon Sep 17 00:00:00 2001 From: Marco Betschart Date: Wed, 13 Oct 2021 07:18:40 +0000 Subject: [PATCH 1/4] Live update badges for account folders --- src/FoldersView/AccountSourceItem.vala | 61 +++++++++++++++++++++++++- src/FoldersView/FolderSourceItem.vala | 2 + 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/FoldersView/AccountSourceItem.vala b/src/FoldersView/AccountSourceItem.vala index 4e3eb90bc..5519c70b2 100644 --- a/src/FoldersView/AccountSourceItem.vala +++ b/src/FoldersView/AccountSourceItem.vala @@ -27,6 +27,7 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem private GLib.Cancellable connect_cancellable; private Gee.HashMap folder_items; + private Gee.HashMap folders; private AccountSavedState saved_state; private unowned Camel.OfflineStore offlinestore; @@ -38,6 +39,7 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem visible = true; connect_cancellable = new GLib.Cancellable (); folder_items = new Gee.HashMap (); + folders = new Gee.HashMap (); saved_state = new AccountSavedState (account); saved_state.bind_with_expandable_item (this); @@ -61,7 +63,7 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem try { var folderinfo = yield offlinestore.get_folder_info (null, Camel.StoreGetFolderInfoFlags.RECURSIVE, GLib.Priority.DEFAULT, connect_cancellable); if (folderinfo != null) { - show_info (folderinfo, this); + folder_created (folderinfo); } } catch (Error e) { @@ -90,6 +92,17 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem private void folder_renamed (string old_name, Camel.FolderInfo folder_info) { var item = folder_items[old_name]; item.update_infos (folder_info); + + lock (folders) { + if (folders.has_key (old_name)) { + Camel.Folder folder; + if (folders.unset (old_name, out folder)) { + folders.set (folder_info.full_name, folder); + + folder.refresh_info.begin (GLib.Priority.DEFAULT, null); + } + } + } } private void folder_deleted (Camel.FolderInfo folder_info) { @@ -97,12 +110,18 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem if (item != null) { item.parent.remove (item); folder_items.unset (folder_info.full_name); + + lock (folders) { + folders.unset (folder_info.full_name); + } } } private void folder_created (Camel.FolderInfo folder_info) { if (folder_info.parent == null) { show_info (folder_info, this); + connect_folder_changed (folder_info); + } else { unowned Camel.FolderInfo parent_info = (Camel.FolderInfo) folder_info.parent; var parent_item = folder_items[parent_info.full_name]; @@ -112,10 +131,50 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem folder_created (folder_info); } else { show_info (folder_info, parent_item); + connect_folder_changed (folder_info); } } } + private void connect_folder_changed (Camel.FolderInfo folder_info) { + if (account.service is Camel.Store) { + var store = (Camel.Store) account.service; + store.get_folder.begin (folder_info.full_name, Camel.StoreGetFolderFlags.NONE, GLib.Priority.DEFAULT, null, (obj, res) => { + try { + var folder = store.get_folder.end (res); + folder.changed.connect ((changes) => { + folder_changed (folder, changes); + }); + + lock (folders) { + folders.set (folder_info.full_name, folder); + } + + } catch (Error e) { + warning ("Error retrieving folder '%s' from store: %s", folder_info.full_name, e.message); + } + }); + } + } + + private void folder_changed (Camel.Folder folder, Camel.FolderChangeInfo changes) { + Mail.FolderSourceItem? item = folder_items[folder.full_name]; + + if (item != null && account.service is Camel.Store) { + var store = (Camel.Store) account.service; + + store.get_folder_info.begin (folder.full_name, Camel.StoreGetFolderInfoFlags.REFRESH, GLib.Priority.DEFAULT, null, (obj, res) => { + try { + var folder_info = store.get_folder_info.end (res); + item.update_infos (folder_info); + + } catch (Error e) { + warning ("Error refreshing folder info for '%s': %s", folder.full_name, e.message); + } + }); + } + } + private async void reload_folders () { var offlinestore = (Camel.OfflineStore) account.service; foreach (var folder_item in folder_items.values) { diff --git a/src/FoldersView/FolderSourceItem.vala b/src/FoldersView/FolderSourceItem.vala index 12fcbe376..0ef96d1fa 100644 --- a/src/FoldersView/FolderSourceItem.vala +++ b/src/FoldersView/FolderSourceItem.vala @@ -46,6 +46,8 @@ public class Mail.FolderSourceItem : Granite.Widgets.SourceList.ExpandableItem { public void update_infos (Camel.FolderInfo folderinfo) { name = folderinfo.display_name; full_name = folderinfo.full_name; + + badge = ""; if (folderinfo.unread > 0) { badge = "%d".printf (folderinfo.unread); } From 189656f6465c8dce026c97bf82576513798c7ee0 Mon Sep 17 00:00:00 2001 From: Marco Betschart Date: Wed, 13 Oct 2021 07:34:19 +0000 Subject: [PATCH 2/4] Use offlinestore instance variable --- src/FoldersView/AccountSourceItem.vala | 29 ++++++++++++-------------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/src/FoldersView/AccountSourceItem.vala b/src/FoldersView/AccountSourceItem.vala index 5519c70b2..88e3b84ac 100644 --- a/src/FoldersView/AccountSourceItem.vala +++ b/src/FoldersView/AccountSourceItem.vala @@ -137,24 +137,21 @@ public class Mail.AccountSourceItem : Granite.Widgets.SourceList.ExpandableItem } private void connect_folder_changed (Camel.FolderInfo folder_info) { - if (account.service is Camel.Store) { - var store = (Camel.Store) account.service; - store.get_folder.begin (folder_info.full_name, Camel.StoreGetFolderFlags.NONE, GLib.Priority.DEFAULT, null, (obj, res) => { - try { - var folder = store.get_folder.end (res); - folder.changed.connect ((changes) => { - folder_changed (folder, changes); - }); - - lock (folders) { - folders.set (folder_info.full_name, folder); - } + offlinestore.get_folder.begin (folder_info.full_name, Camel.StoreGetFolderFlags.NONE, GLib.Priority.DEFAULT, null, (obj, res) => { + try { + var folder = offlinestore.get_folder.end (res); + folder.changed.connect ((changes) => { + folder_changed (folder, changes); + }); - } catch (Error e) { - warning ("Error retrieving folder '%s' from store: %s", folder_info.full_name, e.message); + lock (folders) { + folders.set (folder_info.full_name, folder); } - }); - } + + } catch (Error e) { + warning ("Error retrieving folder '%s' from store: %s", folder_info.full_name, e.message); + } + }); } private void folder_changed (Camel.Folder folder, Camel.FolderChangeInfo changes) { From 37f0931818a376d436aa332f2992a728e46ca6d9 Mon Sep 17 00:00:00 2001 From: Marco Betschart Date: Wed, 13 Oct 2021 07:34:31 +0000 Subject: [PATCH 3/4] Show badge only for INBOX --- src/FoldersView/FolderSourceItem.vala | 5 +++-- src/FoldersView/GroupedFolderSourceItem.vala | 23 +++++++++++--------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/src/FoldersView/FolderSourceItem.vala b/src/FoldersView/FolderSourceItem.vala index 0ef96d1fa..38eeb5e64 100644 --- a/src/FoldersView/FolderSourceItem.vala +++ b/src/FoldersView/FolderSourceItem.vala @@ -65,7 +65,7 @@ public class Mail.FolderSourceItem : Granite.Widgets.SourceList.ExpandableItem { case Camel.FolderInfoFlags.TYPE_TRASH: icon = new ThemedIcon (folderinfo.total == 0 ? "user-trash" : "user-trash-full"); can_modify = false; - badge = null; + badge = ""; break; case Camel.FolderInfoFlags.TYPE_JUNK: icon = new ThemedIcon ("edit-flag"); @@ -74,11 +74,12 @@ public class Mail.FolderSourceItem : Granite.Widgets.SourceList.ExpandableItem { case Camel.FolderInfoFlags.TYPE_SENT: icon = new ThemedIcon ("mail-sent"); can_modify = false; + badge = ""; break; case Camel.FolderInfoFlags.TYPE_ARCHIVE: icon = new ThemedIcon ("mail-archive"); can_modify = false; - badge = null; + badge = ""; break; case Camel.FolderInfoFlags.TYPE_DRAFTS: icon = new ThemedIcon ("mail-drafts"); diff --git a/src/FoldersView/GroupedFolderSourceItem.vala b/src/FoldersView/GroupedFolderSourceItem.vala index c97f28dc7..89fa6b2df 100644 --- a/src/FoldersView/GroupedFolderSourceItem.vala +++ b/src/FoldersView/GroupedFolderSourceItem.vala @@ -123,18 +123,21 @@ public class Mail.GroupedFolderSourceItem : Granite.Widgets.SourceList.Item { } private void update_infos () { - badge = null; - var total_unread = 0; - lock (account_folderinfo) { - foreach (var entry in account_folderinfo) { - if (entry.value == null) { - continue; + badge = ""; + + if (Camel.FolderInfoFlags.TYPE_INBOX == (folder_type & Camel.FOLDER_TYPE_MASK)) { + var total_unread = 0; + lock (account_folderinfo) { + foreach (var entry in account_folderinfo) { + if (entry.value == null) { + continue; + } + total_unread += entry.value.unread; } - total_unread += entry.value.unread; } - } - if (total_unread > 0) { - badge = "%d".printf (total_unread); + if (total_unread > 0) { + badge = "%d".printf (total_unread); + } } } From f6a673fa4f13e5633710387812b972b92432718d Mon Sep 17 00:00:00 2001 From: Marco Betschart Date: Wed, 13 Oct 2021 07:44:28 +0000 Subject: [PATCH 4/4] Update unread count in grouped inbox --- src/FoldersView/GroupedFolderSourceItem.vala | 39 ++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/FoldersView/GroupedFolderSourceItem.vala b/src/FoldersView/GroupedFolderSourceItem.vala index 89fa6b2df..44161519f 100644 --- a/src/FoldersView/GroupedFolderSourceItem.vala +++ b/src/FoldersView/GroupedFolderSourceItem.vala @@ -23,6 +23,7 @@ public class Mail.GroupedFolderSourceItem : Granite.Widgets.SourceList.Item { private GLib.Cancellable connect_cancellable; private Gee.HashMap account_folderinfo; + private Gee.HashMap account_folders; public GroupedFolderSourceItem (Mail.Backend.Session session, Camel.FolderInfoFlags folder_type) { Object (session: session, folder_type: folder_type); @@ -32,6 +33,7 @@ public class Mail.GroupedFolderSourceItem : Granite.Widgets.SourceList.Item { visible = true; connect_cancellable = new GLib.Cancellable (); account_folderinfo = new Gee.HashMap (); + account_folders = new Gee.HashMap (); switch (folder_type & Camel.FOLDER_TYPE_MASK) { case Camel.FolderInfoFlags.TYPE_INBOX: @@ -90,7 +92,9 @@ public class Mail.GroupedFolderSourceItem : Granite.Widgets.SourceList.Item { private async void load_folder_info (Mail.Backend.Account account) { var offlinestore = (Camel.OfflineStore) account.service; var full_name = build_folder_full_name (account); + Camel.FolderInfo? folderinfo = null; + Camel.Folder? folder = null; if (full_name != null) { try { @@ -102,11 +106,26 @@ public class Mail.GroupedFolderSourceItem : Granite.Widgets.SourceList.Item { warning ("Unable to fetch %s of account '%s': %s", full_name, account.service.display_name, e.message); } } + + try { + folder = yield offlinestore.get_folder (full_name, Camel.StoreGetFolderFlags.NONE, GLib.Priority.DEFAULT, connect_cancellable); + + folder.changed.connect ((changes) => { + account_folder_changed (account, folder, changes); + }); + + } catch (Error e) { + warning ("Error retrieving folder '%s' from store: %s", full_name, e.message); + } } lock (account_folderinfo) { account_folderinfo.set (account, folderinfo); } + + lock (account_folders) { + account_folders.set (account, folder); + } update_infos (); } @@ -122,6 +141,26 @@ public class Mail.GroupedFolderSourceItem : Granite.Widgets.SourceList.Item { } } + private void account_folder_changed (Mail.Backend.Account account, Camel.Folder folder, Camel.FolderChangeInfo changes) { + if (account.service is Camel.Store) { + var store = (Camel.Store) account.service; + + store.get_folder_info.begin (folder.full_name, Camel.StoreGetFolderInfoFlags.REFRESH, GLib.Priority.DEFAULT, null, (obj, res) => { + try { + var folder_info = store.get_folder_info.end (res); + lock (account_folderinfo) { + account_folderinfo.set (account, folder_info); + } + + update_infos (); + + } catch (Error e) { + warning ("Error refreshing folder info for '%s': %s", folder.full_name, e.message); + } + }); + } + } + private void update_infos () { badge = "";