Commit 68b2da17 authored by Michael Gratton's avatar Michael Gratton 🤞 Committed by Michael Gratton

Separate and implement contact popover action from conversation message

This leads to a minor bit of UI string and code duplication, but
substantially reduces the complexity of implementing the popover's
actions. Hook up all remaining actions except open and save.
parent 948ed5f9
......@@ -12,15 +12,35 @@
public class Conversation.ContactPopover : Gtk.Popover {
private const string ACTION_COPY_EMAIL= "copy-email";
private const string ACTION_LOAD_REMOTE = "load-remote";
private const string ACTION_NEW_CONVERSATION = "new-conversation";
private const string ACTION_OPEN = "open";
private const string ACTION_SAVE = "save";
private const string ACTION_SHOW_CONVERSATIONS = "show-conversations";
private const string ACTION_STAR = "star";
private const string ACTION_UNSTAR = "unstar";
private const string ACTION_GROUP = "con";
private const GLib.ActionEntry[] ACTION_ENTRIES = {
{ACTION_COPY_EMAIL, on_copy_email, },
{ACTION_LOAD_REMOTE, on_load_remote, null, "false" },
{ACTION_NEW_CONVERSATION, on_new_conversation },
{ACTION_OPEN, on_open },
{ACTION_SAVE, on_save },
{ACTION_SHOW_CONVERSATIONS, on_show_conversations },
{ACTION_STAR, on_star, },
{ACTION_UNSTAR, on_unstar, },
};
public Application.Contact contact { get; private set; }
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;
......@@ -36,45 +56,35 @@ public class Conversation.ContactPopover : Gtk.Popover {
[GtkChild]
private Gtk.Button unstarred_button;
[GtkChild]
private Gtk.ModelButton open_button;
[GtkChild]
private Gtk.ModelButton save_button;
[GtkChild]
private Gtk.ModelButton load_remote_button;
private GLib.SimpleActionGroup actions = new GLib.SimpleActionGroup();
public ContactPopover(Gtk.Widget relative_to,
Application.Contact contact,
Geary.RFC822.MailboxAddress mailbox) {
this.relative_to = relative_to;
this.contact = contact;
this.mailbox = mailbox;
this.load_remote_button.role = CHECK;
this.actions.add_action_entries(ACTION_ENTRIES, this);
insert_action_group(ACTION_GROUP, this.actions);
contact.changed.connect(this.on_contact_changed);
update();
}
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.
*/
......@@ -121,20 +131,94 @@ public class Conversation.ContactPopover : Gtk.Popover {
this.contact_address.hide();
}
bool is_desktop = this.contact.is_desktop_contact;
bool starred = false;
bool unstarred = false;
if (this.contact.is_desktop_contact) {
if (is_desktop) {
starred = this.contact.is_favourite;
unstarred = !this.contact.is_favourite;
}
this.starred_button.set_visible(starred);
this.unstarred_button.set_visible(unstarred);
this.open_button.set_visible(is_desktop);
this.save_button.set_visible(!is_desktop);
this.load_remote_button.set_visible(!is_desktop);
GLib.SimpleAction load_remote = (GLib.SimpleAction)
actions.lookup_action(ACTION_LOAD_REMOTE);
load_remote.set_state(
new GLib.Variant.boolean(
is_desktop || this.contact.load_remote_resources
)
);
}
private async void set_load_remote_resources(bool enabled) {
try {
yield this.contact.set_remote_resource_loading(enabled, null);
} catch (GLib.Error err) {
debug("Failed to set load remote resources for contact %s:, %s",
this.contact.to_string(), err.message);
}
}
private async void set_favourite(bool enabled) {
try {
yield this.contact.set_favourite(enabled, null);
} catch (GLib.Error err) {
debug("Failed to set enabled state for contact %s:, %s",
this.contact.to_string(), err.message);
}
}
private void on_contact_changed() {
update();
}
private void on_copy_email() {
Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
clipboard.set_text(this.mailbox.to_full_display(), -1);
clipboard.store();
}
private void on_load_remote(GLib.SimpleAction action) {
bool state = !action.get_state().get_boolean();
this.set_load_remote_resources.begin(state);
}
private void on_new_conversation() {
MainWindow? main = this.get_toplevel() as MainWindow;
if (main != null) {
main.open_composer_for_mailbox(this.mailbox);
}
}
private void on_open() {
}
private void on_save() {
}
private void on_show_conversations() {
MainWindow? main = this.get_toplevel() as MainWindow;
if (main != null) {
main.show_search_bar("from:%s".printf(this.mailbox.address));
}
}
private void on_star() {
this.set_favourite.begin(true);
}
private void on_unstar() {
this.set_favourite.begin(false);
}
[GtkCallback]
private void after_closed() {
GLib.Idle.add(() => {
......
......@@ -32,11 +32,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private const int MAX_INLINE_IMAGE_MAJOR_DIM = 1024;
private const string ACTION_CONTACT_LOAD_IMAGES = "contact-load-images";
private const string ACTION_CONTACT_OPEN = "contact-open";
private const string ACTION_CONTACT_SAVE = "contact-save";
private const string ACTION_CONTACT_SHOW_CONVERSATIONS =
"contact-show-conversations";
private const string ACTION_CONVERSATION_NEW = "conversation-new";
private const string ACTION_COPY_EMAIL = "copy-email";
private const string ACTION_COPY_LINK = "copy-link";
......@@ -203,9 +198,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
}
private static GLib.VariantType MAILBOX_TYPE = new GLib.VariantType("(ss)");
/** Contact for the primary originator, if any. */
internal Application.Contact? primary_contact {
get; private set;
......@@ -305,8 +297,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
private MenuModel context_menu_email;
private MenuModel context_menu_image;
private MenuModel context_menu_main;
private MenuModel context_menu_known_contact;
private MenuModel context_menu_unknown_contact;
private MenuModel? context_menu_inspector = null;
// Address fields that can be search through
......@@ -406,18 +396,7 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
// Actions
add_action(ACTION_CONTACT_LOAD_IMAGES, true, VariantType.BOOLEAN)
// XXX
;
add_action(ACTION_CONTACT_OPEN, true, VariantType.STRING)
// XXX
;
add_action(ACTION_CONTACT_SAVE, true, ConversationMessage.MAILBOX_TYPE)
// XXX
;
add_action(ACTION_CONTACT_SHOW_CONVERSATIONS, true, VariantType.STRING)
.activate.connect(on_contact_show_conversations);
add_action(ACTION_CONVERSATION_NEW, true, ConversationMessage.MAILBOX_TYPE)
add_action(ACTION_CONVERSATION_NEW, true, VariantType.STRING)
.activate.connect(on_new_conversation);
add_action(ACTION_COPY_EMAIL, true, VariantType.STRING)
.activate.connect(on_copy_email_address);
......@@ -447,12 +426,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
context_menu_email = (MenuModel) builder.get_object("context_menu_email");
context_menu_image = (MenuModel) builder.get_object("context_menu_image");
context_menu_main = (MenuModel) builder.get_object("context_menu_main");
this.context_menu_known_contact = (MenuModel) builder.get_object(
"context_menu_known_contact"
);
this.context_menu_unknown_contact = (MenuModel) builder.get_object(
"context_menu_unknown_contact"
);
if (Args.inspector) {
context_menu_inspector =
(MenuModel) builder.get_object("context_menu_inspector");
......@@ -1080,17 +1053,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
Gee.Map<string,GLib.Variant> values =
new Gee.HashMap<string,GLib.Variant>();
GLib.Variant mailbox_var = new GLib.Variant.tuple(
new GLib.Variant[] {
address.name ?? "",
address.address
});
values[ACTION_CONTACT_OPEN] = "not yet defined";
values[ACTION_CONTACT_SAVE] = mailbox_var;
values[ACTION_CONTACT_SHOW_CONVERSATIONS] = address.address;
values[ACTION_CONTACT_LOAD_IMAGES] = false;
values[ACTION_CONVERSATION_NEW] = mailbox_var;
values[ACTION_COPY_EMAIL] = address.to_full_display();
Conversation.ContactPopover popover = new Conversation.ContactPopover(
......@@ -1099,13 +1061,6 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
address
);
popover.load_avatar.begin();
popover.add_section(this.context_menu_email, values);
popover.add_section(
address_child.contact.is_desktop_contact
? this.context_menu_known_contact
: this.context_menu_unknown_contact,
values
);
popover.set_position(Gtk.PositionType.BOTTOM);
popover.closed.connect(() => {
address_child.unset_state_flags(Gtk.StateFlags.ACTIVE);
......@@ -1245,34 +1200,28 @@ public class ConversationMessage : Gtk.Grid, Geary.BaseInterface {
remote_images_infobar.hide();
}
private void on_contact_show_conversations(Variant? param) {
string email = param as string;
MainWindow? main = this.get_toplevel() as MainWindow;
if (main != null && email != null) {
main.show_search_bar("from:%s".printf(email));
}
private void on_copy_link(Variant? param) {
Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
clipboard.set_text(param.get_string(), -1);
clipboard.store();
}
private void on_new_conversation(Variant? param) {
string value = param.get_string();
if (value.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
value = value.substring(Geary.ComposedEmail.MAILTO_SCHEME.length, -1);
}
MainWindow? main = this.get_toplevel() as MainWindow;
if (main != null &&
param.get_type().equal(ConversationMessage.MAILBOX_TYPE)) {
string? name = (string) param.get_child_value(0);
Geary.RFC822.MailboxAddress.is_valid_address(value)) {
Geary.RFC822.MailboxAddress mailbox = new Geary.RFC822.MailboxAddress(
Geary.String.is_empty_or_whitespace(name) ? null : name,
(string) param.get_child_value(1)
null, value
);
main.open_composer_for_mailbox(mailbox);
}
}
private void on_copy_link(Variant? param) {
Gtk.Clipboard clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD);
clipboard.set_text(param.get_string(), -1);
clipboard.store();
}
private void on_copy_email_address(Variant? param) {
string value = param.get_string();
if (value.has_prefix(Geary.ComposedEmail.MAILTO_SCHEME)) {
......
......@@ -6,7 +6,7 @@
<property name="can_focus">False</property>
<signal name="closed" handler="after_closed" after="yes" swapped="no"/>
<child>
<object class="GtkGrid" id="container">
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_left">10</property>
......@@ -14,7 +14,6 @@
<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>
......@@ -27,7 +26,7 @@
<property name="receives_default">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="action_name">msg.contact-star</property>
<property name="action_name">con.star</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
......@@ -48,7 +47,7 @@
<property name="receives_default">True</property>
<property name="halign">end</property>
<property name="valign">center</property>
<property name="action_name">msg.contact-star</property>
<property name="action_name">con.unstar</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
......@@ -123,6 +122,104 @@
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">con.new-conversation</property>
<property name="text" translatable="yes">_New Conversation…</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">2</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">con.copy-email</property>
<property name="text" translatable="yes">Copy Email _Address</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">3</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can_focus">False</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">4</property>
</packing>
</child>
<child>
<object class="GtkModelButton" id="save_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">con.save</property>
<property name="text" translatable="yes">Save in Contacts…</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">7</property>
</packing>
</child>
<child>
<object class="GtkModelButton">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">con.show-conversations</property>
<property name="text" translatable="yes">Show Conversations</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">5</property>
</packing>
</child>
<child>
<object class="GtkModelButton" id="open_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">con.open</property>
<property name="text" translatable="yes">Open in Contacts</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">6</property>
</packing>
</child>
<child>
<object class="GtkModelButton" id="load_remote_button">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="action_name">con.load-remote</property>
<property name="text" translatable="yes">Always Load Remote Images</property>
</object>
<packing>
<property name="left_attach">0</property>
<property name="top_attach">8</property>
</packing>
</child>
</object>
</child>
<style>
......
......@@ -38,30 +38,6 @@
<attribute name="action">msg.copy-selection</attribute>
</item>
</section>
<section id="context_menu_known_contact">
<item>
<attribute name="label" translatable="yes">Sho_w Conversations</attribute>
<attribute name="action">msg.contact-show-conversations</attribute>
</item>
<item>
<attribute name="label" translatable="yes">_Open in Contacts…</attribute>
<attribute name="action">msg.contact-save</attribute>
</item>
</section>
<section id="context_menu_unknown_contact">
<item>
<attribute name="label" translatable="yes">Sho_w Conversations</attribute>
<attribute name="action">msg.contact-show-conversations</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Save in Con_tacts…</attribute>
<attribute name="action">msg.contact-save</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Always Load Remote Images</attribute>
<attribute name="action">msg.contact-load-images</attribute>
</item>
</section>
<section id="context_menu_inspector">
<item>
<attribute name="label" translatable="yes">_Inspect…</attribute>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment