[geary/wip/713150-conversations: 20/20] Fix scrollbar detection & client-API loop for loading more when necessary



commit 9619493b6a8bbaf174a52f14299bbec8a94d01bf
Author: Jim Nelson <jim yorba org>
Date:   Tue Mar 17 18:12:01 2015 -0700

    Fix scrollbar detection & client-API loop for loading more when necessary

 src/client/application/geary-controller.vala       |   32 +++++++++++---
 src/client/components/main-window.vala             |   20 ++++++++-
 .../conversation-list/conversation-list-store.vala |    2 +-
 src/engine/app/app-conversation-monitor.vala       |   45 +++++++++++++++----
 4 files changed, 80 insertions(+), 19 deletions(-)
---
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index 85a37bc..aa3923e 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -58,7 +58,7 @@ public class GearyController : Geary.BaseObject {
     public const string PROP_CURRENT_CONVERSATION ="current-conversations";
     
     public const int MIN_CONVERSATION_COUNT = 50;
-    public const int LOAD_MORE_CONVERSATION_COUNT = 20;
+    public const int LOAD_MORE_CONVERSATION_COUNT = 10;
     
     private const string DELETE_MESSAGE_TOOLTIP_SINGLE = _("Delete conversation (Shift+Delete)");
     private const string DELETE_MESSAGE_TOOLTIP_MULTIPLE = _("Delete conversations (Shift+Delete)");
@@ -206,6 +206,7 @@ public class GearyController : Geary.BaseObject {
         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.conversation_list_height_changed.connect(on_check_conversation_list_scrollbars);
         main_window.folder_list.folder_selected.connect(on_folder_selected);
         main_window.folder_list.copy_conversation.connect(on_copy_conversation);
         main_window.folder_list.move_conversation.connect(on_move_conversation);
@@ -282,6 +283,7 @@ public class GearyController : Geary.BaseObject {
         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.conversation_list_height_changed.disconnect(on_check_conversation_list_scrollbars);
         main_window.folder_list.folder_selected.disconnect(on_folder_selected);
         main_window.folder_list.copy_conversation.disconnect(on_copy_conversation);
         main_window.folder_list.move_conversation.disconnect(on_move_conversation);
@@ -1453,8 +1455,12 @@ public class GearyController : Geary.BaseObject {
         }
         
         current_conversations.scan_error.connect(on_scan_error);
-        current_conversations.scan_completed.connect(on_scan_completed);
-        current_conversations.scan_completed.connect(on_conversation_count_changed);
+        current_conversations.scan_completed.connect((conversations_added) => {
+            if (conversations_added) {
+                on_check_conversation_list_scrollbars();
+                on_conversation_count_changed();
+            }
+        });
         current_conversations.conversations_added.connect(on_conversation_count_changed);
         current_conversations.conversation_removed.connect(on_conversation_count_changed);
         current_conversations.conversation_removed.connect(on_conversation_removed);
@@ -1471,7 +1477,7 @@ public class GearyController : Geary.BaseObject {
         debug("Scan error: %s", err.message);
     }
     
-    private void on_scan_completed() {
+    private void on_check_conversation_list_scrollbars() {
         if (scrollbar_check_id != 0)
             Source.remove(scrollbar_check_id);
         
@@ -1483,6 +1489,9 @@ public class GearyController : Geary.BaseObject {
         // all code paths lead to this SourceFunc being removed when completed
         scrollbar_check_id = 0;
         
+        if (current_conversations == null)
+            return false;
+        
         // 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())
@@ -1492,6 +1501,8 @@ public class GearyController : Geary.BaseObject {
             current_conversations.get_conversation_count(), current_conversations.min_window_count,
             current_folder.to_string());
         
+        // expand the ConversationMonitor window to include more messages until a scrollbar becomes
+        // present
         on_load_more();
         
         return false;
@@ -1535,8 +1546,17 @@ public class GearyController : Geary.BaseObject {
     }
     
     private void on_load_more() {
-        debug("on_load_more");
-        current_conversations.min_window_count += LOAD_MORE_CONVERSATION_COUNT;
+        if (current_conversations == null || current_conversations.all_mail_loaded)
+            return;
+        
+        int orig = current_conversations.min_window_count;
+        
+        // It's possible for the conversation count to be any value above or below the min_window_count,
+        // so ensure *some* increase happens to trigger loading more conversations
+        current_conversations.min_window_count =
+            current_conversations.get_conversation_count() + LOAD_MORE_CONVERSATION_COUNT;
+        if (current_conversations.min_window_count <= orig)
+            current_conversations.min_window_count = orig + LOAD_MORE_CONVERSATION_COUNT;
     }
     
     private void on_select_folder_completed(Object? source, AsyncResult result) {
diff --git a/src/client/components/main-window.vala b/src/client/components/main-window.vala
index 2f83f26..f2f5a1b 100644
--- a/src/client/components/main-window.vala
+++ b/src/client/components/main-window.vala
@@ -35,6 +35,10 @@ public class MainWindow : Gtk.ApplicationWindow {
     private Geary.ProgressMonitor? conversation_monitor_progress = null;
     private Geary.ProgressMonitor? folder_progress = null;
     private Geary.Folder? current_folder = null;
+    private int conversation_list_height = -1;
+    private int conversation_list_width = -1;
+    
+    public signal void conversation_list_height_changed();
     
     public MainWindow(GearyApplication application) {
         Object(application: application);
@@ -97,6 +101,17 @@ public class MainWindow : Gtk.ApplicationWindow {
         set_styling();
         create_layout();
         on_change_orientation();
+        
+        // can only set this up after create_layout
+        conversation_list_scrolled.size_allocate.connect((alloc) => {
+            if (conversation_list_width == alloc.width && conversation_list_height == alloc.height)
+                return;
+            
+            conversation_list_width = alloc.width;
+            conversation_list_height = alloc.height;
+            
+            conversation_list_height_changed();
+        });
     }
     
     public override void show_all() {
@@ -271,8 +286,9 @@ public class MainWindow : Gtk.ApplicationWindow {
     // Returns true when there's a conversation list scrollbar visible, i.e. the list is tall
     // enough to need one.  Otherwise returns false.
     public bool conversation_list_has_scrollbar() {
-        Gtk.Scrollbar? scrollbar = conversation_list_scrolled.get_vscrollbar() as Gtk.Scrollbar;
-        return scrollbar != null && scrollbar.get_visible();
+        Gtk.Adjustment vadj = conversation_list_scrolled.vadjustment;
+        
+        return (vadj.upper - vadj.lower) > vadj.page_size;
     }
     
     private bool on_key_press_event(Gdk.EventKey event) {
diff --git a/src/client/conversation-list/conversation-list-store.vala 
b/src/client/conversation-list/conversation-list-store.vala
index eca2ced..92cd6ae 100644
--- a/src/client/conversation-list/conversation-list-store.vala
+++ b/src/client/conversation-list/conversation-list-store.vala
@@ -411,7 +411,7 @@ public class ConversationListStore : Gtk.ListStore {
         return true;
     }
     
-    private void on_scan_completed(Geary.App.ConversationMonitor sender) {
+    private void on_scan_completed(Geary.App.ConversationMonitor sender, bool conversations_added) {
         refresh_previews_async.begin(sender);
         loading_local_only = false;
     }
diff --git a/src/engine/app/app-conversation-monitor.vala b/src/engine/app/app-conversation-monitor.vala
index c708e65..ebc779c 100644
--- a/src/engine/app/app-conversation-monitor.vala
+++ b/src/engine/app/app-conversation-monitor.vala
@@ -76,7 +76,9 @@ public class Geary.App.ConversationMonitor : BaseObject {
     }
     
     public Geary.Folder folder { get; private set; }
+    
     public bool is_monitoring { get; private set; default = false; }
+    
     public int min_window_count { get { return _min_window_count; }
         set {
             if (_min_window_count == value)
@@ -87,6 +89,11 @@ public class Geary.App.ConversationMonitor : BaseObject {
         }
     }
     
+    /**
+     * Indicates that all mail in the primary { link folder} has been loaded.
+     */
+    public bool all_mail_loaded { get; private set; default = false; }
+    
     public Geary.ProgressMonitor progress_monitor { get { return operation_queue.progress_monitor; } }
     
     private Geary.Email.Field required_fields;
@@ -150,9 +157,9 @@ public class Geary.App.ConversationMonitor : BaseObject {
     /**
      * "scan-completed" is fired when the scan of the email has finished.
      */
-    public virtual signal void scan_completed() {
-        Logging.debug(Logging.Flag.CONVERSATIONS, "[%s] ConversationMonitor::scan_completed",
-            folder.to_string());
+    public virtual signal void scan_completed(bool conversations_added) {
+        Logging.debug(Logging.Flag.CONVERSATIONS, "[%s] ConversationMonitor::scan_completed 
conversations_added=%s",
+            folder.to_string(), conversations_added.to_string());
     }
     
     /**
@@ -258,8 +265,8 @@ public class Geary.App.ConversationMonitor : BaseObject {
         scan_error(err);
     }
     
-    protected virtual void notify_scan_completed() {
-        scan_completed();
+    protected virtual void notify_scan_completed(bool conversations_added) {
+        scan_completed(conversations_added);
     }
     
     protected virtual void notify_conversations_added(Gee.Collection<Conversation> conversations) {
@@ -434,6 +441,8 @@ public class Geary.App.ConversationMonitor : BaseObject {
     // later when locally-available)
     private async void load_by_id_async(Geary.EmailIdentifier? initial_id, int count, Email.Field fields,
         Geary.Folder.ListFlags flags, Cancellable? cancellable) {
+        int start_conversations = get_conversation_count();
+        
         notify_scan_started();
         try {
             yield process_email_async(folder.path,
@@ -442,13 +451,15 @@ public class Geary.App.ConversationMonitor : BaseObject {
         } catch (Error err) {
             notify_scan_error(err);
         } finally {
-            notify_scan_completed();
+            notify_scan_completed(start_conversations < get_conversation_count());
         }
     }
     
     // See note at load_by_id_async for how Email.Field should be treated by caller
     private async void load_by_sparse_id(Gee.Collection<Geary.EmailIdentifier> ids, Email.Field fields,
         Geary.Folder.ListFlags flags, Cancellable? cancellable) {
+        int start_conversations = get_conversation_count();
+        
         notify_scan_started();
         try {
             yield process_email_async(folder.path,
@@ -457,7 +468,7 @@ public class Geary.App.ConversationMonitor : BaseObject {
         } catch (Error err) {
             notify_scan_error(err);
         } finally {
-            notify_scan_completed();
+            notify_scan_completed(start_conversations < get_conversation_count());
         }
     }
     
@@ -629,10 +640,14 @@ public class Geary.App.ConversationMonitor : BaseObject {
     }
     
     private void on_folder_email_appended(Gee.Collection<Geary.EmailIdentifier> appended_ids) {
+        all_mail_loaded = false;
+        
         operation_queue.add(new AppendOperation(this, appended_ids));
     }
     
     private void on_folder_email_inserted(Gee.Collection<Geary.EmailIdentifier> inserted_ids) {
+        all_mail_loaded = false;
+        
         operation_queue.add(new FillWindowOperation(this, true));
     }
     
@@ -782,8 +797,11 @@ public class Geary.App.ConversationMonitor : BaseObject {
         if (!is_insert && min_window_count <= conversations.size)
             return;
         
-        if (primary_email_id_to_conversation.size >= folder.properties.email_total)
+        if (primary_email_id_to_conversation.size >= folder.properties.email_total) {
+            all_mail_loaded = true;
+            
             return;
+        }
         
         int initial_message_count = get_email_count();
         
@@ -851,11 +869,18 @@ public class Geary.App.ConversationMonitor : BaseObject {
         if (reschedule && expected_more_email)
             reschedule = initial_message_count != get_email_count();
         
+        // as stated in third condition, possible for email_total to be incorrect, so use both to
+        // check if all mail has been loaded
+        if (folder.properties.email_total <= primary_email_id_to_conversation.size)
+            all_mail_loaded = true;
+        else if (expected_more_email && initial_message_count == get_email_count())
+            all_mail_loaded = true;
+        
         if (reschedule)
             operation_queue.add(new FillWindowOperation(this, false));
         
-        debug("fill_window_async: loaded from %s, email_count=%d primary_ids.size=%d folder emails=%d 
conversations.size=%d rescheduled=%s",
-            low_id != null ? low_id.to_string() : "(null)", get_email_count(), 
primary_email_id_to_conversation.size,
+        debug("fill_window_async: loaded from %s, email_count=%d min_window_count=%d primary_ids.size=%d 
folder.email_total=%d conversations.size=%d rescheduled=%s",
+            low_id != null ? low_id.to_string() : "(null)", get_email_count(), min_window_count, 
primary_email_id_to_conversation.size,
             folder.properties.email_total, conversations.size, reschedule.to_string());
     }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]