[geary/wip/794700-lazy-load-conversations: 3/3] Rework how email are loaded and displayed in the conversation viewer



commit d8cf5fdb80dbd435c30c797a37bf02813e23403d
Author: Michael Gratton <mike vee net>
Date:   Wed Jan 16 14:57:11 2019 +1100

    Rework how email are loaded and displayed in the conversation viewer
    
    Ensure email are loaded and added in order, so that sorting can be
    disabled while loading the coversation. Load email in reverse order, so
    that more interesting ones are loaded first. Load the latest email
    fully first, so that it can be displayed ASAP up front.
    
    This breaks scrolling to the first starred conversation, but that might
    be better handled with a toaster notifying users of the first starred
    conversation and letting them scroll to it.

 .../conversation-viewer/conversation-list-box.vala | 104 +++++++--------------
 1 file changed, 36 insertions(+), 68 deletions(-)
---
diff --git a/src/client/conversation-viewer/conversation-list-box.vala 
b/src/client/conversation-viewer/conversation-list-box.vala
index 5822afc6..8ac95c4b 100644
--- a/src/client/conversation-viewer/conversation-list-box.vala
+++ b/src/client/conversation-viewer/conversation-list-box.vala
@@ -1,6 +1,6 @@
 /*
  * Copyright 2016 Software Freedom Conservancy Inc.
- * Copyright 2016 Michael Gratton <mike vee net>
+ * Copyright 2016,2019 Michael Gratton <mike vee net>
  *
  * This software is licensed under the GNU Lesser General Public License
  * (version 2.1 or later). See the COPYING file in this distribution.
@@ -456,61 +456,51 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
 
     public async void load_conversation()
         throws Error {
-        // Fetch full emails from the conversation
-        Gee.Collection<Geary.Email> full_emails =
-            yield load_full_emails(
-                this.conversation.get_emails(
-                    Geary.App.Conversation.Ordering.SENT_DATE_ASCENDING
-                )
-            );
+        set_sort_func(null);
 
-        // Add them all
+        // Add all email in the conversation. This is done in reverse
+        // so that the most internal (i.e. recent) messages are added
+        // first.
+        Gee.List<Geary.Email> email = this.conversation.get_emails(
+            Geary.App.Conversation.Ordering.SENT_DATE_DESCENDING
+        );
+        EmailRow? last_row = null;
         EmailRow? first_expanded_row = null;
-        foreach (Geary.Email full_email in full_emails) {
+        foreach (Geary.Email convo_email in email) {
             if (this.cancellable.is_cancelled()) {
                 break;
             }
-            if (!this.email_rows.has_key(full_email.id)) {
-                EmailRow row = add_email(full_email);
-                if (row.is_expanded &&
-                    (first_expanded_row == null ||
-                     on_sort(row, first_expanded_row) < 0)) {
-                    first_expanded_row = row;
-                }
+            Geary.Email full_email = yield this.email_store.fetch_email_async(
+                convo_email.id,
+                REQUIRED_FIELDS,
+                Geary.Folder.ListFlags.NONE,
+                this.cancellable
+            );
+            EmailRow row = add_email(full_email);
+            if (last_row == null) {
+                last_row = row;
+
+                // Expand to start loading the message body, but wait
+                // until the row has fully loaded before continuing, so that we don't
+                // cause the view to jump around as the row is
+                // changing size when loading
+                row.view.notify["message-bodies-loaded"].connect(() => {
+                        this.load_conversation.callback();
+                    });
+                row.expand();
+                yield;
             }
-        }
-
-        update_first_last_row();
-        EmailRow? last_email = this.last_row as EmailRow;
-
-        if (last_email != null && !this.cancellable.is_cancelled()) {
-            // If no other row was expanded by default, use the last
-            if (first_expanded_row == null) {
-                last_email.expand();
-                first_expanded_row = last_email;
+            if (row.is_expanded) {
+                first_expanded_row = row;
             }
+            row.view.load_avatars.begin(this.avatar_store);
 
-            // Start the first expanded row loading before any others,
-            // scroll the view to it when its done
-            yield first_expanded_row.view.load_avatars(this.avatar_store);
-            first_expanded_row.should_scroll.connect(scroll_to);
-            first_expanded_row.enable_should_scroll();
-
-            // Start everything else loading
-            this.foreach((child) => {
-                    if (!this.cancellable.is_cancelled()) {
-                        EmailRow? row = child as EmailRow;
-                        if (row != null && row != first_expanded_row) {
-                            row.view.load_avatars.begin(this.avatar_store);
-                        }
-                    }
-                });
-
-            debug("Conversation loading complete");
+            scroll_to(last_row);
         }
 
         this.loading_timeout_id = 0;
         set_placeholder(null);
+        set_sort_func(ConversationListBox.on_sort);
     }
 
     /**
@@ -726,28 +716,6 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
             });
     }
 
-    // Given some emails, fetch the full versions with all required fields.
-    private async Gee.Collection<Geary.Email> load_full_emails(
-        Gee.Collection<Geary.Email> emails) throws Error {
-        Gee.ArrayList<Geary.EmailIdentifier> ids = new Gee.ArrayList<Geary.EmailIdentifier>();
-        foreach (Geary.Email email in emails)
-            ids.add(email.id);
-
-        Gee.Collection<Geary.Email>? full_emails =
-            yield this.email_store.list_email_by_sparse_id_async(
-                ids,
-                REQUIRED_FIELDS,
-                Geary.Folder.ListFlags.NONE,
-                this.cancellable
-            );
-
-        if (full_emails == null) {
-            full_emails = Gee.Collection.empty<Geary.Email>();
-        }
-
-        return full_emails;
-    }
-
     // Loads full version of an email, adds it to the listbox
     private async void load_full_email(Geary.EmailIdentifier id)
         throws Error {
@@ -758,7 +726,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
         if (!this.cancellable.is_cancelled()) {
             EmailRow row = add_email(full_email);
             update_first_last_row();
-            yield row.view.load_avatars(this.avatar_store);
+            row.view.load_avatars.begin(this.avatar_store);
         }
     }
 
@@ -805,7 +773,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
         EmailRow row = new EmailRow(view);
         this.email_rows.set(email.id, row);
 
-        add(row);
+        insert(row, 0);
         email_added(view);
 
         // Expand interesting messages by default


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