using GLib; using Gee; public class ConversationListModel : Object, ListModel { public SortedSet conversations { owned get { return _conversations.read_only_view; } } private SortedSet _conversations; public ConversationListModel() { _conversations = new TreeSet((a, b) => { // Sort by date in descending order (newest first) return (int)(b.date - a.date); }); Repository.get_instance().conversations_updated.connect(load_conversations); Repository.get_instance().messages_updated.connect(load_conversations); } public void load_conversations() { try { Conversation[] new_conversations = Repository.get_instance().get_conversations(); // Create a map of old conversations for quick lookup var old_conversations_map = new HashMap(); foreach (var conv in _conversations) { old_conversations_map[conv.guid] = conv; } // Create a map of new conversations for quick lookup var new_conversations_map = new HashMap(); foreach (var conv in new_conversations) { new_conversations_map[conv.guid] = conv; } // Find removed conversations var removed_positions = new ArrayList(); var current_position = 0; foreach (var old_conv in _conversations) { if (!new_conversations_map.has_key(old_conv.guid)) { removed_positions.add(current_position); } current_position++; } // Remove conversations in reverse order to maintain correct positions for (int i = removed_positions.size - 1; i >= 0; i--) { var pos = removed_positions[i]; _conversations.remove(_conversations.to_array()[pos]); items_changed(pos, 1, 0); } // Find added conversations and changed conversations var added_conversations = new ArrayList(); var changed_conversations = new ArrayList(); foreach (var new_conv in new_conversations) { if (!old_conversations_map.has_key(new_conv.guid)) { added_conversations.add(new_conv); } else { var old_conv = old_conversations_map[new_conv.guid]; if (!old_conv.equals(new_conv)) { changed_conversations.add(new_conv); } } } // Add new conversations foreach (var conv in added_conversations) { _conversations.add(conv); // Find the position by counting how many items are before this one uint pos = 0; foreach (var existing_conv in _conversations) { if (existing_conv.guid == conv.guid) break; pos++; } items_changed(pos, 0, 1); } // Update changed conversations GLib.message("Changed conversations: %d", changed_conversations.size); foreach (var conv in changed_conversations) { // Find position of old conversation uint old_pos = 0; var old_conv = old_conversations_map[conv.guid]; foreach (var existing_conv in _conversations) { if (existing_conv.guid == old_conv.guid) break; old_pos++; } // Remove the old one _conversations.remove(old_conv); // Add the new one _conversations.add(conv); // Find the new (sorted) position uint new_pos = 0; foreach (var existing_conv in _conversations) { if (existing_conv.guid == conv.guid) break; new_pos++; } // Notify of the change items_changed(old_pos, 1, 0); items_changed(new_pos, 0, 1); } } 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]; } }