[gnome-contacts] editor: Make sure saving an avatar works again



commit a7d27b5189136a57709c9059a24c0e910c3fb5f7
Author: Niels De Graef <nielsdegraef gmail com>
Date:   Thu Jan 13 12:26:56 2022 +0100

    editor: Make sure saving an avatar works again

 data/ui/contacts-avatar-selector.ui |  5 +-
 src/contacts-avatar-selector.vala   | 97 +++++++++++++++++++++----------------
 src/contacts-avatar.vala            |  8 +++
 src/contacts-contact-editor.vala    | 24 +++++++--
 src/contacts-contact-list.vala      |  5 +-
 5 files changed, 88 insertions(+), 51 deletions(-)
---
diff --git a/data/ui/contacts-avatar-selector.ui b/data/ui/contacts-avatar-selector.ui
index 4872e0d4..6c2a2472 100644
--- a/data/ui/contacts-avatar-selector.ui
+++ b/data/ui/contacts-avatar-selector.ui
@@ -50,8 +50,9 @@
                         <property name="column_spacing">5</property>
                         <property name="row_spacing">5</property>
                         <property name="max_children_per_line">8</property>
-                        <property name="selection_mode">single</property>
-                        <property name="homogeneous">False</property>
+                        <property name="selection-mode">single</property>
+                        <property name="homogeneous">True</property>
+                        <property name="activate-on-single-click">False</property>
                       </object>
                     </child>
                   </object>
diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala
index 59616c02..dfdb7c56 100644
--- a/src/contacts-avatar-selector.vala
+++ b/src/contacts-avatar-selector.vala
@@ -83,15 +83,40 @@ public class Contacts.AvatarSelector : Gtk.Dialog {
 
   private Xdp.Portal? portal = null;
 
+  private Gdk.Pixbuf? _selected_avatar = null;
+  public Gdk.Pixbuf? selected_avatar {
+    owned get { return scale_pixbuf_for_avatar_use (this._selected_avatar); }
+    private set { this._selected_avatar = value; }
+  }
+
   public AvatarSelector (Individual? individual, Gtk.Window? window = null) {
     Object (transient_for: window, use_header_bar: 1);
     this.individual = individual;
 
+    this.thumbnail_grid.selected_children_changed.connect (on_thumbnails_selected);
+    this.thumbnail_grid.child_activated.connect (on_thumbnail_activated);
     update_thumbnail_grid ();
 
     this.setup_camera_portal.begin ();
   }
 
+  private void on_thumbnails_selected (Gtk.FlowBox thumbnail_grid) {
+    var selected = thumbnail_grid.get_selected_children ();
+    if (selected != null) {
+      unowned var thumbnail = (Thumbnail) selected.data;
+      this.selected_avatar = thumbnail.source_pixbuf;
+    } else {
+      this.selected_avatar = null;
+    }
+  }
+
+  private void on_thumbnail_activated (Gtk.FlowBox thumbnail_grid,
+                                       Gtk.FlowBoxChild child) {
+    unowned var thumbnail = (Thumbnail) child;
+    this.selected_avatar = thumbnail.source_pixbuf;
+    this.response (Gtk.ResponseType.ACCEPT);
+  }
+
   private async void setup_camera_portal () {
     this.portal = new Xdp.Portal ();
 
@@ -103,7 +128,10 @@ public class Contacts.AvatarSelector : Gtk.Dialog {
     }
   }
 
-  private Gdk.Pixbuf scale_pixbuf_for_avatar_use (Gdk.Pixbuf pixbuf) {
+  private Gdk.Pixbuf? scale_pixbuf_for_avatar_use (Gdk.Pixbuf? pixbuf) {
+    if (pixbuf == null)
+      return null;
+
     int w = pixbuf.get_width ();
     int h = pixbuf.get_height ();
 
@@ -121,42 +149,37 @@ public class Contacts.AvatarSelector : Gtk.Dialog {
     return pixbuf.scale_simple (w, h, Gdk.InterpType.HYPER);
   }
 
-  private void selected_pixbuf (Gdk.Pixbuf pixbuf) {
-    try {
-      uint8[] buffer;
-      pixbuf.save_to_buffer (out buffer, "png", null);
-      var icon = new BytesIcon (new Bytes (buffer));
-      // Set the new avatar
-      this.individual.change_avatar.begin (icon as LoadableIcon, (obj, res) => {
-        try {
-          this.individual.change_avatar.end (res);
-        } catch (Error e) {
-          warning ("Failed to set avatar: %s", e.message);
-          Utils.show_error_dialog (_("Failed to set avatar."),
-                                   get_root () as Gtk.Window);
-        }
-      });
-    } catch (GLib.Error e) {
-      warning ("Failed to set avatar: %s", e.message);
-      Utils.show_error_dialog (_("Failed to set avatar."),
-                               get_root () as Gtk.Window);
-    }
+  /**
+   * Saves the selected avatar as the one that should be used.
+   *
+   * You should probably only do this after the "response" signal
+   * (with ResponseType.ACCEPT)
+   */
+  public async void save_selection () throws GLib.Error {
+    debug ("Saving selected avatar");
+    uint8[] buffer;
+    this.selected_avatar.save_to_buffer (out buffer, "png", null);
+    var icon = new BytesIcon (new Bytes (buffer));
+    // Set the new avatar
+    yield this.individual.change_avatar (icon as LoadableIcon);
   }
 
   private void update_thumbnail_grid () {
     if (this.individual != null) {
       foreach (var p in individual.personas) {
-        var widget = new Thumbnail.for_persona (p);
-        if (widget.source_pixbuf != null)
-          this.thumbnail_grid.insert (widget, -1);
+        var thumbnail = new Thumbnail.for_persona (p);
+        if (thumbnail.source_pixbuf != null) {
+          this.thumbnail_grid.insert (thumbnail, -1);
+        }
       }
     }
 
     var stock_files = Utils.get_stock_avatars ();
     foreach (var file_name in stock_files) {
-      var widget = new Thumbnail.for_filename (file_name);
-      if (widget.source_pixbuf != null)
-        this.thumbnail_grid.insert (widget, -1);
+      var thumbnail = new Thumbnail.for_filename (file_name);
+      if (thumbnail.source_pixbuf != null) {
+        this.thumbnail_grid.insert (thumbnail, -1);
+      }
     }
   }
 
@@ -168,19 +191,6 @@ public class Contacts.AvatarSelector : Gtk.Dialog {
     // dialog.show ();
   }
 
-  public override void response (int response) {
-    if (response == Gtk.ResponseType.OK) {
-      var selected_children = thumbnail_grid.get_selected_children ();
-      if (selected_children != null) {
-        unowned var thumbnail = (selected_children.data as Thumbnail);
-        if (thumbnail != null)
-          selected_pixbuf (scale_pixbuf_for_avatar_use (thumbnail.source_pixbuf));
-      }
-    }
-
-    this.close ();
-  }
-
   [GtkCallback]
   private void on_file_clicked (Gtk.Button button) {
     var chooser = new Gtk.FileChooserNative (_("Browse for more pictures"),
@@ -213,14 +223,15 @@ public class Contacts.AvatarSelector : Gtk.Dialog {
                                                   get_root () as Gtk.Window);
           dialog.response.connect ((response) => {
               if (response == Gtk.ResponseType.ACCEPT) {
-                var cropped = dialog.create_pixbuf ();
-                selected_pixbuf (scale_pixbuf_for_avatar_use (cropped));
+                this.selected_avatar = dialog.create_pixbuf ();
+                this.response (Gtk.ResponseType.ACCEPT);
               }
               dialog.destroy ();
           });
           dialog.show ();
         } else {
-          selected_pixbuf (scale_pixbuf_for_avatar_use (pixbuf));
+          this.selected_avatar = pixbuf;
+          this.response (Gtk.ResponseType.ACCEPT);
         }
       } catch (GLib.Error e) {
         warning ("Failed to set avatar: %s", e.message);
diff --git a/src/contacts-avatar.vala b/src/contacts-avatar.vala
index 3f8b4bab..330fa8ed 100644
--- a/src/contacts-avatar.vala
+++ b/src/contacts-avatar.vala
@@ -75,6 +75,14 @@ public class Contacts.Avatar : Adw.Bin {
     }
   }
 
+  /**
+   * Forces a reload of the avatar (e.g. after a property change).
+   */
+  public async void reload () {
+    this.load_avatar_started = false;
+    yield this.load_avatar ();
+  }
+
   /**
    * Manually set the avatar to the given pixbuf, even if the contact has an avatar.
    */
diff --git a/src/contacts-contact-editor.vala b/src/contacts-contact-editor.vala
index dd2f764b..805b3c0b 100644
--- a/src/contacts-contact-editor.vala
+++ b/src/contacts-contact-editor.vala
@@ -25,8 +25,8 @@ using Folks;
 public class Contacts.ContactEditor : Gtk.Box {
 
   private Individual individual;
-  private Gtk.Entry name_entry;
-  private Avatar avatar;
+  private unowned Gtk.Entry name_entry;
+  private unowned Avatar avatar;
 
   construct {
     this.orientation = Gtk.Orientation.VERTICAL;
@@ -50,7 +50,8 @@ public class Contacts.ContactEditor : Gtk.Box {
 
   // Creates the contact's current avatar in a big button on top of the Editor
   private Gtk.Widget create_avatar_button () {
-    this.avatar = new Avatar (PROFILE_SIZE, this.individual);
+    var avatar = new Avatar (PROFILE_SIZE, this.individual);
+    this.avatar = avatar;
 
     var button = new Gtk.Button ();
     button.tooltip_text = _("Change avatar");
@@ -63,7 +64,19 @@ public class Contacts.ContactEditor : Gtk.Box {
   // Show the avatar popover when the avatar is clicked
   private void on_avatar_button_clicked (Gtk.Button avatar_button) {
     var avatar_selector = new AvatarSelector (this.individual, get_root () as Gtk.Window);
-    avatar_selector.response.connect (() => {
+    avatar_selector.response.connect ((response) => {
+      if (response == Gtk.ResponseType.ACCEPT) {
+        avatar_selector.save_selection.begin ((obj, res) => {
+          try {
+            avatar_selector.save_selection.end (res);
+            this.avatar.set_pixbuf (avatar_selector.selected_avatar);
+          } catch (Error e) {
+            warning ("Failed to set avatar: %s", e.message);
+            Utils.show_error_dialog (_("Failed to set avatar."),
+                                     get_root () as Gtk.Window);
+          }
+        });
+      }
       avatar_selector.destroy ();
     });
     avatar_selector.show ();
@@ -72,7 +85,8 @@ public class Contacts.ContactEditor : Gtk.Box {
   // Creates the big name entry on the top
   private Gtk.Widget create_name_entry () {
     NameDetails name = this.individual as NameDetails;
-    this.name_entry = new Gtk.Entry ();
+    var entry = new Gtk.Entry ();
+    this.name_entry = entry;
     this.name_entry.hexpand = true;
     this.name_entry.valign = Gtk.Align.CENTER;
     this.name_entry.input_purpose = Gtk.InputPurpose.NAME;
diff --git a/src/contacts-contact-list.vala b/src/contacts-contact-list.vala
index 247e7aaf..edce740d 100644
--- a/src/contacts-contact-list.vala
+++ b/src/contacts-contact-list.vala
@@ -380,7 +380,10 @@ public class Contacts.ContactList : Adw.Bin {
     }
 
     private void on_contact_changed (Object obj, ParamSpec pspec) {
-      //TODO: Update also the Avatar
+      if (pspec.get_name () == "avatar") {
+        this.avatar.reload ();
+      }
+      // Always update the label, since it can depend on a lot of properties
       this.label.set_text (this.individual.display_name);
       changed ();
     }


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