[geary/Community/Purism/geary-hdy-avatar: 2/3] avatar: Use HdyAvatar for displaying avatars




commit 6a052031df579556ada034d0a9bb00797d368d63
Author: Julian Sparber <julian sparber net>
Date:   Thu Jan 14 17:33:58 2021 +0100

    avatar: Use HdyAvatar for displaying avatars

 .../application/application-avatar-store.vala      | 166 ---------------------
 .../application/application-contact-store.vala     |   5 +-
 src/client/application/application-contact.vala    |  29 ++--
 src/client/application/application-controller.vala |   6 +-
 .../conversation-contact-popover.vala              |  39 ++---
 .../conversation-viewer/conversation-message.vala  |  34 ++---
 src/client/meson.build                             |   1 -
 .../desktop-notifications.vala                     |  42 +++---
 test/client/composer/composer-widget-test.vala     |   3 +-
 ui/conversation-contact-popover.ui                 |   6 +-
 ui/conversation-message.ui                         |   8 +-
 11 files changed, 66 insertions(+), 273 deletions(-)
---
diff --git a/src/client/application/application-contact-store.vala 
b/src/client/application/application-contact-store.vala
index 981483fd3..bf9916491 100644
--- a/src/client/application/application-contact-store.vala
+++ b/src/client/application/application-contact-store.vala
@@ -44,7 +44,6 @@ public class Application.ContactStore : Geary.BaseObject {
     public Geary.Account account { get; private set; }
 
     internal Folks.IndividualAggregator individuals;
-    internal AvatarStore avatars;
 
     // Cache for storing Folks individuals by email address. Store
     // nulls so that negative lookups are cached as well.
@@ -62,14 +61,12 @@ public class Application.ContactStore : Geary.BaseObject {
 
     /** Constructs a new contact store for an account. */
     internal ContactStore(Geary.Account account,
-                          Folks.IndividualAggregator individuals,
-                          AvatarStore avatars) {
+                          Folks.IndividualAggregator individuals) {
         this.account = account;
         this.individuals = individuals;
         this.individuals.individuals_changed_detailed.connect(
             on_individuals_changed
         );
-        this.avatars = avatars;
     }
 
     ~ContactStore() {
diff --git a/src/client/application/application-contact.vala b/src/client/application/application-contact.vala
index 7f9a7cc51..71397cf04 100644
--- a/src/client/application/application-contact.vala
+++ b/src/client/application/application-contact.vala
@@ -19,6 +19,14 @@ public class Application.Contact : Geary.BaseObject {
     /** The human-readable name of the contact. */
     public string display_name { get; private set; }
 
+    /** The avatar of the contact. */
+    public GLib.LoadableIcon? avatar { get {
+      if (this.individual != null)
+        return this.individual.avatar;
+      else
+        return null;
+    }}
+
     /** Determines if {@link display_name} the same as its email address. */
     public bool display_name_is_email { get; private set; default = false; }
 
@@ -265,21 +273,6 @@ public class Application.Contact : Geary.BaseObject {
         );
     }
 
-    /** Returns the avatar for this contact. */
-    public async Gdk.Pixbuf? load_avatar(Geary.RFC822.MailboxAddress source,
-                                         int pixel_size,
-                                         GLib.Cancellable cancellable)
-        throws GLib.Error {
-        Gdk.Pixbuf? avatar = null;
-        ContactStore? store = this.store;
-        if (store != null) {
-            avatar = yield store.avatars.load(
-                this, source, pixel_size, cancellable
-            );
-        }
-        return avatar;
-    }
-
     /** Sets remote resource loading for this contact. */
     public async void set_remote_resource_loading(bool enabled,
                                                   GLib.Cancellable? cancellable)
@@ -332,8 +325,13 @@ public class Application.Contact : Geary.BaseObject {
             Geary.RFC822.MailboxAddress.is_valid_address(name);
     }
 
+    private void on_individual_avatar_notify() {
+        notify_property("avatar");
+    }
+
     private void update_from_individual(Folks.Individual? replacement) {
         if (this.individual != null) {
+            this.individual.notify["avatar"].disconnect(this.on_individual_avatar_notify);
             this.individual.notify.disconnect(this.on_individual_notify);
             this.individual.removed.disconnect(this.on_individual_removed);
         }
@@ -341,6 +339,7 @@ public class Application.Contact : Geary.BaseObject {
         this.individual = replacement;
 
         if (this.individual != null) {
+            this.individual.notify["avatar"].connect(this.on_individual_avatar_notify);
             this.individual.notify.connect(this.on_individual_notify);
             this.individual.removed.connect(this.on_individual_removed);
         }
diff --git a/src/client/application/application-controller.vala 
b/src/client/application/application-controller.vala
index 4bb2f631f..e6c5dfe46 100644
--- a/src/client/application/application-controller.vala
+++ b/src/client/application/application-controller.vala
@@ -73,9 +73,6 @@ internal class Application.Controller :
         get; private set;
     }
 
-    // Avatar store for the application.
-    private Application.AvatarStore avatars = new Application.AvatarStore();
-
     // Primary collection of the application's open accounts
     private Gee.Map<Geary.AccountInformation,AccountContext> accounts =
         new Gee.HashMap<Geary.AccountInformation,AccountContext>();
@@ -317,7 +314,6 @@ internal class Application.Controller :
         } catch (GLib.Error err) {
             warning("Error closing plugin manager: %s", err.message);
         }
-        this.avatars.close();
         this.pending_mailtos.clear();
         this.composer_widgets.clear();
 
@@ -983,7 +979,7 @@ internal class Application.Controller :
             account,
             new Geary.App.SearchFolder(account, account.local_folder_root),
             new Geary.App.EmailStore(account),
-            new Application.ContactStore(account, this.folks, this.avatars)
+            new Application.ContactStore(account, this.folks)
         );
         this.accounts.set(account.information, context);
 
diff --git a/src/client/conversation-viewer/conversation-contact-popover.vala 
b/src/client/conversation-viewer/conversation-contact-popover.vala
index 97d27bb19..1ec220f1a 100644
--- a/src/client/conversation-viewer/conversation-contact-popover.vala
+++ b/src/client/conversation-viewer/conversation-contact-popover.vala
@@ -43,7 +43,8 @@ public class Conversation.ContactPopover : Gtk.Popover {
 
     [GtkChild] private unowned Gtk.Grid contact_pane;
 
-    [GtkChild] private unowned Gtk.Image avatar;
+    [GtkChild]
+    private Hdy.Avatar avatar;
 
     [GtkChild] private unowned Gtk.Label contact_name;
 
@@ -82,6 +83,16 @@ public class Conversation.ContactPopover : Gtk.Popover {
 
         this.load_remote_button.role = CHECK;
 
+        this.contact.bind_property("display-name",
+                                   this.avatar,
+                                   "text",
+                                   BindingFlags.SYNC_CREATE);
+
+        this.contact.bind_property("avatar",
+                                   this.avatar,
+                                   "loadable-icon",
+                                   BindingFlags.SYNC_CREATE);
+
         this.actions.add_action_entries(ACTION_ENTRIES, this);
         insert_action_group(ACTION_GROUP, this.actions);
 
@@ -92,32 +103,6 @@ public class Conversation.ContactPopover : Gtk.Popover {
     /**
      * Starts loading the avatar for the message's sender.
      */
-    public async void load_avatar() {
-        var main = this.get_toplevel() as Application.MainWindow;
-        if (main != null) {
-            int window_scale = get_scale_factor();
-            int pixel_size = (
-                Application.Client.AVATAR_SIZE_PIXELS * window_scale
-            );
-            try {
-                Gdk.Pixbuf? avatar_buf = yield contact.load_avatar(
-                    this.mailbox,
-                    pixel_size,
-                    this.load_cancellable
-                );
-                if (avatar_buf != null) {
-                    this.avatar.set_from_surface(
-                        Gdk.cairo_surface_create_from_pixbuf(
-                            avatar_buf, window_scale, get_window()
-                        )
-                    );
-                }
-            } catch (GLib.Error err) {
-                debug("Conversation load failed: %s", err.message);
-            }
-        }
-    }
-
     public override void destroy() {
         this.contact.changed.disconnect(this.on_contact_changed);
         this.load_cancellable.cancel();
diff --git a/src/client/conversation-viewer/conversation-message.vala 
b/src/client/conversation-viewer/conversation-message.vala
index b987dbdd6..becf3bf77 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -335,7 +335,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
 
     private GLib.DateTime? local_date = null;
 
-    [GtkChild] private unowned Gtk.Image avatar;
+    [GtkChild] private unowned Hdy.Avatar avatar;
 
     [GtkChild] private unowned Gtk.Revealer compact_revealer;
     [GtkChild] private unowned Gtk.Label compact_from;
@@ -822,31 +822,18 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
                     this.primary_originator, cancellable
                 );
 
-                int window_scale = get_scale_factor();
-                int pixel_size =
-                    Application.Client.AVATAR_SIZE_PIXELS * window_scale;
-                Gdk.Pixbuf? avatar_buf = yield this.primary_contact.load_avatar(
-                    this.primary_originator,
-                    pixel_size,
-                    cancellable
-                );
-                if (avatar_buf != null) {
-                    this.avatar.set_from_surface(
-                        Gdk.cairo_surface_create_from_pixbuf(
-                            avatar_buf, window_scale, get_window()
-                        )
-                    );
+                if (this.primary_contact != null) {
+                    this.primary_contact.bind_property("display-name",
+                                                       this.avatar,
+                                                       "text",
+                                                       BindingFlags.SYNC_CREATE);
+                    this.primary_contact.bind_property("avatar",
+                                                       this.avatar,
+                                                       "loadable-icon",
+                                                       BindingFlags.SYNC_CREATE);
                 }
-            } else {
-                this.avatar.set_from_icon_name(
-                    "avatar-default-symbolic", Gtk.IconSize.DIALOG
-                );
-                this.avatar.set_pixel_size(
-                    Application.Client.AVATAR_SIZE_PIXELS
-                );
             }
 
-
             // Preview headers
             this.compact_from.set_text(
                 yield format_originator_compact(cancellable)
@@ -1268,7 +1255,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
                 address_child.contact,
                 address
             );
-            popover.load_avatar.begin();
             popover.set_position(Gtk.PositionType.BOTTOM);
             popover.load_remote_resources_changed.connect((enabled) => {
                     if (this.primary_contact.equal_to(address_child.contact) &&
diff --git a/src/client/meson.build b/src/client/meson.build
index f20fe5c83..11cf375f5 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -14,7 +14,6 @@ client_vala_sources = files(
   'application/application-account-context.vala',
   'application/application-account-interface.vala',
   'application/application-attachment-manager.vala',
-  'application/application-avatar-store.vala',
   'application/application-certificate-manager.vala',
   'application/application-client.vala',
   'application/application-command.vala',
diff --git a/src/client/plugin/desktop-notifications/desktop-notifications.vala 
b/src/client/plugin/desktop-notifications/desktop-notifications.vala
index 68dfa6185..255e4ec7e 100644
--- a/src/client/plugin/desktop-notifications/desktop-notifications.vala
+++ b/src/client/plugin/desktop-notifications/desktop-notifications.vala
@@ -97,7 +97,7 @@ public class Plugin.DesktopNotifications :
                                                Email email
     ) throws GLib.Error {
         string title = to_notitication_title(folder.account, total);
-        Gdk.Pixbuf? icon = null;
+        GLib.Icon icon = null;
         Geary.RFC822.MailboxAddress? originator = email.get_primary_originator();
         if (originator != null) {
             ContactStore contacts =
@@ -112,19 +112,7 @@ public class Plugin.DesktopNotifications :
                 : originator.to_short_display()
             );
 
-            int window_scale = 1;
-            Gdk.Display? display = Gdk.Display.get_default();
-            if (display != null) {
-                Gdk.Monitor? monitor = display.get_primary_monitor();
-                if (monitor != null) {
-                    window_scale = monitor.scale_factor;
-                }
-            }
-            icon = yield contact.load_avatar(
-                originator,
-                global::Application.Client.AVATAR_SIZE_PIXELS * window_scale,
-                this.cancellable
-            );
+            icon = contact.avatar;
         }
 
         string body = Util.Email.strip_subject_prefixes(email);
@@ -144,10 +132,24 @@ public class Plugin.DesktopNotifications :
             );
         }
 
+        int window_scale = 1;
+        Gdk.Display? display = Gdk.Display.get_default();
+        if (display != null) {
+          Gdk.Monitor? monitor = display.get_primary_monitor();
+          if (monitor != null) {
+            window_scale = monitor.scale_factor;
+          }
+        }
+
+        var avatar = new Hdy.Avatar(32, title, true);
+        avatar.loadable_icon = icon as GLib.LoadableIcon;
+        icon = yield avatar.draw_to_pixbuf_async(32, window_scale, null);
+
         issue_arrived_notification(title, body, icon, folder, email.identifier);
     }
 
     private void notify_general(Folder folder, int total, int added) {
+        GLib.Icon icon = new GLib.ThemedIcon("%s-symbolic".printf(global::Application.Client.APP_ID));
         string title = to_notitication_title(folder.account, total);
         string body = ngettext(
             /// Notification body when multiple messages have been
@@ -170,12 +172,12 @@ public class Plugin.DesktopNotifications :
             ).printf(body, total);
         }
 
-        issue_arrived_notification(title, body, null, folder, null);
+        issue_arrived_notification(title, body, icon, folder, null);
     }
 
     private void issue_arrived_notification(string summary,
                                             string body,
-                                            Gdk.Pixbuf? icon,
+                                            GLib.Icon icon,
                                             Folder folder,
                                             EmailIdentifier? id) {
         // only one outstanding notification at a time
@@ -204,15 +206,9 @@ public class Plugin.DesktopNotifications :
     private GLib.Notification issue_notification(string id,
                                                  string summary,
                                                  string body,
-                                                 Gdk.Pixbuf? avatar,
+                                                 GLib.Icon icon,
                                                  string? action,
                                                  GLib.Variant? action_target) {
-        GLib.Icon icon = avatar;
-        if (avatar == null) {
-            icon = new GLib.ThemedIcon(
-                "%s-symbolic".printf(global::Application.Client.APP_ID)
-            );
-        }
         GLib.Notification notification = new GLib.Notification(summary);
         notification.set_body(body);
         notification.set_icon(icon);
diff --git a/test/client/composer/composer-widget-test.vala b/test/client/composer/composer-widget-test.vala
index 6b31c9435..cdbcd3d61 100644
--- a/test/client/composer/composer-widget-test.vala
+++ b/test/client/composer/composer-widget-test.vala
@@ -125,8 +125,7 @@ public class Composer.WidgetTest : TestCase {
             new Geary.App.EmailStore(mock_account),
             new Application.ContactStore(
                 mock_account,
-                Folks.IndividualAggregator.dup(),
-                new Application.AvatarStore()
+                Folks.IndividualAggregator.dup()
             )
         );
     }
diff --git a/ui/conversation-contact-popover.ui b/ui/conversation-contact-popover.ui
index 113f718c6..6030fee15 100644
--- a/ui/conversation-contact-popover.ui
+++ b/ui/conversation-contact-popover.ui
@@ -60,9 +60,11 @@
                   </packing>
                 </child>
                 <child>
-                  <object class="GtkImage" id="avatar">
+                  <object class="HdyAvatar" id="avatar">
                     <property name="visible">True</property>
-                    <property name="pixel_size">48</property>
+                    <property name="can_focus">False</property>
+                    <property name="show-initials">True</property>
+                    <property name="size">48</property>
                   </object>
                   <packing>
                     <property name="left_attach">0</property>
diff --git a/ui/conversation-message.ui b/ui/conversation-message.ui
index 769a3e5f6..c6afd79c4 100644
--- a/ui/conversation-message.ui
+++ b/ui/conversation-message.ui
@@ -2,6 +2,7 @@
 <!-- Generated with glade 3.22.2 -->
 <interface>
   <requires lib="gtk+" version="3.14"/>
+  <requires lib="libhandy" version="1.0"/>
   <template class="ConversationMessage" parent="GtkGrid">
     <property name="visible">True</property>
     <property name="orientation">vertical</property>
@@ -11,12 +12,11 @@
         <property name="hexpand">True</property>
         <property name="column_spacing">6</property>
         <child>
-          <object class="GtkImage" id="avatar">
-            <property name="width_request">18</property>
-            <property name="height_request">18</property>
+          <object class="HdyAvatar" id="avatar">
             <property name="visible">True</property>
             <property name="valign">start</property>
-            <property name="pixel_size">48</property>
+            <property name="show-initials">True</property>
+            <property name="size">48</property>
           </object>
           <packing>
             <property name="left_attach">0</property>


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