Reenable and update code for inline message image display.

Use a GtkInfoBar to display to the user the message and related buttons
instead of the message-inline HTML approach. Still needs some additional
work to save per-message loading and displaying images from same sender
in convo when "Always Show" is chosen.

* src/client/conversation-viewer/conversation-message.vala: Reenable
  remote image related code, remove HTML-based UI management code.

* src/client/components/main-window.vala (MainWindow::set_styling):
  Add some theme CSS to style the remote images infobar.

* ui/conversation-message.ui: Add the remote images infobar.
This commit is contained in:
Michael James Gratton 2016-04-13 00:08:14 +10:00
parent a6acfe97d4
commit 22e67655ac
3 changed files with 198 additions and 109 deletions

View file

@ -102,6 +102,9 @@ public class ConversationMessage : Gtk.Box {
[GtkChild]
private Gtk.Label bad_link_label;
[GtkChild]
private Gtk.InfoBar remote_images_infobar;
// The folder containing the message
private Geary.Folder containing_folder = null; // XXX weak??
@ -440,32 +443,21 @@ public class ConversationMessage : Gtk.Box {
});
web_view.load_string(body_text, "text/html", "UTF8", "");
// XXX The following will probably need to happen after the
// message has been loaded.
// if (remote_images) {
// Geary.Contact contact = containing_folder.account.get_contact_store().get_by_rfc822(
// email.get_primary_originator());
// bool always_load = contact != null && contact.always_load_remote_images();
if (remote_images) {
Geary.Contact contact = containing_folder.account.get_contact_store().get_by_rfc822(
email.get_primary_originator());
bool always_load = contact != null && contact.always_load_remote_images();
// if (always_load || email.load_remote_images().is_certain()) {
// show_images_email(div_message, false);
// } else {
// WebKit.DOM.HTMLElement remote_images_bar =
// Util.DOM.select(div_message, ".remote_images");
// try {
// ((WebKit.DOM.Element) remote_images_bar).get_class_list().add("show");
// remote_images_bar.set_inner_html("""%s %s
// <input type="button" value="%s" class="show_images" />
// <input type="button" value="%s" class="show_from" />""".printf(
// remote_images_bar.get_inner_html(),
// _("This message contains remote images."), _("Show Images"),
// _("Always Show From Sender")));
// } catch (Error error) {
// warning("Error showing remote images bar: %s", error.message);
// }
// }
// }
if (always_load || email.load_remote_images().is_certain()) {
web_view.notify["load-status"].connect((source, param) => {
if (web_view.load_status == WebKit.LoadStatus.FINISHED) {
show_images(false);
}
});
} else {
remote_images_infobar.show();
}
}
}
// This delegate is called from within Geary.RFC822.Message.get_body while assembling the plain
@ -642,90 +634,6 @@ public class ConversationMessage : Gtk.Box {
// get_viewer().mark_read();
// }
// private void on_show_images() {
// show_images(true);
// }
// private void on_show_images_from() {
// Geary.ContactStore contact_store =
// containing_folder.account.get_contact_store();
// Geary.Contact? contact = contact_store.get_by_rfc822(email.get_primary_originator());
// if (contact == null) {
// debug("Couldn't find contact for %s", email.from.to_string());
// return;
// }
// Geary.ContactFlags flags = new Geary.ContactFlags();
// flags.add(Geary.ContactFlags.ALWAYS_LOAD_REMOTE_IMAGES);
// Gee.ArrayList<Geary.Contact> contact_list = new Gee.ArrayList<Geary.Contact>();
// contact_list.add(contact);
// contact_store.mark_contacts_async.begin(contact_list, flags, null);
// WebKit.DOM.Document document = web_view.get_dom_document();
// try {
// WebKit.DOM.NodeList nodes = document.query_selector_all(".email");
// for (ulong i = 0; i < nodes.length; i ++) {
// WebKit.DOM.Element? email_element = nodes.item(i) as WebKit.DOM.Element;
// if (email_element != null) {
// string? address = null;
// WebKit.DOM.Element? address_el = email_element.query_selector(".address_value");
// if (address_el != null) {
// address = ((WebKit.DOM.HTMLElement) address_el).get_inner_text();
// } else {
// address_el = email_element.query_selector(".address_name");
// if (address_el != null)
// address = ((WebKit.DOM.HTMLElement) address_el).get_inner_text();
// }
// if (address != null && address.normalize().casefold() == contact.normalized_email)
// show_images(false);
// }
// }
// } catch (Error error) {
// debug("Error showing images: %s", error.message);
// }
// }
// private void show_images(bool remember) {
// WebKit.DOM.Element email_element = get_email_element();
// try {
// WebKit.DOM.NodeList body_nodes = email_element.query_selector_all(".body");
// for (ulong j = 0; j < body_nodes.length; j++) {
// WebKit.DOM.Element? body = body_nodes.item(j) as WebKit.DOM.Element;
// if (body == null)
// continue;
// WebKit.DOM.NodeList nodes = body.query_selector_all("img");
// for (ulong i = 0; i < nodes.length; i++) {
// WebKit.DOM.Element? element = nodes.item(i) as WebKit.DOM.Element;
// if (element == null || !element.has_attribute("src"))
// continue;
// string src = element.get_attribute("src");
// if (!web_view.is_always_loaded(src)) {
// // Workaround a WebKitGTK+ 2.4.10 crash. See Bug 763933
// element.remove_attribute("src");
// element.set_attribute("src", web_view.allow_prefix + src);
// }
// }
// }
// WebKit.DOM.Element? remote_images = email_element.query_selector(".remote_images");
// if (remote_images != null)
// remote_images.get_class_list().remove("show");
// } catch (Error error) {
// warning("Error showing images: %s", error.message);
// }
// if (remember) {
// // only add flag to load remote images if not already present
// if (email != null && !email.load_remote_images().is_certain()) {
// Geary.EmailFlags flags = new Geary.EmailFlags();
// flags.add(Geary.EmailFlags.LOAD_REMOTE_IMAGES);
// get_viewer().mark_messages(Geary.iterate<Geary.EmailIdentifier>(email.id).to_array_list(), flags, null);
// }
// }
// }
// private void on_attachment_clicked(string attachment_id) {
// Geary.Attachment? attachment = null;
// try {
@ -1039,6 +947,66 @@ public class ConversationMessage : Gtk.Box {
}
}
private void show_images(bool remember) {
try {
WebKit.DOM.Element body = Util.DOM.select(
web_view.get_dom_document(), "body"
);
if (body == null) {
warning("Could not find message body");
} else {
WebKit.DOM.NodeList nodes = body.get_elements_by_tag_name("img");
for (ulong i = 0; i < nodes.length; i++) {
WebKit.DOM.Element? element = nodes.item(i) as WebKit.DOM.Element;
if (element == null || !element.has_attribute("src"))
continue;
string src = element.get_attribute("src");
if (!web_view.is_always_loaded(src)) {
// Workaround a WebKitGTK+ 2.4.10 crash. See Bug 763933
element.remove_attribute("src");
element.set_attribute("src", web_view.allow_prefix + src);
}
}
}
} catch (Error error) {
warning("Error showing images: %s", error.message);
}
if (remember) {
// only add flag to load remote images if not already present
if (email != null && !email.load_remote_images().is_certain()) {
Geary.EmailFlags flags = new Geary.EmailFlags();
flags.add(Geary.EmailFlags.LOAD_REMOTE_IMAGES);
// XXX reenable this
//get_viewer().mark_messages(Geary.iterate<Geary.EmailIdentifier>(email.id).to_array_list(), flags, null);
}
}
}
private void always_show_images() {
Geary.ContactStore contact_store =
containing_folder.account.get_contact_store();
Geary.Contact? contact = contact_store.get_by_rfc822(
email.get_primary_originator()
);
if (contact == null) {
debug("Couldn't find contact for %s", email.from.to_string());
return;
}
Geary.ContactFlags flags = new Geary.ContactFlags();
flags.add(Geary.ContactFlags.ALWAYS_LOAD_REMOTE_IMAGES);
Gee.ArrayList<Geary.Contact> contact_list = new Gee.ArrayList<Geary.Contact>();
contact_list.add(contact);
contact_store.mark_contacts_async.begin(contact_list, flags, null);
show_images(false);
// XXX notify something to go load images for the rest of the
// messages in he current convo for this sender
}
// private bool should_show_attachment(Geary.Attachment attachment) {
// // if displayed inline, don't include in attachment list
// if (attachment.content_id in inlined_content_ids)
@ -1293,6 +1261,24 @@ public class ConversationMessage : Gtk.Box {
body_box.set_tooltip_text(hover_url);
body_box.trigger_tooltip_query();
}
[GtkCallback]
private void on_remote_images_response(Gtk.InfoBar info_bar,
int response_id) {
switch (response_id) {
case 1:
show_images(true);
break;
case 2:
always_show_images();
break;
default:
break; // pass
}
remote_images_infobar.hide();
}
// private void on_copy_text() {
// web_view.copy_clipboard();

View file

@ -412,6 +412,105 @@
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkInfoBar" id="remote_images_infobar">
<property name="app_paintable">True</property>
<property name="can_focus">False</property>
<property name="no_show_all">True</property>
<property name="message_type">warning</property>
<property name="show_close_button">True</property>
<signal name="response" handler="on_remote_images_response" swapped="no"/>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can_focus">False</property>
<property name="spacing">6</property>
<property name="layout_style">end</property>
<child>
<object class="GtkButton" id="button1">
<property name="label" translatable="yes">Show Images</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="button2">
<property name="label" translatable="yes">Always Show From Sender</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="non_homogeneous">True</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Remote images not shown</property>
<property name="xalign">0</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Only show remote images from senders you trust.</property>
<property name="xalign">0</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<action-widgets>
<action-widget response="1">button1</action-widget>
<action-widget response="2">button2</action-widget>
</action-widgets>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>

View file

@ -82,6 +82,10 @@ row.geary-folder-popover-list-row > label {
#ConversationMessage separator {
margin: 12px 0;
}
#ConversationMessage infobar {
border-radius: 2px;
margin-bottom: 12px;
}
#composer_embed headerbar {
border-radius: 0px;