[geary/wip/135-contact-popovers: 34/56] Add initial contact popover UI and implementation
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/135-contact-popovers: 34/56] Add initial contact popover UI and implementation
- Date: Sun, 7 Apr 2019 01:44:53 +0000 (UTC)
commit 9a3ac61cf846415baae84cc94c1dd0ab0350de4b
Author: Michael Gratton <mike vee net>
Date: Thu Mar 14 16:59:55 2019 +1100
Add initial contact popover UI and implementation
.../application/application-avatar-store.vala | 3 +
src/client/application/geary-controller.vala | 12 +-
.../conversation-contact-popover.vala | 113 ++++++++++++++++++
src/client/meson.build | 1 +
ui/conversation-contact-popover.ui | 127 +++++++++++++++++++++
ui/geary.css | 5 +
ui/org.gnome.Geary.gresource.xml | 1 +
7 files changed, 256 insertions(+), 6 deletions(-)
---
diff --git a/src/client/application/application-avatar-store.vala
b/src/client/application/application-avatar-store.vala
index 6d3d9402..e57bcf34 100644
--- a/src/client/application/application-avatar-store.vala
+++ b/src/client/application/application-avatar-store.vala
@@ -12,6 +12,9 @@
public class Application.AvatarStore : Geary.BaseObject {
+ /** Default size of avatar images, in toolkit pixels */
+ public const int PIXEL_SIZE = 48;
+
// Max age is low since we really only want to cache between
// conversation loads.
private const int64 MAX_CACHE_AGE_US = 5 * 1000 * 1000;
diff --git a/src/client/application/geary-controller.vala b/src/client/application/geary-controller.vala
index bf2b3a16..b279a104 100644
--- a/src/client/application/geary-controller.vala
+++ b/src/client/application/geary-controller.vala
@@ -120,7 +120,7 @@ public class GearyController : Geary.BaseObject {
public AutostartManager? autostart_manager { get; private set; default = null; }
- public Application.AvatarStore? avatar_store {
+ public Application.AvatarStore? avatars {
get; private set; default = null;
}
@@ -274,7 +274,7 @@ public class GearyController : Geary.BaseObject {
});
}
- this.avatar_store = new Application.AvatarStore(individuals);
+ this.avatars = new Application.AvatarStore(individuals);
// Create the main window (must be done after creating actions.)
main_window = new MainWindow(this.application);
@@ -315,7 +315,7 @@ public class GearyController : Geary.BaseObject {
unity_launcher = new UnityLauncher(new_messages_monitor);
this.libnotify = new Libnotify(
- this.new_messages_monitor, this.avatar_store
+ this.new_messages_monitor, this.avatars
);
this.libnotify.invoked.connect(on_libnotify_invoked);
@@ -545,8 +545,8 @@ public class GearyController : Geary.BaseObject {
this.autostart_manager = null;
- this.avatar_store.close();
- this.avatar_store = null;
+ this.avatars.close();
+ this.avatars = null;
debug("Closed GearyController");
@@ -1316,7 +1316,7 @@ public class GearyController : Geary.BaseObject {
viewer.load_conversation.begin(
convo,
store,
- this.avatar_store,
+ this.avatars,
(obj, ret) => {
try {
viewer.load_conversation.end(ret);
diff --git a/src/client/conversation-viewer/conversation-contact-popover.vala
b/src/client/conversation-viewer/conversation-contact-popover.vala
new file mode 100644
index 00000000..c781a9dc
--- /dev/null
+++ b/src/client/conversation-viewer/conversation-contact-popover.vala
@@ -0,0 +1,113 @@
+/*
+ * 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.
+ */
+
+/**
+ * Display contact information and supported actions for a contact.
+ */
+[GtkTemplate (ui = "/org/gnome/Geary/conversation-contact-popover.ui")]
+public class Conversation.ContactPopover : Gtk.Popover {
+
+
+ public Geary.RFC822.MailboxAddress mailbox { get; private set; }
+
+ private GLib.Cancellable load_cancellable = new GLib.Cancellable();
+
+ [GtkChild]
+ private Gtk.Grid container;
+
+ [GtkChild]
+ private Gtk.Image avatar;
+
+ [GtkChild]
+ private Gtk.Label contact_name;
+
+ [GtkChild]
+ private Gtk.Label contact_address;
+
+
+ public ContactPopover(Gtk.Widget relative_to,
+ Geary.RFC822.MailboxAddress mailbox) {
+ this.relative_to = relative_to;
+ this.mailbox = mailbox;
+ if (Geary.String.is_empty_or_whitespace(mailbox.name)) {
+ this.contact_name.set_text(mailbox.address);
+ this.contact_name.vexpand = true;
+ this.contact_name.valign = FILL;
+ this.contact_address.hide();
+ } else {
+ this.contact_name.set_text(mailbox.name);
+ this.contact_address.set_text(mailbox.address);
+ }
+ }
+
+ public void add_section(GLib.MenuModel section,
+ Gee.Map<string,GLib.Variant> values) {
+ Gtk.Separator separator = new Gtk.Separator(Gtk.Orientation.HORIZONTAL);
+ separator.show();
+ this.container.add(separator);
+ for (int i = 0; i < section.get_n_items(); i++) {
+ GLib.MenuItem item = new MenuItem.from_model(section, i);
+ string action_fq = (string) item.get_attribute_value(
+ Menu.ATTRIBUTE_ACTION, VariantType.STRING
+ );
+
+ string action_name = action_fq.substring(action_fq.index_of(".") + 1);
+
+ Gtk.ModelButton button = new Gtk.ModelButton();
+ button.text = (string) item.get_attribute_value(
+ Menu.ATTRIBUTE_LABEL, VariantType.STRING
+ );
+ button.action_name = (string) item.get_attribute_value(
+ Menu.ATTRIBUTE_ACTION, VariantType.STRING
+ );
+ button.action_target = values[action_name];
+ button.show();
+
+ this.container.add(button);
+ }
+ }
+
+ /**
+ * Starts loading the avatar for the message's sender.
+ */
+ public async void load_avatar() {
+ MainWindow? main = this.get_toplevel() as MainWindow;
+ if (main != null) {
+ Application.AvatarStore loader = main.application.controller.avatars;
+ int window_scale = get_scale_factor();
+ int pixel_size = Application.AvatarStore.PIXEL_SIZE * window_scale;
+ try {
+ Gdk.Pixbuf? avatar_buf = yield loader.load(
+ this.mailbox, pixel_size, this.load_cancellable
+ );
+ if (avatar_buf != null) {
+ this.avatar.set_from_surface(
+ Gdk.cairo_surface_create_from_pixbuf(
+ avatar_buf, window_scale, get_window()
+ )
+ );
+ }
+ } catch (GLib.Error err) {
+ debug("Conversation load failed: %s", err.message);
+ }
+ }
+ }
+
+ public override void destroy() {
+ this.load_cancellable.cancel();
+ base.destroy();
+ }
+
+ [GtkCallback]
+ private void after_closed() {
+ GLib.Idle.add(() => {
+ this.destroy();
+ return GLib.Source.REMOVE;
+ } );
+ }
+
+}
diff --git a/src/client/meson.build b/src/client/meson.build
index d1c7863a..77db6b1a 100644
--- a/src/client/meson.build
+++ b/src/client/meson.build
@@ -55,6 +55,7 @@ geary_client_vala_sources = files(
'conversation-list/conversation-list-view.vala',
'conversation-list/formatted-conversation-data.vala',
+ 'conversation-viewer/conversation-contact-popover.vala',
'conversation-viewer/conversation-email.vala',
'conversation-viewer/conversation-list-box.vala',
'conversation-viewer/conversation-message.vala',
diff --git a/ui/conversation-contact-popover.ui b/ui/conversation-contact-popover.ui
new file mode 100644
index 00000000..fc81a9db
--- /dev/null
+++ b/ui/conversation-contact-popover.ui
@@ -0,0 +1,127 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Generated with glade 3.22.1 -->
+<interface>
+ <requires lib="gtk+" version="3.20"/>
+ <template class="ConversationContactPopover" parent="GtkPopover">
+ <property name="can_focus">False</property>
+ <signal name="closed" handler="after_closed" after="yes" swapped="no"/>
+ <child>
+ <object class="GtkGrid" id="container">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">10</property>
+ <property name="margin_right">10</property>
+ <property name="margin_top">10</property>
+ <property name="margin_bottom">10</property>
+ <property name="orientation">vertical</property>
+ <property name="row_spacing">2</property>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_bottom">6</property>
+ <property name="column_spacing">6</property>
+ <child>
+ <object class="GtkButton" id="unstarred_button">
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">non-starred-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="starred_button">
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="relief">none</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">starred-symbolic</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkImage" id="avatar">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pixel_size">48</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="contact_name">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">end</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="contact_address">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="valign">start</property>
+ <property name="margin_top">2</property>
+ <property name="hexpand">False</property>
+ <property name="vexpand">True</property>
+ <property name="ellipsize">middle</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ <style>
+ <class name="menu"/>
+ <class name="geary-contact-popover"/>
+ </style>
+ </template>
+</interface>
diff --git a/ui/geary.css b/ui/geary.css
index b1bd0031..b7c061b4 100644
--- a/ui/geary.css
+++ b/ui/geary.css
@@ -174,6 +174,11 @@ grid.geary-message-summary {
margin: 36px 16px;
}
+/* ContactPopover */
+
+.geary-contact-popover .dim-label {
+ font-size: 80%;
+}
/* Composer */
diff --git a/ui/org.gnome.Geary.gresource.xml b/ui/org.gnome.Geary.gresource.xml
index 45c0e4f6..da1d0fc9 100644
--- a/ui/org.gnome.Geary.gresource.xml
+++ b/ui/org.gnome.Geary.gresource.xml
@@ -17,6 +17,7 @@
<file compressed="true" preprocess="xml-stripblanks">composer-widget.ui</file>
<file compressed="true">composer-web-view.css</file>
<file compressed="true">composer-web-view.js</file>
+ <file compressed="true" preprocess="xml-stripblanks">conversation-contact-popover.ui</file>
<file compressed="true" preprocess="xml-stripblanks">conversation-email.ui</file>
<file compressed="true" preprocess="xml-stripblanks">conversation-email-attachment-view.ui</file>
<file compressed="true" preprocess="xml-stripblanks">conversation-email-menus.ui</file>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]