[gnome-contacts] Avatar: lazily load the Pixbuf of the avatar.



commit b4822d1040af1ff5858fe22924acbfb75a96ca7d
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Mon Jan 22 17:38:00 2018 +0100

    Avatar: lazily load the Pixbuf of the avatar.
    
    This should again decrease our memory usage in most cases.

 src/contacts-avatar-selector.vala        |    9 +-----
 src/contacts-avatar.vala                 |   44 +++++++++++++++++++++--------
 src/contacts-contact-editor.vala         |   10 +------
 src/contacts-contact-list.vala           |    3 +-
 src/contacts-contact-sheet.vala          |    5 +---
 src/contacts-link-suggestion-grid.vala   |    7 +---
 src/contacts-linked-accounts-dialog.vala |    5 +---
 7 files changed, 39 insertions(+), 44 deletions(-)
---
diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala
index 16c1ba4..83e3631 100644
--- a/src/contacts-avatar-selector.vala
+++ b/src/contacts-avatar-selector.vala
@@ -82,14 +82,7 @@ public class Contacts.AvatarSelector : Dialog {
     this.contact = contact;
 
     // Load the current avatar
-    this.current_avatar = new Avatar (MAIN_SIZE);
-    if (contact != null) {
-      contact.keep_widget_uptodate (this.current_avatar, (w) => {
-          (w as Avatar).set_image.begin (contact.individual, contact);
-        });
-    } else {
-      this.current_avatar.set_image.begin (null, null);
-    }
+    this.current_avatar = new Avatar (MAIN_SIZE, contact);
     this.current_avatar.set_hexpand (false);
     this.current_avatar.show ();
     this.grid.attach (this.current_avatar, 0, 0);
diff --git a/src/contacts-avatar.vala b/src/contacts-avatar.vala
index 3d62747..bfe6c9c 100644
--- a/src/contacts-avatar.vala
+++ b/src/contacts-avatar.vala
@@ -26,45 +26,65 @@ using Gee;
 public class Contacts.Avatar : DrawingArea {
   private int size;
   private Gdk.Pixbuf? pixbuf = null;
+
   private Contact? contact = null;
+  // We want to lazily load the Pixbuf to make sure we don't draw all contact avatars at once.
+  // As long as there is no need for it to be drawn, keep this to false.
+  private bool avatar_loaded = false;
 
   // The background color used in case of a fallback avatar
   private Gdk.RGBA? bg_color = null;
   // The color used for an initial or the fallback icon
   private const Gdk.RGBA fg_color = { 0, 0, 0, 0.25 };
 
-  public Avatar (int size) {
+  public Avatar (int size, Contact? contact = null) {
+    this.contact = contact;
+    if (contact != null) {
+      contact.individual.notify["avatar"].connect ( (s, p) => {
+          load_avatar.begin ();
+        });
+    }
+
     this.size = size;
     set_size_request (size, size);
 
     get_style_context ().add_class ("contacts-avatar");
 
+    // If we don't have an avatar, don't try to load it later
+    this.avatar_loaded = (contact == null || contact.individual == null
+                          || contact.individual.avatar == null);
+
     show ();
   }
 
+  /**
+   * Manually set the avatar to the given pixbuf, even if the contact has an avatar.
+   */
   public void set_pixbuf (Gdk.Pixbuf? a_pixbuf) {
     this.pixbuf = a_pixbuf;
     queue_draw ();
   }
 
-  public async void set_image (AvatarDetails? details, Contact? contact = null) {
-    this.contact = contact;
-
-    // FIXME listen for changes in the Individual's avatar
+  private async void load_avatar () {
+    assert (this.contact != null);
 
-    if (details != null && details.avatar != null) {
-      try {
-        var stream = yield details.avatar.load_async (size, null);
-        this.pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async (stream, size, size, true);
-        queue_draw ();
-      } catch {
-      }
+    this.avatar_loaded = true;
+    try {
+      var stream = yield this.contact.individual.avatar.load_async (this.size);
+      this.pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async (stream, this.size, this.size, true);
+      queue_draw ();
+    } catch (Error e) {
+      debug ("Couldn't load avatar of contact %s. Reason: %s", this.contact.individual.display_name, 
e.message);
     }
   }
 
   public override bool draw (Cairo.Context cr) {
     cr.save ();
 
+    // This exists to implement lazy loading: i.e. only load the avatar on the first draw()
+    if (!this.avatar_loaded)
+      load_avatar.begin ();
+
     if (this.pixbuf != null)
       draw_contact_avatar (cr);
     else // No avatar available, draw a fallback
diff --git a/src/contacts-contact-editor.vala b/src/contacts-contact-editor.vala
index 0c5de6d..3cde0c2 100644
--- a/src/contacts-contact-editor.vala
+++ b/src/contacts-contact-editor.vala
@@ -942,21 +942,13 @@ public class Contacts.ContactEditor : Grid {
 
   // Creates the contact's current avatar in a big button on top of the Editor
   private void create_avatar_button () {
-    this.avatar = new Avatar (PROFILE_SIZE);
+    this.avatar = new Avatar (PROFILE_SIZE, this.contact);
 
     var button = new Button ();
     button.get_accessible ().set_name (_("Change avatar"));
     button.image = this.avatar;
     button.clicked.connect (on_avatar_button_clicked);
 
-    if (this.contact != null) {
-      this.contact.keep_widget_uptodate (this.avatar,  (w) => {
-          this.avatar.set_image.begin (this.contact.individual, this.contact);
-        });
-    } else {
-      this.avatar.set_image.begin (null, null);
-    }
-
     this.container_grid.attach (button, 0, 0, 1, 3);
   }
 
diff --git a/src/contacts-contact-list.vala b/src/contacts-contact-list.vala
index 2aa2b85..618ecc8 100644
--- a/src/contacts-contact-list.vala
+++ b/src/contacts-contact-list.vala
@@ -44,7 +44,7 @@ public class Contacts.ContactList : ListBox {
       grid.margin = 3;
       grid.margin_start = 9;
       grid.set_column_spacing (10);
-      this.avatar = new Avatar (LIST_AVATAR_SIZE);
+      this.avatar = new Avatar (LIST_AVATAR_SIZE, this.contact);
 
       this.label = new Label (c.individual.display_name);
       this.label.ellipsize = Pango.EllipsizeMode.END;
@@ -71,7 +71,6 @@ public class Contacts.ContactList : ListBox {
     public void update () {
       // Update widgets
       this.label.set_text (this.contact.individual.display_name);
-      this.avatar.set_image.begin (this.contact.individual, this.contact);
     }
 
     // Sets whether the checbox should always be shown (and not only on hover)
diff --git a/src/contacts-contact-sheet.vala b/src/contacts-contact-sheet.vala
index 88c0bb1..8467f46 100644
--- a/src/contacts-contact-sheet.vala
+++ b/src/contacts-contact-sheet.vala
@@ -96,12 +96,9 @@ public class Contacts.ContactSheet : Grid {
   }
 
   public void update (Contact c) {
-    var image_frame = new Avatar (PROFILE_SIZE);
+    var image_frame = new Avatar (PROFILE_SIZE, c);
     image_frame.set_vexpand (false);
     image_frame.set_valign (Align.START);
-    c.keep_widget_uptodate (image_frame,  (w) => {
-        (w as Avatar).set_image.begin (c.individual, c);
-      });
     attach (image_frame,  0, 0, 1, 3);
 
     var name_label = new Label (null);
diff --git a/src/contacts-link-suggestion-grid.vala b/src/contacts-link-suggestion-grid.vala
index 36f4a61..998c5eb 100644
--- a/src/contacts-link-suggestion-grid.vala
+++ b/src/contacts-link-suggestion-grid.vala
@@ -43,16 +43,13 @@ public class Contacts.LinkSuggestionGrid : Grid {
   public LinkSuggestionGrid (Contact contact) {
     get_style_context ().add_class ("contacts-suggestion");
 
-    var image_frame = new Avatar (AVATAR_SIZE);
+    var image_frame = new Avatar (AVATAR_SIZE, contact);
     image_frame.hexpand = false;
     image_frame.margin = 12;
-    contact.keep_widget_uptodate (image_frame,  (w) => {
-        (w as Avatar).set_image.begin (contact.individual, contact);
-      });
     image_frame.show ();
     attach (image_frame, 0, 0, 1, 2);
 
-    this.description_label.xalign = 0; // FIXME: hack to make it actually align left.
+    this.description_label.xalign = 0;
     this.description_label.label = contact.is_main?
           _("Is this the same person as %s from %s?").printf (contact.individual.display_name, 
contact.format_persona_stores ())
         : _("Is this the same person as %s?").printf (contact.individual.display_name);
diff --git a/src/contacts-linked-accounts-dialog.vala b/src/contacts-linked-accounts-dialog.vala
index 6bb3df6..5913e5e 100644
--- a/src/contacts-linked-accounts-dialog.vala
+++ b/src/contacts-linked-accounts-dialog.vala
@@ -80,13 +80,10 @@ public class Contacts.LinkedAccountsDialog : Dialog {
 
       var row_grid = new Grid ();
 
-      var image_frame = new Avatar (AVATAR_SIZE);
+      var image_frame = new Avatar (AVATAR_SIZE, contact);
       image_frame.set_hexpand (false);
       image_frame.margin = 6;
       image_frame.margin_end = 12;
-      contact.keep_widget_uptodate (image_frame, (w) => {
-          (w as Avatar).set_image.begin (contact.individual, contact);
-        });
       row_grid.attach (image_frame, 0, 0, 1, 2);
 
       var display_name = new Label ("");


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