Private
Public Access
1
0

~buzzert/Kordophone#9: gtk v2: Conversation selected state lost when reloading

This commit is contained in:
2025-05-02 15:51:43 -07:00
parent 410182eab8
commit ef0312ccbd
3 changed files with 137 additions and 19 deletions

View File

@@ -21,29 +21,90 @@ public class ConversationListModel : Object, ListModel
public void load_conversations() { public void load_conversations() {
try { try {
Conversation[] conversations = Repository.get_instance().get_conversations(); Conversation[] new_conversations = Repository.get_instance().get_conversations();
// Clear existing set // Create a map of old conversations for quick lookup
uint old_count = _conversations.size; var old_conversations_map = new HashMap<string, Conversation>();
_conversations.clear(); foreach (var conv in _conversations) {
old_conversations_map[conv.guid] = conv;
// Notify of removal
if (old_count > 0) {
items_changed(0, old_count, 0);
} }
// Process each conversation // Create a map of new conversations for quick lookup
uint position = 0; var new_conversations_map = new HashMap<string, Conversation>();
foreach (var conv in new_conversations) {
for (int i = 0; i < conversations.length; i++) { new_conversations_map[conv.guid] = conv;
var conversation = conversations[i];
_conversations.add(conversation);
position++;
} }
// Notify of additions // Find removed conversations
if (position > 0) { var removed_positions = new ArrayList<uint>();
items_changed(0, 0, position); 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<Conversation>();
var changed_conversations = new ArrayList<Conversation>();
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) { } catch (Error e) {
warning("Failed to load conversations: %s", e.message); warning("Failed to load conversations: %s", e.message);

View File

@@ -11,6 +11,9 @@ public class ConversationListView : Adw.Bin
private Adw.HeaderBar header_bar; private Adw.HeaderBar header_bar;
private ConversationListModel conversation_model; private ConversationListModel conversation_model;
private string? selected_conversation_guid = null;
private bool selection_update_queued = false;
public ConversationListView () { public ConversationListView () {
container = new Adw.ToolbarView (); container = new Adw.ToolbarView ();
set_child (container); set_child (container);
@@ -25,7 +28,10 @@ public class ConversationListView : Adw.Bin
list_box.row_selected.connect ((row) => { list_box.row_selected.connect ((row) => {
var conversation_row = (ConversationRow?) row; var conversation_row = (ConversationRow?) row;
conversation_selected(conversation_row != null ? conversation_row.conversation.guid : null); if (conversation_row != null) {
selected_conversation_guid = conversation_row.conversation.guid;
conversation_selected(selected_conversation_guid);
}
}); });
header_bar = new Adw.HeaderBar (); header_bar = new Adw.HeaderBar ();
@@ -44,9 +50,43 @@ public class ConversationListView : Adw.Bin
// Set up model and bind to list // Set up model and bind to list
conversation_model = new ConversationListModel (); conversation_model = new ConversationListModel ();
conversation_model.items_changed.connect (on_items_changed);
list_box.bind_model (conversation_model, create_conversation_row); list_box.bind_model (conversation_model, create_conversation_row);
} }
private void on_items_changed (uint position, uint removed, uint added) {
enqueue_selection_update();
}
private void enqueue_selection_update() {
if (selection_update_queued) {
return;
}
selection_update_queued = true;
GLib.Idle.add(() => {
update_selection();
selection_update_queued = false;
return false;
}, GLib.Priority.HIGH);
}
private void update_selection() {
// Re-select selected_conversation_guid, if it has changed.
if (selected_conversation_guid != null) {
for (uint i = 0; i < conversation_model.get_n_items(); i++) {
var conversation = (Conversation) conversation_model.get_item(i);
if (conversation.guid == selected_conversation_guid) {
var row = list_box.get_row_at_index((int)i);
if (row != null) {
list_box.select_row(row);
}
}
}
}
}
private Widget create_conversation_row (Object item) { private Widget create_conversation_row (Object item) {
Conversation conversation = (Conversation) item; Conversation conversation = (Conversation) item;
return new ConversationRow (conversation); return new ConversationRow (conversation);

View File

@@ -52,4 +52,21 @@ public class Conversation : Object {
_display_name = conversation_data["display_name"].get_string(); _display_name = conversation_data["display_name"].get_string();
} }
} }
public bool equals(Conversation other) {
if (other == null) return false;
if (guid != other.guid) return false;
if (date != other.date) return false;
if (unread_count != other.unread_count) return false;
if (last_message_preview != other.last_message_preview) return false;
if (_display_name != other._display_name) return false;
// Compare participants arrays
if (participants.length != other.participants.length) return false;
for (int i = 0; i < participants.length; i++) {
if (participants[i] != other.participants[i]) return false;
}
return true;
}
} }