[geary/wip/794700-lazy-load-conversations: 1/3] Lazily load message bodies in conversation viewer
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/794700-lazy-load-conversations: 1/3] Lazily load message bodies in conversation viewer
- Date: Wed, 16 Jan 2019 04:01:17 +0000 (UTC)
commit 7cb7b2e551b711e3ad7313f3aaea8fd917dc08df
Author: Michael Gratton <mike vee net>
Date: Wed Jan 16 14:43:07 2019 +1100
Lazily load message bodies in conversation viewer
This reduces resource consumption when loading large conversations.
.../conversation-viewer/conversation-email.vala | 70 ++++++++++------------
.../conversation-viewer/conversation-list-box.vala | 13 ++--
.../conversation-viewer/conversation-message.vala | 4 ++
3 files changed, 40 insertions(+), 47 deletions(-)
---
diff --git a/src/client/conversation-viewer/conversation-email.vala
b/src/client/conversation-viewer/conversation-email.vala
index d0e160d0..2e3852ab 100644
--- a/src/client/conversation-viewer/conversation-email.vala
+++ b/src/client/conversation-viewer/conversation-email.vala
@@ -255,6 +255,9 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
/** Determines if all message's web views have finished loading. */
public bool message_bodies_loaded { get; private set; default = false; }
+ // Cancellable to use when loading message content
+ private GLib.Cancellable load_cancellable;
+
// Contacts for the email's account
private Geary.ContactStore contact_store;
@@ -268,7 +271,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
// A subset of the message's attachments that are displayed in the
// attachments view
- Gee.Collection<Geary.Attachment> displayed_attachments =
+ private Gee.Collection<Geary.Attachment> displayed_attachments =
new Gee.LinkedList<Geary.Attachment>();
// Message-specific actions
@@ -371,11 +374,13 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
Geary.ContactStore contact_store,
Configuration config,
bool is_sent,
- bool is_draft) {
+ bool is_draft,
+ GLib.Cancellable load_cancellable) {
base_ref();
this.email = email;
this.contact_store = contact_store;
this.config = config;
+ this.load_cancellable = load_cancellable;
if (is_sent) {
get_style_context().add_class(SENT_CLASS);
@@ -520,33 +525,12 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
}
/**
- * Starts loading the complete email.
- *
- * This method will load the avatar and message body for the
- * primary message and any attached messages, as well as
- * attachment names, types and icons.
+ * Loads avatars for the email's messages.
*/
- public async void start_loading(Application.AvatarStore avatars,
- Cancellable load_cancelled) {
+ public async void load_avatars(Application.AvatarStore store) {
foreach (ConversationMessage view in this) {
- if (load_cancelled.is_cancelled()) {
- break;
- }
- yield view.load_message_body(load_cancelled);
- view.load_avatar.begin(avatars, load_cancelled);
- }
-
- // Only load attachments once the web views have finished
- // loading, since we want to know if any attachments marked as
- // being inline were actually not displayed inline, and hence
- // need to be displayed as if they were attachments.
- if (!load_cancelled.is_cancelled()) {
- if (this.message_bodies_loaded) {
- yield load_attachments(load_cancelled);
- } else {
- this.notify["message-bodies-loaded"].connect(() => {
- load_attachments.begin(load_cancelled);
- });
+ if (!this.load_cancellable.is_cancelled()) {
+ yield view.load_avatar(store, this.load_cancellable);
}
}
}
@@ -572,13 +556,15 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
* Shows the complete message: headers, body and attachments.
*/
public void expand_email(bool include_transitions=true) {
- is_collapsed = false;
+ this.is_collapsed = false;
update_email_state();
- attachments_button.set_sensitive(true);
- email_menubutton.set_sensitive(true);
- primary_message.show_message_body(include_transitions);
- foreach (ConversationMessage attached in this._attached_messages) {
- attached.show_message_body(include_transitions);
+ this.attachments_button.set_sensitive(true);
+ this.email_menubutton.set_sensitive(true);
+ foreach (ConversationMessage message in this) {
+ message.show_message_body(include_transitions);
+ if (!message.body_load_started) {
+ message.load_message_body.begin(this.load_cancellable);
+ }
}
}
@@ -682,10 +668,16 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
break;
}
}
- if (all_loaded == true && !this.message_bodies_loaded) {
- // Only update the property value if not already
- // true
+ if (all_loaded && !this.message_bodies_loaded) {
this.message_bodies_loaded = true;
+ // Only load attachments once the web views have
+ // finished loading, since we want to know if any
+ // attachments marked as being inline were
+ // actually not displayed inline, and hence need
+ // to be displayed as if they were attachments.
+ if (!this.load_cancellable.is_cancelled()) {
+ this.load_attachments.begin();
+ }
}
});
view.web_view.selection_changed.connect((has_selection) => {
@@ -726,7 +718,7 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
}
}
- private async void load_attachments(Cancellable load_cancelled) {
+ private async void load_attachments() {
// Determine if we have any attachments to be displayed. This
// relies on the primary and any attached message bodies
// having being already loaded, so that we know which
@@ -765,12 +757,12 @@ public class ConversationEmail : Gtk.Box, Geary.BaseInterface {
}
foreach (Geary.Attachment attachment in this.displayed_attachments) {
- if (load_cancelled.is_cancelled()) {
+ if (this.load_cancellable.is_cancelled()) {
return;
}
AttachmentView view = new AttachmentView(attachment);
this.attachments_view.add(view);
- yield view.load_icon(load_cancelled);
+ yield view.load_icon(this.load_cancellable);
}
}
}
diff --git a/src/client/conversation-viewer/conversation-list-box.vala
b/src/client/conversation-viewer/conversation-list-box.vala
index 9c4e767d..5822afc6 100644
--- a/src/client/conversation-viewer/conversation-list-box.vala
+++ b/src/client/conversation-viewer/conversation-list-box.vala
@@ -492,9 +492,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
// Start the first expanded row loading before any others,
// scroll the view to it when its done
- yield first_expanded_row.view.start_loading(
- this.avatar_store, this.cancellable
- );
+ yield first_expanded_row.view.load_avatars(this.avatar_store);
first_expanded_row.should_scroll.connect(scroll_to);
first_expanded_row.enable_should_scroll();
@@ -503,9 +501,7 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
if (!this.cancellable.is_cancelled()) {
EmailRow? row = child as EmailRow;
if (row != null && row != first_expanded_row) {
- row.view.start_loading.begin(
- this.avatar_store, this.cancellable
- );
+ row.view.load_avatars.begin(this.avatar_store);
}
}
});
@@ -762,7 +758,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.start_loading(this.avatar_store, this.cancellable);
+ yield row.view.load_avatars(this.avatar_store);
}
}
@@ -789,7 +785,8 @@ public class ConversationListBox : Gtk.ListBox, Geary.BaseInterface {
this.contact_store,
this.config,
is_sent,
- is_draft
+ is_draft,
+ this.cancellable
);
view.mark_email.connect(on_mark_email);
view.mark_email_from_here.connect(on_mark_email_from_here);
diff --git a/src/client/conversation-viewer/conversation-message.vala
b/src/client/conversation-viewer/conversation-message.vala
index 60faa8ac..db5fabb6 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -145,6 +145,9 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
/** The specific RFC822 message displayed by this view. */
public Geary.RFC822.Message message { get; private set; }
+ /** Determines if the message body as started loading. */
+ public bool body_load_started { get; private set; default = false; }
+
/** Box containing the preview and full header widgets. */
[GtkChild]
internal Gtk.Grid summary;
@@ -472,6 +475,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
* Starts loading the message body in the HTML view.
*/
public async void load_message_body(Cancellable load_cancelled) {
+ this.body_load_started = true;
string? body_text = null;
try {
body_text = (this.message.has_html_body())
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]