Commit 3daaca5a authored by Julian Sparber's avatar Julian Sparber
Browse files

debian: backport upstream changes since 3.38 release

parent a53b4d6f
Pipeline #62155 failed with stages
in 5 minutes and 50 seconds
From f40524f205a9d4180220d31dcc536653452c4632 Mon Sep 17 00:00:00 2001
From: Christopher Davis <brainblasted@disroot.org>
Date: Sat, 3 Oct 2020 15:30:13 -0700
Subject: [PATCH 03/42] avatar: Use HdyAvatar
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
---
src/contacts-avatar-selector.vala | 3 +-
src/contacts-avatar-utils.vala | 183 ------------------------------
src/contacts-avatar.vala | 106 +++++------------
src/meson.build | 1 -
4 files changed, 32 insertions(+), 261 deletions(-)
delete mode 100644 src/contacts-avatar-utils.vala
diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala
index e2e9c1cf..5e6a1600 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 c5c6d61d..00000000
--- 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 9f542170..fb758dfb 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 63b28478..a38b2629 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',
)
--
2.29.2
From 3f4bfdb650554eb8dd202b1feee41d63905db8f4 Mon Sep 17 00:00:00 2001
From: Christopher Davis <brainblasted@disroot.org>
Date: Sat, 3 Oct 2020 16:12:11 -0700
Subject: [PATCH 06/42] window: Use HdyWindow
Allows us to drop the use of HdyTitleBar.
---
data/ui/contacts-window.ui | 131 +++++++++++++++++++------------------
src/contacts-window.vala | 25 +++++--
2 files changed, 86 insertions(+), 70 deletions(-)
diff --git a/data/ui/contacts-window.ui b/data/ui/contacts-window.ui
index 0c2d3d5b..aa858e80 100644
--- a/data/ui/contacts-window.ui
+++ b/data/ui/contacts-window.ui
@@ -136,7 +136,7 @@
</object>
</child>
</object>
- <template class="ContactsWindow" parent="GtkApplicationWindow">
+ <template class="ContactsWindow" parent="HdyApplicationWindow">
<property name="can_focus">False</property>
<property name="default_width">800</property>
<property name="default_height">600</property>
@@ -144,9 +144,10 @@
<property name="title" translatable="yes">Contacts</property>
<signal name="key-press-event" handler="key_press_event_cb" object="ContactsWindow" after="yes" swapped="no"/>
<signal name="delete-event" handler="delete_event_cb" object="ContactsWindow" after="no" swapped="no"/>
- <child type="titlebar">
- <object class="HdyTitleBar" id="titlebar">
+ <child>
+ <object class="GtkBox">
<property name="visible">True</property>
+ <property name="orientation">vertical</property>
<child>
<object class="HdyLeaflet" id="header">
<property name="visible">True</property>
@@ -155,7 +156,7 @@
<property name="child-transition-duration" bind-source="content_box" bind-property="child-transition-duration" bind-flags="bidirectional|sync-create"/>
<property name="transition-type" bind-source="content_box" bind-property="transition-type" bind-flags="bidirectional|sync-create"/>
<child>
- <object class="GtkHeaderBar" id="left_header">
+ <object class="HdyHeaderBar" id="left_header">
<property name="visible">True</property>
<property name="hexpand">False</property>
<property name="can_focus">False</property>
@@ -193,7 +194,7 @@
<property name="can_focus">True</property>
<property name="focus_on_click">False</property>
<property name="popover">hamburger_menu_popover</property>
- <accelerator key="F10" signal="clicked"/>
+ <accelerator key="F10" signal="clicked"/>
<child>
<object class="GtkImage">
<property name="visible">True</property>
@@ -235,7 +236,7 @@
</packing>
</child>
<child>
- <object class="GtkHeaderBar" id="right_header">
+ <object class="HdyHeaderBar" id="right_header">
<property name="visible">True</property>
<property name="hexpand">True</property>
<property name="show_close_button">True</property>
@@ -350,82 +351,82 @@
</child>
</object>
</child>
- </object>
- </child>
- <child>
- <object class="GtkOverlay" id="notification_overlay">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
<child>
- <object class="HdyLeaflet" id="content_box">
+ <object class="GtkOverlay" id="notification_overlay">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="can-swipe-back">True</property>
- <signal name="notify::folded" handler="on_folded" object="ContactsWindow" after="yes" swapped="no"/>
- <signal name="notify::child-transition-running" handler="on_child_transition_running" object="ContactsWindow" after="yes" swapped="no"/>
<child>
- <object class="GtkStack" id="list_pane_stack">
+ <object class="HdyLeaflet" id="content_box">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="hexpand">False</property>
+ <property name="can-swipe-back">True</property>
+ <signal name="notify::folded" handler="on_folded" object="ContactsWindow" after="yes" swapped="no"/>
+ <signal name="notify::child-transition-running" handler="on_child_transition_running" object="ContactsWindow" after="yes" swapped="no"/>
<child>
- <object class="GtkBox">
+ <object class="GtkStack" id="list_pane_stack">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="orientation">vertical</property>
- <property name="width_request">300</property>
- <property name="homogeneous">True</property>
+ <property name="hexpand">False</property>
<child>
- <object class="GtkSpinner">
+ <object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
- <property name="active">True</property>
- <property name="valign">end</property>
- <property name="halign">center</property>
- <style>
- <class name="contacts-watermark"/>
- </style>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="label1">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="valign">start</property>
- <property name="halign">center</property>
- <property name="label" translatable="yes">Loading</property>
- <style>
- <class name="contacts-watermark"/>
- </style>
+ <property name="orientation">vertical</property>
+ <property name="width_request">300</property>
+ <property name="homogeneous">True</property>
+ <child>
+ <object class="GtkSpinner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="active">True</property>
+ <property name="valign">end</property>
+ <property name="halign">center</property>
+ <style>
+ <class name="contacts-watermark"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="valign">start</property>
+ <property name="halign">center</property>
+ <property name="label" translatable="yes">Loading</property>
+ <style>
+ <class name="contacts-watermark"/>
+ </style>
+ </object>
+ </child>
</object>
</child>
</object>
+ <packing>
+ <property name="name">list-pane</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSeparator">
+ <property name="visible">True</property>
+ <style>
+ <class name="sidebar"/>
+ </style>
+ </object>
+ <packing>
+ <property name="navigatable">False</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkOverlay" id="contact_pane_container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ </object>
+ <packing>
+ <property name="name">contact-pane</property>
+ </packing>
</child>
</object>
- <packing>
- <property name="name">list-pane</property>
- </packing>
- </child>
- <child>
- <object class="GtkSeparator">
- <property name="visible">True</property>
- <style>
- <class name="sidebar"/>
- </style>
- </object>
- <packing>
- <property name="navigatable">False</property>
- </packing>
- </child>
- <child>
- <object class="GtkOverlay" id="contact_pane_container">
- <property name="visible">True</property>
- <property name="can_focus">False</property>
- <property name="hexpand">True</property>
- </object>
- <packing>
- <property name="name">contact-pane</property>
- </packing>
</child>
</object>
</child>
diff --git a/src/contacts-window.vala b/src/contacts-window.vala
index 53494562..759832b5 100644
--- a/src/contacts-window.vala
+++ b/src/contacts-window.vala
@@ -18,7 +18,7 @@
using Folks;
[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-window.ui")]
-public class Contacts.Window : Gtk.ApplicationWindow {
+public class Contacts.Window : Hdy.ApplicationWindow {
private const GLib.ActionEntry[] action_entries = {
{ "edit-contact", edit_contact },
@@ -38,11 +38,11 @@ public class Contacts.Window : Gtk.ApplicationWindow {
[GtkChild]
private Gtk.Container contact_pane_container;
[GtkChild]
- private Hdy.TitleBar titlebar;
+ private Hdy.HeaderBar left_header;
[GtkChild]
- private Gtk.HeaderBar left_header;
+ private Gtk.Separator header_separator;
[GtkChild]
- private Gtk.HeaderBar right_header;
+ private Hdy.HeaderBar right_header;
[GtkChild]
private Gtk.Overlay notification_overlay;
[GtkChild]
@@ -240,7 +240,7 @@ public class Contacts.Window : Gtk.ApplicationWindow {
((Gtk.Widget) this.done_button).set_focus_on_click (true);
}
// When selecting or editing, we get special headerbars
- this.titlebar.selection_mode = this.state == UiState.SELECTING || this.state.editing ();
+ set_selection_mode (this.state == UiState.SELECTING || this.state.editing ());