[geary/wip/3.32-avatars: 38/40] Port GNOME 3.32 avatar code to vala, use when Folks avatar is missing



commit e51d122e4a01407228aa24248b24d84a864f4763
Author: Michael Gratton <mike vee net>
Date:   Fri Mar 1 13:02:43 2019 +1100

    Port GNOME 3.32 avatar code to vala, use when Folks avatar is missing
    
    This ports the code written by Felipe Borges for GNOME/Initiatives#6 to
    vala, and uses that when no Folks individual was found or it does not
    have an avatar.

 po/POTFILES.in                                     |   1 +
 .../application/application-avatar-store.vala      |  26 ++++
 src/client/meson.build                             |   1 +
 src/client/util/util-avatar.vala                   | 140 +++++++++++++++++++++
 4 files changed, 168 insertions(+)
---
diff --git a/po/POTFILES.in b/po/POTFILES.in
index 92f7e71e..4030f724 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -87,6 +87,7 @@ src/client/sidebar/sidebar-common.vala
 src/client/sidebar/sidebar-count-cell-renderer.vala
 src/client/sidebar/sidebar-entry.vala
 src/client/sidebar/sidebar-tree.vala
+src/client/util/util-avatar.vala
 src/client/util/util-date.vala
 src/client/util/util-email.vala
 src/client/util/util-files.vala
diff --git a/src/client/application/application-avatar-store.vala 
b/src/client/application/application-avatar-store.vala
index 1a334c53..6d3d9402 100644
--- a/src/client/application/application-avatar-store.vala
+++ b/src/client/application/application-avatar-store.vala
@@ -81,9 +81,35 @@ public class Application.AvatarStore : Geary.BaseObject {
                     pixbuf = yield new Gdk.Pixbuf.from_stream_at_scale_async(
                         data, pixel_size, pixel_size, true, cancellable
                     );
+                    pixbuf = Util.Avatar.round_image(pixbuf);
                     this.pixbufs.add(pixbuf);
                 }
             }
+
+            if (pixbuf == null) {
+                string? name = null;
+                // XXX should really be using the folks display name
+                // here as below, but since we should the name from
+                // the email address if present in
+                // ConversationMessage, and since that might not match
+                // the folks display name, it is confusing when the
+                // initials are one thing and the name is
+                // another. Re-enable below when we start using the
+                // folks display name in ConversationEmail
+                name = this.mailbox.to_short_display();
+                // if (this.individual != null) {
+                //     name = this.individual.display_name;
+                // } else {
+                //     // Use short display because it will clean up the
+                //     // string, use the name if present and fall back
+                //     // on the address if not.
+                //     name = this.mailbox.to_short_display();
+                // }
+                pixbuf = Util.Avatar.generate_user_picture(name, pixel_size);
+                pixbuf = Util.Avatar.round_image(pixbuf);
+                this.pixbufs.add(pixbuf);
+            }
+
             return pixbuf;
         }
 
diff --git a/src/client/meson.build b/src/client/meson.build
index b7f64b1b..7eb97653 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -91,6 +91,7 @@ geary_client_vala_sources = files(
   'sidebar/sidebar-entry.vala',
   'sidebar/sidebar-tree.vala',
 
+  'util/util-avatar.vala',
   'util/util-date.vala',
   'util/util-email.vala',
   'util/util-files.vala',
diff --git a/src/client/util/util-avatar.vala b/src/client/util/util-avatar.vala
new file mode 100644
index 00000000..21ce4ab8
--- /dev/null
+++ b/src/client/util/util-avatar.vala
@@ -0,0 +1,140 @@
+/*
+ * 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 Util.Avatar {
+
+    // The following was ported from 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) {
+        string initials = extract_initials_from_name(name);
+        string font = "Sans %d".printf((int) GLib.Math.ceil(size / 2.5));
+        Gdk.RGBA color = get_color_for_name(name);
+
+        Cairo.Surface surface = new Cairo.ImageSurface(
+            Cairo.Format.ARGB32, size, size
+        );
+        Cairo.Context cr = new Cairo.Context(surface);
+        cr.rectangle(0, 0, size, size);
+        cr.set_source_rgb(
+            color.red / 255.0, color.green / 255.0, color.blue / 255.0
+        );
+        cr.fill();
+
+        /* Draw the initials on top */
+        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);
+        
+        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();
+            buf.append_unichar(normalized.get_char(0));
+
+            int index = normalized.last_index_of_char(' ');
+            if (index != -1 && (index + 1) < normalized.length) {
+                buf.append_unichar(normalized.get_char(index + 1));
+            }
+            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[,3] 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;
+        uint idx;
+
+        if (name == "") {
+            return color;
+        }
+
+        hash = name.hash();
+        number_of_colors = GNOME_COLOR_PALETTE.length[0];
+        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;
+    }
+
+}


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