[geary/wip/730682-refine-convo-list: 9/12] Re-implement conversation lazy loading on scroll.
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/730682-refine-convo-list: 9/12] Re-implement conversation lazy loading on scroll.
- Date: Sun, 15 Oct 2017 10:46:49 +0000 (UTC)
commit c1365b40716d8220e4c234104df172235eb5b604
Author: Michael James Gratton <mike vee net>
Date: Sun Oct 15 07:58:36 2017 +1030
Re-implement conversation lazy loading on scroll.
* src/client/conversation-list/conversation-list.vala (ConversationList):
Move lazy loading code over from old ConversationListView class. Use a
percentage of the viewport size rather than an absolute value so that
loading is triggered in around the same place regardless of the window
size.
* src/client/application/geary-controller.vala (GearyController): Move
lazy-loading related code to MainWindow.
* src/client/components/main-window.vala (MainWindow): Hook up
lazy-loading signals to new conversation list.
src/client/application/geary-controller.vala | 23 -----
src/client/components/main-window.vala | 25 ++++++
.../conversation-list/conversation-list.vala | 85 ++++++++++++++++++++
3 files changed, 110 insertions(+), 23 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index bc99e2f..f3b4a55 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -226,7 +226,6 @@ public class GearyController : Geary.BaseObject {
Geary.Engine.instance.untrusted_host.connect(on_untrusted_host);
// Connect to various UI signals.
- main_window.conversation_list_view.load_more.connect(on_load_more);
main_window.conversation_list_view.mark_conversations.connect(on_mark_conversations);
main_window.conversation_list_view.visible_conversations_changed.connect(on_visible_conversations_changed);
main_window.folder_list.folder_selected.connect(on_folder_selected);
@@ -298,7 +297,6 @@ public class GearyController : Geary.BaseObject {
Geary.Engine.instance.untrusted_host.disconnect(on_untrusted_host);
// Disconnect from various UI signals.
- main_window.conversation_list_view.load_more.disconnect(on_load_more);
main_window.conversation_list_view.mark_conversations.disconnect(on_mark_conversations);
main_window.conversation_list_view.visible_conversations_changed.disconnect(on_visible_conversations_changed);
main_window.folder_list.folder_selected.disconnect(on_folder_selected);
@@ -1446,9 +1444,6 @@ public class GearyController : Geary.BaseObject {
// Inbox selected, clear new messages if visible
clear_new_messages("do_select_folder (inbox)", null);
}
-
- current_conversations.scan_error.connect(on_scan_error);
- current_conversations.seed_completed.connect(on_seed_completed);
if (!current_conversations.is_monitoring)
yield current_conversations.start_monitoring_async(conversation_cancellable);
@@ -1458,19 +1453,6 @@ public class GearyController : Geary.BaseObject {
debug("Switched to %s", folder.to_string());
}
- private void on_scan_error(Error err) {
- debug("Scan error: %s", err.message);
- }
-
- private void on_seed_completed() {
- // Done scanning. Check if we have enough messages to fill the conversation list; if not,
- // trigger a load_more();
- if (!main_window.conversation_list_has_scrollbar()) {
- debug("Not enough messages, loading more for folder %s", current_folder.to_string());
- on_load_more();
- }
- }
-
private void on_libnotify_invoked(Geary.Folder? folder, Geary.Email? email) {
new_messages_monitor.clear_all_new_messages();
@@ -1500,11 +1482,6 @@ public class GearyController : Geary.BaseObject {
main_window.folder_list.select_folder(folder);
}
- private void on_load_more() {
- debug("on_load_more");
- current_conversations.min_window_count += MIN_CONVERSATION_COUNT;
- }
-
private void on_select_folder_completed(Object? source, AsyncResult result) {
try {
do_select_folder.end(result);
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index c333b6a..5031c7f 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -66,6 +66,7 @@ public class MainWindow : Gtk.ApplicationWindow {
this.conversation_list.conversation_selection_changed.connect(on_conversation_selection_changed);
this.conversation_list.conversation_activated.connect(on_conversation_activated);
+ this.conversation_list.load_more.connect(on_load_more);
load_config(application.config);
restore_saved_window_state();
@@ -85,6 +86,7 @@ public class MainWindow : Gtk.ApplicationWindow {
~MainWindow() {
this.conversation_list.conversation_selection_changed.disconnect(on_conversation_selection_changed);
this.conversation_list.conversation_activated.disconnect(on_conversation_activated);
+ this.conversation_list.load_more.disconnect(on_load_more);
}
/**
@@ -288,6 +290,8 @@ public class MainWindow : Gtk.ApplicationWindow {
Geary.App.ConversationMonitor? old_monitor = (this.conversation_list != null)
? this.conversation_list.model.monitor : null;
if (old_monitor != null) {
+ old_monitor.scan_error.disconnect(on_scan_error);
+ old_monitor.seed_completed.disconnect(on_seed_completed);
old_monitor.seed_completed.disconnect(on_conversation_count_changed);
old_monitor.scan_completed.disconnect(on_conversation_count_changed);
old_monitor.conversations_added.disconnect(on_conversation_count_changed);
@@ -305,6 +309,9 @@ public class MainWindow : Gtk.ApplicationWindow {
this.conversation_list_view.set_model(new_model);
this.conversation_list.bind_model(new_monitor);
+
+ new_monitor.scan_error.connect(on_scan_error);
+ new_monitor.seed_completed.connect(on_seed_completed);
new_monitor.seed_completed.connect(on_conversation_count_changed);
new_monitor.scan_completed.connect(on_conversation_count_changed);
new_monitor.conversations_added.connect(on_conversation_count_changed);
@@ -489,6 +496,24 @@ public class MainWindow : Gtk.ApplicationWindow {
}
}
+ private void on_load_more() {
+ debug("on_load_more");
+ this.application.controller.current_conversations.min_window_count +=
GearyController.MIN_CONVERSATION_COUNT;
+ }
+
+ private void on_scan_error(Error err) {
+ debug("Scan error: %s", err.message);
+ }
+
+ private void on_seed_completed() {
+ // Done scanning. Check if we have enough messages to fill the conversation list; if not,
+ // trigger a load_more();
+ if (!conversation_list_has_scrollbar()) {
+ debug("Not enough messages, loading more for folder %s", current_folder.to_string());
+ on_load_more();
+ }
+ }
+
private void on_conversation_count_changed() {
if (this.application.controller.current_conversations != null) {
int count = this.application.controller.current_conversations.get_conversation_count();
diff --git a/src/client/conversation-list/conversation-list.vala
b/src/client/conversation-list/conversation-list.vala
index 525cd55..c404b97 100644
--- a/src/client/conversation-list/conversation-list.vala
+++ b/src/client/conversation-list/conversation-list.vala
@@ -19,6 +19,9 @@ public class ConversationList : Gtk.ListBox {
private Configuration config;
+ private bool enable_load_more = true;
+ private bool reset_adjustment = false;
+ private double adj_last_upper = -1.0;
/** Fired when a user changes the list's selection. */
@@ -27,6 +30,10 @@ public class ConversationList : Gtk.ListBox {
/** Fired when a user activates a row in the list. */
public signal void conversation_activated(Geary.App.Conversation activated);
+ /** Fired when additional conversations are required. */
+ public virtual signal void load_more() {
+ this.enable_load_more = false;
+ }
public ConversationList(Configuration config) {
this.config = config;
@@ -47,10 +54,17 @@ public class ConversationList : Gtk.ListBox {
}
this.conversation_selection_changed(new_selection);
});
+
+ this.show.connect(on_show);
}
public new void bind_model(Geary.App.ConversationMonitor monitor) {
+ monitor.scan_started.connect(on_scan_started);
+ monitor.scan_completed.connect(on_scan_completed);
+
this.model = new ConversationListModel(monitor);
+ this.model.items_changed.connect(on_model_items_changed);
+
Geary.Folder displayed = monitor.folder;
Gee.List<Geary.RFC822.MailboxAddress> account_addresses =
displayed.account.information.get_all_mailboxes();
bool use_to = (displayed != null) && displayed.special_folder_type.is_outgoing();
@@ -63,4 +77,75 @@ public class ConversationList : Gtk.ListBox {
);
}
+ private void on_show() {
+ // Wait until we're visible to set this signal up.
+ get_adjustment().value_changed.connect(on_adjustment_value_changed);
+ }
+
+ private void on_adjustment_value_changed() {
+ Gtk.Adjustment? adjustment = get_adjustment();
+ if (this.enable_load_more && adjustment != null) {
+ // Check if we're towards the bottom of the list. If we
+ // are, it's time to issue a load_more signal.
+ double value = adjustment.get_value();
+ double upper = adjustment.get_upper();
+ if ((value / upper) >= 0.85 &&
+ upper > this.adj_last_upper) {
+ load_more();
+ this.adj_last_upper = upper;
+ }
+ }
+ }
+
+ private void on_scan_started() {
+ this.enable_load_more = false;
+ }
+
+ private void on_scan_completed() {
+ this.enable_load_more = true;
+
+ // Select the first conversation, if autoselect is enabled,
+ // nothing has been selected yet and we're not composing. Do
+ // this here instead of in on_seed_completed since we want to
+ // to select the first row on folder change as soon as
+ // possible.
+ if (this.config.autoselect && get_selected_row() == null) {
+ Gtk.ListBoxRow? first = get_row_at_index(0);
+ if (first != null) {
+ select_row(first);
+ }
+ }
+ }
+
+ private void on_model_items_changed(uint pos, uint removed, uint added) {
+ if (added > 0) {
+ // Conversations were added
+ Gtk.Adjustment? adjustment = get_adjustment();
+ if (pos == 0) {
+ // We were at the top and we want to stay there after
+ // conversations are added
+ this.reset_adjustment = (adjustment != null) && (adjustment.get_value() == 0);
+ } else if (this.reset_adjustment && adjustment != null) {
+ // Pump the loop to make sure the new conversations are
+ // taking up space in the window. Without this, setting
+ // the adjustment here is a no-op because as far as it's
+ // concerned, it's already at the top.
+ while (Gtk.events_pending())
+ Gtk.main_iteration();
+
+ adjustment.set_value(0);
+ }
+ this.reset_adjustment = false;
+ }
+
+ if (removed >= 0) {
+ // Conversations were removed.
+
+ // Reset the last upper limit so scrolling to the bottom
+ // will always activate a reload (this is particularly
+ // important if the model is cleared)
+ this.adj_last_upper = -1.0;
+ }
+ }
+
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]