diff options
author | Niels De Graef <nielsdegraef@gmail.com> | 2023-02-20 22:44:34 +0100 |
---|---|---|
committer | Niels De Graef <nielsdegraef@gmail.com> | 2023-02-21 15:02:47 +0000 |
commit | 0f2d408c1a3ec818f3f59fce5a04aeae88f2ef6c (patch) | |
tree | 047653f91d9186af074a3850d7d91344debcd391 | |
parent | cb544e27d7aa5e6debe19f7f6b57bb6937720bbb (diff) | |
download | gnome-contacts-0f2d408c1a3ec818f3f59fce5a04aeae88f2ef6c.tar.gz |
Add EditableAvatar custom widget
Rather than awkwardly shoehorning an `AdwAvatar` into a button, let's be
a bit more helpful and just overlay 2 buttons, one for editing and one
for deleting the avatar.
Fixes: https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/217
Fixes: https://gitlab.gnome.org/GNOME/gnome-contacts/-/issues/26
-rw-r--r-- | data/contacts.gresource.xml | 1 | ||||
-rw-r--r-- | data/ui/contacts-editable-avatar.ui | 47 | ||||
-rw-r--r-- | data/ui/style.css | 6 | ||||
-rw-r--r-- | po/POTFILES.in | 2 | ||||
-rw-r--r-- | po/POTFILES.skip | 1 | ||||
-rw-r--r-- | src/contacts-avatar-selector.vala | 2 | ||||
-rw-r--r-- | src/contacts-contact-editor.vala | 24 | ||||
-rw-r--r-- | src/contacts-editable-avatar.vala | 80 | ||||
-rw-r--r-- | src/meson.build | 1 |
9 files changed, 138 insertions, 26 deletions
diff --git a/data/contacts.gresource.xml b/data/contacts.gresource.xml index 3d46685..e9158c1 100644 --- a/data/contacts.gresource.xml +++ b/data/contacts.gresource.xml @@ -18,6 +18,7 @@ <file compressed="true" preprocess="xml-stripblanks">ui/contacts-avatar-selector.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-contact-pane.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-crop-dialog.ui</file> + <file compressed="true" preprocess="xml-stripblanks">ui/contacts-editable-avatar.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-editor-menu.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-link-suggestion-grid.ui</file> <file compressed="true" preprocess="xml-stripblanks">ui/contacts-main-window.ui</file> diff --git a/data/ui/contacts-editable-avatar.ui b/data/ui/contacts-editable-avatar.ui new file mode 100644 index 0000000..1f2261f --- /dev/null +++ b/data/ui/contacts-editable-avatar.ui @@ -0,0 +1,47 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <template class="ContactsEditableAvatar" parent="GtkWidget"> + <child> + <object class="GtkOverlay" id="overlay"> + <child type="overlay"> + <object class="AdwBin"> + <property name="halign">end</property> + <property name="valign">start</property> + <style> + <class name="contacts-cutout-button"/> + </style> + <child> + <object class="GtkButton"> + <property name="action-name">edit-avatar</property> + <property name="icon-name">document-edit-symbolic</property> + <property name="tooltip-text" translatable="yes">Change Avatar</property> + <style> + <class name="circular"/> + </style> + </object> + </child> + </object> + </child> + <child type="overlay"> + <object class="AdwBin"> + <property name="halign">end</property> + <property name="valign">end</property> + <style> + <class name="contacts-cutout-button"/> + </style> + <child> + <object class="GtkButton"> + <property name="action-name">delete-avatar</property> + <property name="icon-name">user-trash-symbolic</property> + <property name="tooltip-text" translatable="yes">Remove Avatar</property> + <style> + <class name="circular"/> + </style> + </object> + </child> + </object> + </child> + </object> + </child> + </template> +</interface> diff --git a/data/ui/style.css b/data/ui/style.css index f33ee8d..6593344 100644 --- a/data/ui/style.css +++ b/data/ui/style.css @@ -31,9 +31,11 @@ font-size: 20px; } -flowboxchild.circular { - padding: 4px; +/* Used to provide a little cutout around an overlayed circular button */ +.contacts-cutout-button { + background-color: @window_bg_color; border-radius: 9999px; + padding: 2px; } /* Contact Sheet/Editor common */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 25fb680..c132dd9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -7,6 +7,7 @@ data/ui/contacts-avatar-selector.ui data/ui/contacts-contact-pane.ui data/ui/contacts-crop-dialog.ui data/ui/contacts-editor-menu.ui +data/ui/contacts-editable-avatar.ui data/ui/contacts-linked-personas-dialog.ui data/ui/contacts-link-suggestion-grid.ui data/ui/contacts-main-window.ui @@ -23,6 +24,7 @@ src/contacts-contact-pane.vala src/contacts-contact-sheet.vala src/contacts-crop-dialog.vala src/contacts-delete-operation.vala +src/contacts-editable-avatar.vala src/contacts-esd-setup.vala src/contacts-im-service.vala src/contacts-linked-personas-dialog.vala diff --git a/po/POTFILES.skip b/po/POTFILES.skip index 6f848f9..4a8ec06 100644 --- a/po/POTFILES.skip +++ b/po/POTFILES.skip @@ -12,6 +12,7 @@ src/contacts-contact-pane.c src/contacts-contact-sheet.c src/contacts-crop-dialog.c src/contacts-delete-operation.c +src/contacts-editable-avatar.c src/contacts-esd-setup.c src/contacts-im-service.c src/contacts-linked-personas-dialog.c diff --git a/src/contacts-avatar-selector.vala b/src/contacts-avatar-selector.vala index e9740c8..b6da6ff 100644 --- a/src/contacts-avatar-selector.vala +++ b/src/contacts-avatar-selector.vala @@ -70,8 +70,6 @@ private class Contacts.Thumbnail : Gtk.FlowBoxChild { [GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-avatar-selector.ui")] public class Contacts.AvatarSelector : Gtk.Window { - const string AVATAR_BUTTON_CSS_NAME = "avatar-button"; - public unowned Contact contact { get; construct set; } [GtkChild] diff --git a/src/contacts-contact-editor.vala b/src/contacts-contact-editor.vala index 26c5730..3383472 100644 --- a/src/contacts-contact-editor.vala +++ b/src/contacts-contact-editor.vala @@ -31,7 +31,6 @@ public class Contacts.ContactEditor : Gtk.Widget { private GenericArray<Persona?> personas = new GenericArray<Persona?> (); private unowned Gtk.Entry name_entry; - private unowned Avatar avatar; construct { var box_layout = new Gtk.BoxLayout (Gtk.Orientation.VERTICAL); @@ -44,8 +43,8 @@ public class Contacts.ContactEditor : Gtk.Widget { public ContactEditor (Contact contact) { Object (contact: contact); - var header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6); - header.append (create_widget_for_avatar (contact)); + var header = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12); + header.append (new EditableAvatar (contact, PROFILE_SIZE)); header.append (create_name_entry (contact)); header.set_parent (this); @@ -88,25 +87,6 @@ public class Contacts.ContactEditor : Gtk.Widget { // they're still editing } - // Creates the contact's current avatar in a big button on top of the Editor - private Gtk.Widget create_widget_for_avatar (Contact contact) { - var avatar = new Avatar.for_contact (PROFILE_SIZE, contact); - this.avatar = avatar; - - var button = new Gtk.Button (); - button.tooltip_text = _("Change avatar"); - button.set_child (this.avatar); - button.clicked.connect (on_avatar_button_clicked); - - return button; - } - - // 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.contact, get_root () as Gtk.Window); - avatar_selector.present (); - } - // Creates the big name entry on the top private Gtk.Widget create_name_entry (Contact contact) { var entry = new Gtk.Entry (); diff --git a/src/contacts-editable-avatar.vala b/src/contacts-editable-avatar.vala new file mode 100644 index 0000000..4469ce8 --- /dev/null +++ b/src/contacts-editable-avatar.vala @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2023 Niels De Graef <nielsdegraef@gmail.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +using Folks; + +/** + * The EditableAvatar is a custom widget that allows changing or unsetting a + * {@link Contact}'s avatar. + */ +[GtkTemplate (ui = "/org/gnome/Contacts/ui/contacts-editable-avatar.ui")] +public class Contacts.EditableAvatar : Gtk.Widget { + + [GtkChild] + private unowned Gtk.Overlay overlay; + + public Contact contact { get; construct; } + + public int avatar_size { get; set; } + + static construct { + set_layout_manager_type (typeof (Gtk.BinLayout)); + + install_action ("edit-avatar", null, (Gtk.WidgetActionActivateFunc) on_edit_avatar); + install_action ("delete-avatar", null, (Gtk.WidgetActionActivateFunc) on_delete_avatar); + } + + construct { + var avatar = new Avatar.for_contact (this.avatar_size, this.contact); + this.bind_property ("avatar-size", avatar, "avatar-size"); + this.overlay.child = avatar; + + var chunk = this.contact.get_most_relevant_chunk ("avatar", true); + if (chunk == null) + chunk = this.contact.create_chunk ("avatar", null); + unowned var avatar_chunk = (AvatarChunk) chunk; + action_set_enabled ("delete-avatar", avatar_chunk.avatar != null); + avatar_chunk.notify["avatar"].connect (on_avatar_chunk_notify); + } + + public EditableAvatar (Contact contact, int size) { + Object (contact: contact, avatar_size: size); + } + + public override void dispose () { + this.overlay.unparent (); + base.dispose (); + } + + private void on_avatar_chunk_notify (Object object, ParamSpec pspec) { + unowned var avatar_chunk = (AvatarChunk) object; + action_set_enabled ("delete-avatar", avatar_chunk.avatar != null); + } + + private void on_edit_avatar (string action_name, Variant? param) { + var selector = new AvatarSelector (this.contact, + get_root () as Gtk.Window); + selector.present (); + } + + private void on_delete_avatar (string action_name, Variant? param) { + var avatar_chunk = this.contact.get_most_relevant_chunk ("avatar", true); + if (avatar_chunk == null) + avatar_chunk = this.contact.create_chunk ("avatar", null); + ((AvatarChunk) avatar_chunk).avatar = null; + } +} diff --git a/src/meson.build b/src/meson.build index 821f240..dea4fa3 100644 --- a/src/meson.build +++ b/src/meson.build @@ -92,6 +92,7 @@ contacts_vala_sources = files( 'contacts-contact-pane.vala', 'contacts-contact-sheet.vala', 'contacts-crop-dialog.vala', + 'contacts-editable-avatar.vala', 'contacts-link-suggestion-grid.vala', 'contacts-main-window.vala', 'contacts-qr-code-dialog.vala', |