diff options
| author | frosty <gabriel@bwaaa.monster> | 2026-08-26 15:55:22 -0400 |
|---|---|---|
| committer | frosty <gabriel@bwaaa.monster> | 2026-08-26 15:55:22 -0400 |
| commit | c61e889f209fd07cbff94147df38609de13e3766 (patch) | |
| tree | 0ebc5beb48bacdaab1362f3926a0a1f4081ff8b5 /main/src/ui | |
| parent | 2ba1fe874070fc372c1a522c5c5b97173fbe1459 (diff) | |
feat: add launcher badge
Diffstat (limited to 'main/src/ui')
| -rw-r--r-- | main/src/ui/application.vala | 11 | ||||
| -rw-r--r-- | main/src/ui/launcher_badge.vala | 118 |
2 files changed, 129 insertions, 0 deletions
diff --git a/main/src/ui/application.vala b/main/src/ui/application.vala index 9ac512d9..b72a8d0e 100644 --- a/main/src/ui/application.vala +++ b/main/src/ui/application.vala @@ -14,6 +14,7 @@ public class Dino.Ui.Application : Adw.Application, Dino.Application { public MainWindow window; public MainWindowController controller; + private LauncherBadge? launcher_badge; private StatusNotifierItem? status_notifier_item; public Database db { get; set; } @@ -50,6 +51,12 @@ public class Dino.Ui.Application : Adw.Application, Dino.Application { warning("Could not create Dino's tray icon: %s", e.message); } + try { + launcher_badge = new LauncherBadge(stream_interactor); + } catch (IOError e) { + warning("Could not create Dino's launcher badge: %s", e.message); + } + NotificationEvents notification_events = stream_interactor.get_module(NotificationEvents.IDENTITY); get_notifications_dbus.begin((_, res) => { // It might take a bit to get the interface. NotificationEvents will queue any notifications in the meantime. @@ -76,6 +83,10 @@ public class Dino.Ui.Application : Adw.Application, Dino.Application { }); shutdown.connect(() => { + if (launcher_badge != null) { + launcher_badge.shutdown(); + launcher_badge = null; + } if (status_notifier_item != null) { status_notifier_item.shutdown(); status_notifier_item = null; diff --git a/main/src/ui/launcher_badge.vala b/main/src/ui/launcher_badge.vala new file mode 100644 index 00000000..aa07fbaa --- /dev/null +++ b/main/src/ui/launcher_badge.vala @@ -0,0 +1,118 @@ +using Gee; +using GLib; + +using Dino.Entities; + +namespace Dino.Ui { + +[DBus (name = "com.canonical.Unity.LauncherEntry")] +public class LauncherBadge : Object { + private const string APP_URI = "application://im.dino.Dino.desktop"; + private const string BUS_NAME = "com.canonical.Unity"; + private const string OBJECT_PATH = "/im/dino/Dino/LauncherEntry"; + + private StreamInteractor stream_interactor; + private DBusConnection connection; + private HashMap<Conversation, ulong> read_handler_ids = new HashMap<Conversation, ulong>(Conversation.hash_func, Conversation.equals_func); + private int64 unread_count = -1; + private uint object_registration_id; + private uint watcher_id; + private ulong conversation_activated_handler_id; + private ulong conversation_deactivated_handler_id; + private ulong new_item_handler_id; + private ulong setting_handler_id; + + public signal void update(string app_uri, HashTable<string, Variant> properties); + + public LauncherBadge(StreamInteractor stream_interactor) throws IOError { + this.stream_interactor = stream_interactor; + connection = Bus.get_sync(BusType.SESSION); + object_registration_id = connection.register_object(OBJECT_PATH, this); + + ConversationManager conversation_manager = stream_interactor.get_module(ConversationManager.IDENTITY); + conversation_activated_handler_id = conversation_manager.conversation_activated.connect(add_conversation); + conversation_deactivated_handler_id = conversation_manager.conversation_deactivated.connect(remove_conversation); + new_item_handler_id = stream_interactor.get_module(ContentItemStore.IDENTITY).new_item.connect(() => update_count()); + setting_handler_id = Dino.Application.get_default().settings.notify["notifications-badge"].connect(() => update_count(true)); + + foreach (Conversation conversation in conversation_manager.get_active_conversations()) { + connect_conversation(conversation); + } + + watcher_id = Bus.watch_name_on_connection( + connection, + BUS_NAME, + BusNameWatcherFlags.NONE, + () => update_count(true)); + update_count(true); + } + + public void query(out string app_uri, out HashTable<string, Variant> properties) throws Error { + app_uri = APP_URI; + properties = get_properties(); + } + + internal void shutdown() { + unread_count = 0; + update(APP_URI, get_properties()); + + ConversationManager conversation_manager = stream_interactor.get_module(ConversationManager.IDENTITY); + conversation_manager.disconnect(conversation_activated_handler_id); + conversation_manager.disconnect(conversation_deactivated_handler_id); + stream_interactor.get_module(ContentItemStore.IDENTITY).disconnect(new_item_handler_id); + Dino.Application.get_default().settings.disconnect(setting_handler_id); + + foreach (Conversation conversation in read_handler_ids.keys) { + conversation.disconnect(read_handler_ids[conversation]); + } + read_handler_ids.clear(); + + if (watcher_id != 0) { + Bus.unwatch_name(watcher_id); + watcher_id = 0; + } + if (object_registration_id != 0) { + connection.unregister_object(object_registration_id); + object_registration_id = 0; + } + } + + private void add_conversation(Conversation conversation) { + connect_conversation(conversation); + update_count(); + } + + private void remove_conversation(Conversation conversation) { + if (read_handler_ids.has_key(conversation)) { + conversation.disconnect(read_handler_ids[conversation]); + read_handler_ids.unset(conversation); + } + update_count(); + } + + private void connect_conversation(Conversation conversation) { + if (read_handler_ids.has_key(conversation)) return; + read_handler_ids[conversation] = conversation.notify["read-up-to-item"].connect(() => update_count()); + } + + private void update_count(bool force = false) { + int64 count = 0; + ChatInteraction chat_interaction = stream_interactor.get_module(ChatInteraction.IDENTITY); + foreach (Conversation conversation in stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations()) { + count += chat_interaction.get_num_unread(conversation); + } + + if (!force && count == unread_count) return; + unread_count = count; + update(APP_URI, get_properties()); + } + + private HashTable<string, Variant> get_properties() { + HashTable<string, Variant> properties = new HashTable<string, Variant>(str_hash, str_equal); + properties["count"] = new Variant.int64(unread_count); + properties["count-visible"] = new Variant.boolean(Dino.Application.get_default().settings.notifications_badge && unread_count > 0); + return properties; + } +} + +} |
