using GLib; using Gee; public class ConversationListModel : Object, ListModel { public SortedSet conversations { owned get { return _conversations.read_only_view; } } private SortedSet _conversations; private RepositoryService repository; private uint dbus_watch_id; public ConversationListModel() { _conversations = new TreeSet((a, b) => { // Sort by date in descending order (newest first) return (int)(b.date - a.date); }); connect_to_dbus.begin(); } ~ConversationListModel() { if (dbus_watch_id > 0) { Bus.unwatch_name(dbus_watch_id); } } private async void connect_to_dbus() { bool connected = false; const string path = "/net/buzzert/kordophonecd/daemon"; try { debug("Trying to connect to DBus service at path: %s", path); repository = yield Bus.get_proxy(BusType.SESSION, "net.buzzert.kordophonecd", path); // Test the connection repository.get_version(); // If we get here, connection succeeded debug("Connected to DBus service at path: %s", path); connected = true; // Listen for updates repository.conversations_updated.connect(load_conversations); // Initial load load_conversations(); } catch (Error e) { debug("Failed to connect to kordophonecd at %s: %s", path, e.message); } if (!connected) { warning("Failed to connect to kordophonecd on any known path"); // Watch for the service to appear dbus_watch_id = Bus.watch_name(BusType.SESSION, "net.buzzert.kordophonecd", BusNameWatcherFlags.AUTO_START, () => { connect_to_dbus.begin(); }, null); } } public void load_conversations() { if (repository == null) { return; } try { Variant conversations_variant = repository.get_conversations(); // Clear existing set uint old_count = _conversations.size; _conversations.clear(); // Notify of removal if (old_count > 0) { items_changed(0, old_count, 0); } // Process each conversation size_t n_children = conversations_variant.n_children(); uint position = 0; for (size_t i = 0; i < n_children; i++) { Variant child = conversations_variant.get_child_value(i); var conversation = new Conversation.from_variant(child); _conversations.add(conversation); position++; } // Notify of additions if (position > 0) { items_changed(0, 0, position); } } catch (Error e) { warning("Failed to load conversations: %s", e.message); } } // ListModel implementation public Type get_item_type() { return typeof(Conversation); } public uint get_n_items() { return _conversations.size; } public Object? get_item(uint position) { return _conversations.to_array()[position]; } }