summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristopher Davis <brainblasted@disroot.org>2020-10-03 15:30:13 -0700
committerChristopher Davis <brainblasted@disroot.org>2020-10-03 16:32:31 -0700
commit906f3f948ee29f223182fea7cf2d9b0a8e5eeacc (patch)
tree9e8fa036cb2064456660ed5919a7d58218ae1c58
parent464ccd0da48019b8ef03c1cd50b5458103ea6b90 (diff)
downloadgnome-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.vala3
-rw-r--r--src/contacts-avatar-utils.vala183
-rw-r--r--src/contacts-avatar.vala106
-rw-r--r--src/meson.build1
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',
)