diff options
author | Christopher Davis <brainblasted@disroot.org> | 2020-10-03 15:30:13 -0700 |
---|---|---|
committer | Christopher Davis <brainblasted@disroot.org> | 2020-10-03 16:32:31 -0700 |
commit | 906f3f948ee29f223182fea7cf2d9b0a8e5eeacc (patch) | |
tree | 9e8fa036cb2064456660ed5919a7d58218ae1c58 | |
parent | 464ccd0da48019b8ef03c1cd50b5458103ea6b90 (diff) | |
download | gnome-contacts-wip/christopherdavis/hdy-avatar.tar.gz |
avatar: Use HdyAvatarwip/christopherdavis/hdy-avatar
Makes Contacts.Avatar a wrapper around HdyAvatar.
This allows us to drop our custom fallback and
circular avatar code in favor of HdyAvatar.
Fixes https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/183
Related to https://gitlab.gnome.org/GNOME/Initiatives/-/issues/20
-rw-r--r-- | src/contacts-avatar-selector.vala | 3 | ||||
-rw-r--r-- | src/contacts-avatar-utils.vala | 183 | ||||
-rw-r--r-- | src/contacts-avatar.vala | 106 | ||||
-rw-r--r-- | src/meson.build | 1 |
4 files changed, 32 insertions, 261 deletions
diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala index e2e9c1c..5e6a160 100644 --- a/src/contacts-avatar-selector.vala +++ b/src/contacts-avatar-selector.vala @@ -119,8 +119,7 @@ public class Contacts.AvatarSelector : Popover { private FlowBoxChild create_thumbnail (Gdk.Pixbuf source_pixbuf) { var avatar = new Avatar (ICONS_SIZE); - var pixbuf = source_pixbuf.scale_simple (ICONS_SIZE, ICONS_SIZE, Gdk.InterpType.HYPER); - avatar.set_pixbuf (pixbuf); + avatar.set_pixbuf (source_pixbuf); var button = new Button (); button.get_style_context ().add_class (AVATAR_BUTTON_CSS_NAME); diff --git a/src/contacts-avatar-utils.vala b/src/contacts-avatar-utils.vala deleted file mode 100644 index c5c6d61..0000000 --- a/src/contacts-avatar-utils.vala +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 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. - */ - -namespace Contacts.AvatarUtils { - - // The following was based on code written by Felipe Borges for - // gnome-control-enter in panels/user-accounts/user-utils.c commit - // 02c288ab6f069a0c106323a93400f192a63cb67e. The copyright in that - // file is: "Copyright 2009-2010 Red Hat, Inc," - - public Gdk.Pixbuf generate_user_picture(string name, int size, bool label = true) { - Cairo.Surface surface = new Cairo.ImageSurface( - Cairo.Format.ARGB32, size, size - ); - Cairo.Context cr = new Cairo.Context(surface); - cr.rectangle(0, 0, size, size); - - /* Fill the background with a colour for the name */ - Gdk.RGBA color = get_color_for_name(name); - cr.set_source_rgb( - color.red / 255.0, color.green / 255.0, color.blue / 255.0 - ); - cr.fill(); - - /* Draw the initials on top */ - if (label) { - string? initials = extract_initials_from_name(name); - if (initials != null) { - string font = "Cantarell Ultra-Bold %d".printf((int) GLib.Math.ceil(size / 3)); - - cr.set_source_rgb(1.0, 1.0, 1.0); - Pango.Layout layout = Pango.cairo_create_layout(cr); - layout.set_text(initials, -1); - layout.set_font_description(Pango.FontDescription.from_string(font)); - - int width, height; - layout.get_size(out width, out height); - cr.translate(size / 2, size / 2); - cr.move_to( - -((double) width / Pango.SCALE) / 2, - -((double) height / Pango.SCALE) / 2 - ); - Pango.cairo_show_layout(cr, layout); - } - } else { - try { - var theme = Gtk.IconTheme.get_default (); - var fallback_avatar = theme.lookup_icon ("avatar-default", - size * 1/2, - Gtk.IconLookupFlags.FORCE_SYMBOLIC); - Gdk.RGBA fg_color = { 1, 1, 1, 1 }; - var icon_pixbuf = fallback_avatar.load_symbolic (fg_color); - var x = (double) size / 2.0 - (double) icon_pixbuf.width / 2.0; - // We also add a offset to the height to visually center the icon - var y = (double) size / 2.0 - (double) icon_pixbuf.height / 2.0 - (2 * size / 100.0); - Gdk.cairo_set_source_pixbuf (cr, icon_pixbuf, x, y); - cr.paint (); - } catch (Error e) { - warning ("Couldn't get default avatar icon: %s", e.message); - } - } - - return Gdk.pixbuf_get_from_surface( - surface, 0, 0, size, size - ); - } - - public Gdk.Pixbuf round_image(Gdk.Pixbuf source) { - int size = source.width; - Cairo.Surface surface = new Cairo.ImageSurface( - Cairo.Format.ARGB32, size, size - ); - Cairo.Context cr = new Cairo.Context(surface); - - /* Clip a circle */ - cr.arc(size / 2, size / 2, size / 2, 0, 2 * GLib.Math.PI); - cr.clip(); - cr.new_path(); - - Gdk.cairo_set_source_pixbuf(cr, source, 0, 0); - cr.paint(); - - return Gdk.pixbuf_get_from_surface( - surface, 0, 0, size, size - ); - } - - public string? extract_initials_from_name(string name) { - string normalized = name.strip().up().normalize(); - string? initials = null; - if (normalized != "") { - GLib.StringBuilder buf = new GLib.StringBuilder(); - unichar c = 0; - int index = 0; - - // Get the first alphanumeric char of the string - for (int i = 0; normalized.get_next_char(ref index, out c); i++) { - if (c.isalnum()) { - buf.append_unichar(c); - break; - } - } - - // Get the first alphanumeric char of the last word of the string - index = normalized.last_index_of_char(' '); - if (index >= 0) { - for (int i = 0; normalized.get_next_char(ref index, out c); i++) { - if (c.isalnum()) { - buf.append_unichar(c); - break; - } - } - } - - if (buf.data.length > 0) { - initials = (string) buf.data; - } - } - return initials; - } - - - public Gdk.RGBA get_color_for_name(string name) { - // https://gitlab.gnome.org/Community/Design/HIG-app-icons/blob/master/GNOME%20HIG.gpl - const double[,] GNOME_COLOR_PALETTE = { - { 98, 160, 234 }, - { 53, 132, 228 }, - { 28, 113, 216 }, - { 26, 95, 180 }, - { 87, 227, 137 }, - { 51, 209, 122 }, - { 46, 194, 126 }, - { 38, 162, 105 }, - { 248, 228, 92 }, - { 246, 211, 45 }, - { 245, 194, 17 }, - { 229, 165, 10 }, - { 255, 163, 72 }, - { 255, 120, 0 }, - { 230, 97, 0 }, - { 198, 70, 0 }, - { 237, 51, 59 }, - { 224, 27, 36 }, - { 192, 28, 40 }, - { 165, 29, 45 }, - { 192, 97, 203 }, - { 163, 71, 186 }, - { 129, 61, 156 }, - { 97, 53, 131 }, - { 181, 131, 90 }, - { 152, 106, 68 }, - { 134, 94, 60 }, - { 99, 69, 44 } - }; - - Gdk.RGBA color = { 255, 255, 255, 1.0 }; - uint hash; - uint number_of_colors = GNOME_COLOR_PALETTE.length[0]; - uint idx; - - if (name == "") { - // Return a random color if we don't have a name - idx = Random.int_range (0, (int32) number_of_colors); - color.red = GNOME_COLOR_PALETTE[idx,0]; - color.green = GNOME_COLOR_PALETTE[idx,1]; - color.blue = GNOME_COLOR_PALETTE[idx,2]; - return color; - } - - hash = name.hash(); - idx = hash % number_of_colors; - - color.red = GNOME_COLOR_PALETTE[idx,0]; - color.green = GNOME_COLOR_PALETTE[idx,1]; - color.blue = GNOME_COLOR_PALETTE[idx,2]; - - return color; - } -} diff --git a/src/contacts-avatar.vala b/src/contacts-avatar.vala index 9f54217..fb758df 100644 --- a/src/contacts-avatar.vala +++ b/src/contacts-avatar.vala @@ -23,29 +23,31 @@ using Gee; * The Avatar of a Contact is responsible for showing an {@link Folks.Individual}'s * avatar, or a fallback if it's not available. */ -public class Contacts.Avatar : DrawingArea { - private int size; - private Gdk.Pixbuf? pixbuf = null; - private Gdk.Pixbuf? cache = null; +public class Contacts.Avatar : Bin { + private Hdy.Avatar widget; private Individual? individual = 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; public Avatar (int size, Individual? individual = null) { this.individual = individual; - if (individual != null) { - individual.notify["avatar"].connect ( (s, p) => { - load_avatar.begin (); - }); + string name = ""; + bool show_initials = false; + if (this.individual != null) { + name = find_display_name (); + /* If we don't have a usable name use the display_name + * to generate the color but don't show any label + */ + if (name == "") { + name = this.individual.display_name; + } else { + show_initials = true; + } } - this.size = size; - set_size_request (size, size); - - // If we don't have an avatar, don't try to load it later - this.avatar_loaded = (individual == null || individual.avatar == null); + this.widget = new Hdy.Avatar (size, name, show_initials); + this.widget.set_image_load_func (size => load_avatar (size)); + this.widget.show (); + add(this.widget); show (); } @@ -54,69 +56,23 @@ public class Contacts.Avatar : DrawingArea { * Manually set the avatar to the given pixbuf, even if the contact has an avatar. */ public void set_pixbuf (Gdk.Pixbuf? a_pixbuf) { - this.cache = null; - this.pixbuf = a_pixbuf; - queue_draw (); - } - - private async void load_avatar () { - assert (this.individual != null); - - this.avatar_loaded = true; - try { - var stream = yield this.individual.avatar.load_async (this.size); - this.cache = null; - 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.individual.display_name, e.message); - } - } - - public override bool draw (Cairo.Context cr) { - // 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.cache != null) { - // Don't do anything if we have already a cached avatar - } else if (this.pixbuf != null) - this.cache = create_contact_avatar (); - else // No avatar or cache available, create the fallback - this.cache = create_fallback (); - - draw_cached_avatar (cr); - - return true; - } - - private void draw_cached_avatar (Cairo.Context cr) { - Gdk.cairo_set_source_pixbuf (cr, this.cache, 0, 0); - cr.paint (); + this.widget.set_image_load_func (size => load_avatar (size, a_pixbuf)); } - private Gdk.Pixbuf create_contact_avatar () { - return AvatarUtils.round_image(this.pixbuf); - } - - private Gdk.Pixbuf create_fallback () { - string name = ""; - bool show_label = false; - if (this.individual != null) { - name = find_display_name (); - /* If we don't have a usable name use the display_name - * to generate the color but don't show any label - */ - if (name == "") { - name = this.individual.display_name; - } else { - show_label = true; + private Gdk.Pixbuf? load_avatar (int size, Gdk.Pixbuf? pixbuf = null) { + if (pixbuf != null) { + return pixbuf.scale_simple (size, size, Gdk.InterpType.HYPER); + } else { + if (this.individual != null && this.individual.avatar != null) { + try { + var stream = this.individual.avatar.load (size, null); + return new Gdk.Pixbuf.from_stream_at_scale (stream, size, size, true); + } catch (Error e) { + debug ("Couldn't load avatar of contact %s. Reason: %s", this.individual.display_name, e.message); + } } } - var pixbuf = AvatarUtils.generate_user_picture(name, this.size, show_label); - pixbuf = AvatarUtils.round_image(pixbuf); - - return pixbuf; + return null; } /* Find a nice name to generate the label and color for the fallback avatar diff --git a/src/meson.build b/src/meson.build index 63b2847..a38b262 100644 --- a/src/meson.build +++ b/src/meson.build @@ -13,7 +13,6 @@ libcontacts_sources = files( 'contacts-typeset.vala', 'contacts-type-descriptor.vala', 'contacts-utils.vala', - 'contacts-avatar-utils.vala', 'contacts-vcard-type-mapping.vala', ) |