[geary/wip/135-contact-popovers: 44/56] Update converation message details when a client contact changes
- From: Michael Gratton <mjog src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [geary/wip/135-contact-popovers: 44/56] Update converation message details when a client contact changes
- Date: Sun, 7 Apr 2019 01:45:44 +0000 (UTC)
commit 6da9c38980386873bca7da96d25e8f90f4893b11
Author: Michael Gratton <mike vee net>
Date: Sat Mar 16 17:43:51 2019 +1100
Update converation message details when a client contact changes
Add Application.Contact.changed signal, hook up to that in
ContactFlowBoxChild and ContactPopover.
.../application/application-contact-store.vala | 2 +-
src/client/application/application-contact.vala | 77 ++++++++++++++--
.../conversation-contact-popover.vala | 30 ++++--
.../conversation-viewer/conversation-message.vala | 101 ++++++++++++++-------
4 files changed, 157 insertions(+), 53 deletions(-)
---
diff --git a/src/client/application/application-contact-store.vala
b/src/client/application/application-contact-store.vala
index 44753ea3..59ae9108 100644
--- a/src/client/application/application-contact-store.vala
+++ b/src/client/application/application-contact-store.vala
@@ -17,7 +17,7 @@ public class Application.ContactStore : Geary.BaseObject {
/** The account this store aggregates data for. */
public Geary.Account account { get; private set; }
- private Folks.IndividualAggregator individuals;
+ internal Folks.IndividualAggregator individuals;
/** Constructs a new contact store for an account. */
diff --git a/src/client/application/application-contact.vala b/src/client/application/application-contact.vala
index 516a8234..5ff5d3fa 100644
--- a/src/client/application/application-contact.vala
+++ b/src/client/application/application-contact.vala
@@ -41,6 +41,11 @@ public class Application.Contact : Geary.BaseObject {
}
}
+
+ /** Fired when the contact has changed in some way. */
+ public signal void changed();
+
+
private weak ContactStore store;
private Folks.Individual? individual;
private Geary.Contact? contact;
@@ -51,15 +56,11 @@ public class Application.Contact : Geary.BaseObject {
Geary.Contact? contact,
Geary.RFC822.MailboxAddress source) {
this.store = store;
- this.individual = individual;
this.contact = contact;
+ update_individual(individual);
- if (individual != null) {
- this.display_name = individual.display_name;
- this.is_desktop_contact = true;
- } else if (contact != null) {
- this.display_name = contact.real_name;
- } else {
+ update();
+ if (Geary.String.is_empty_or_whitespace(this.display_name)) {
this.display_name = source.name;
}
@@ -74,6 +75,11 @@ public class Application.Contact : Geary.BaseObject {
}
}
+ ~Contact() {
+ // Disconnect from signals if any
+ update_individual(null);
+ }
+
/** Sets remote resource loading for this contact. */
public async void set_remote_resource_loading(bool enabled,
GLib.Cancellable? cancellable)
@@ -90,6 +96,8 @@ public class Application.Contact : Geary.BaseObject {
// XXX cancellable
);
}
+
+ changed();
}
/** Returns a string representation for debugging */
@@ -97,4 +105,59 @@ public class Application.Contact : Geary.BaseObject {
return "Contact(\"%s\")".printf(this.display_name);
}
+ private void update_individual(Folks.Individual? replacement) {
+ if (this.individual != null) {
+ this.individual.notify.disconnect(this.on_individual_notify);
+ this.individual.removed.disconnect(this.on_individual_removed);
+ }
+
+ this.individual = replacement;
+
+ if (this.individual != null) {
+ this.individual.notify.connect(this.on_individual_notify);
+ this.individual.removed.connect(this.on_individual_removed);
+ }
+ }
+
+ private void update() {
+ if (this.individual != null) {
+ this.display_name = this.individual.display_name;
+ this.is_desktop_contact = true;
+ } else {
+ if (this.contact != null) {
+ this.display_name = this.contact.real_name;
+ }
+ this.is_desktop_contact = false;
+ }
+ }
+
+ private async void update_replacement(Folks.Individual? replacement) {
+ if (replacement == null) {
+ ContactStore? store = this.store;
+ if (store != null) {
+ try {
+ replacement = yield store.individuals.look_up_individual(
+ this.individual.id
+ );
+ } catch (GLib.Error err) {
+ debug("Error loading replacement for Folks %s: %s",
+ this.individual.id, err.message);
+ }
+ }
+ }
+
+ update_individual(replacement);
+ update();
+ changed();
+ }
+
+ private void on_individual_notify() {
+ update();
+ changed();
+ }
+
+ private void on_individual_removed(Folks.Individual? replacement) {
+ this.update_replacement.begin(replacement);
+ }
+
}
diff --git a/src/client/conversation-viewer/conversation-contact-popover.vala
b/src/client/conversation-viewer/conversation-contact-popover.vala
index 24f87002..033c59e1 100644
--- a/src/client/conversation-viewer/conversation-contact-popover.vala
+++ b/src/client/conversation-viewer/conversation-contact-popover.vala
@@ -38,16 +38,8 @@ public class Conversation.ContactPopover : Gtk.Popover {
this.contact = contact;
this.mailbox = mailbox;
- string? display_name = contact.display_name;
- this.contact_name.set_text(display_name);
-
- if (!contact.display_name_is_email) {
- this.contact_address.set_text(mailbox.address);
- } else {
- this.contact_name.vexpand = true;
- this.contact_name.valign = FILL;
- this.contact_address.hide();
- }
+ contact.changed.connect(this.on_contact_changed);
+ update();
}
public void add_section(GLib.MenuModel section,
@@ -106,10 +98,28 @@ public class Conversation.ContactPopover : Gtk.Popover {
}
public override void destroy() {
+ this.contact.changed.disconnect(this.on_contact_changed);
this.load_cancellable.cancel();
base.destroy();
}
+ private void update() {
+ string display_name = this.contact.display_name;
+ this.contact_name.set_text(display_name);
+
+ if (!this.contact.display_name_is_email) {
+ this.contact_address.set_text(this.mailbox.address);
+ } else {
+ this.contact_name.vexpand = true;
+ this.contact_name.valign = FILL;
+ this.contact_address.hide();
+ }
+ }
+
+ private void on_contact_changed() {
+ update();
+ }
+
[GtkCallback]
private void after_closed() {
GLib.Idle.add(() => {
diff --git a/src/client/conversation-viewer/conversation-message.vala
b/src/client/conversation-viewer/conversation-message.vala
index e3fbde3a..ccc90448 100644
--- a/src/client/conversation-viewer/conversation-message.vala
+++ b/src/client/conversation-viewer/conversation-message.vala
@@ -46,14 +46,20 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private const string ACTION_SAVE_IMAGE = "save-image";
private const string ACTION_SELECT_ALL = "select-all";
+
// Widget used to display sender/recipient email addresses in
// message header Gtk.FlowBox instances.
private class ContactFlowBoxChild : Gtk.FlowBoxChild {
+
private const string PRIMARY_CLASS = "geary-primary";
+
public enum Type { FROM, OTHER; }
+
+ public Type address_type { get; private set; }
+
public Application.Contact contact { get; private set; }
public Geary.RFC822.MailboxAddress displayed { get; private set; }
@@ -61,13 +67,55 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private string search_value;
+ private Gtk.Bin container;
+
+
public ContactFlowBoxChild(Application.Contact contact,
Geary.RFC822.MailboxAddress source,
- Type type = Type.OTHER) {
+ Type address_type = Type.OTHER) {
this.contact = contact;
this.source = source;
+ this.address_type = address_type;
this.search_value = source.to_searchable_string().casefold();
+ // Update prelight state when mouse-overed.
+ Gtk.EventBox events = new Gtk.EventBox();
+ events.add_events(
+ Gdk.EventMask.ENTER_NOTIFY_MASK |
+ Gdk.EventMask.LEAVE_NOTIFY_MASK
+ );
+ events.set_visible_window(false);
+ events.enter_notify_event.connect(on_prelight_in_event);
+ events.leave_notify_event.connect(on_prelight_out_event);
+
+ add(events);
+ this.container = events;
+ set_halign(Gtk.Align.START);
+
+ this.contact.changed.connect(on_contact_changed);
+ update();
+ }
+
+ public override void destroy() {
+ this.contact.changed.disconnect(on_contact_changed);
+ base.destroy();
+ }
+
+ public bool highlight_search_term(string term) {
+ bool found = term in this.search_value;
+ if (found) {
+ get_style_context().add_class(MATCH_CLASS);
+ } else {
+ get_style_context().remove_class(MATCH_CLASS);
+ }
+ return found;
+ }
+
+ public void unmark_search_terms() {
+ get_style_context().remove_class(MATCH_CLASS);
+ }
+
+ private void update() {
// We use two GTK.Label instances here when address has
// distinct parts so we can dim the secondary part, if
// any. Ideally, it would be just one label instance in
@@ -76,7 +124,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
Gtk.Grid address_parts = new Gtk.Grid();
- bool is_spoofed = source.is_spoofed();
+ bool is_spoofed = this.source.is_spoofed();
if (is_spoofed) {
Gtk.Image spoof_img = new Gtk.Image.from_icon_name(
"dialog-warning-symbolic", Gtk.IconSize.SMALL_TOOLBAR
@@ -91,34 +139,34 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
primary.ellipsize = Pango.EllipsizeMode.END;
primary.set_halign(Gtk.Align.START);
primary.get_style_context().add_class(PRIMARY_CLASS);
- if (type == Type.FROM) {
+ if (this.address_type == Type.FROM) {
primary.get_style_context().add_class(FROM_CLASS);
}
address_parts.add(primary);
- string display_address = source.to_address_display("", "");
+ string display_address = this.source.to_address_display("", "");
- if (is_spoofed || contact.display_name_is_email) {
+ if (is_spoofed || this.contact.display_name_is_email) {
// Don't display the name to avoid duplication and/or
// reduce the chance of the user of being tricked by
// malware.
primary.set_text(display_address);
this.displayed = new Geary.RFC822.MailboxAddress(
- null, source.address
+ null, this.source.address
);
- } else if (contact.is_desktop_contact) {
+ } else if (this.contact.is_desktop_contact) {
// The contact's name can be trusted, so no need to
// display the email address
- primary.set_text(contact.display_name);
+ primary.set_text(this.contact.display_name);
this.displayed = new Geary.RFC822.MailboxAddress(
- contact.display_name, source.address
+ this.contact.display_name, this.source.address
);
} else {
// Display both the display name and the email address
// so that the user has the full information at hand
- primary.set_text(contact.display_name);
+ primary.set_text(this.contact.display_name);
this.displayed = new Geary.RFC822.MailboxAddress(
- contact.display_name, source.address
+ this.contact.display_name, this.source.address
);
Gtk.Label secondary = new Gtk.Label(null);
@@ -129,34 +177,17 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
address_parts.add(secondary);
}
- // Update prelight state when mouse-overed.
- Gtk.EventBox events = new Gtk.EventBox();
- events.add_events(
- Gdk.EventMask.ENTER_NOTIFY_MASK |
- Gdk.EventMask.LEAVE_NOTIFY_MASK
- );
- events.set_visible_window(false);
- events.enter_notify_event.connect(on_prelight_in_event);
- events.leave_notify_event.connect(on_prelight_out_event);
- events.add(address_parts);
+ Gtk.Widget? existing_ui = this.container.get_child();
+ if (existing_ui != null) {
+ this.container.remove(existing_ui);
+ }
- add(events);
- set_halign(Gtk.Align.START);
+ this.container.add(address_parts);
show_all();
}
- public bool highlight_search_term(string term) {
- bool found = term in this.search_value;
- if (found) {
- get_style_context().add_class(MATCH_CLASS);
- } else {
- get_style_context().remove_class(MATCH_CLASS);
- }
- return found;
- }
-
- public void unmark_search_terms() {
- get_style_context().remove_class(MATCH_CLASS);
+ private void on_contact_changed() {
+ update();
}
private bool on_prelight_in_event(Gdk.Event event) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]