Update message header layout, use GtkFlowBox for addresses.

This takes some inspiration from the GNOME Mail mockups.

* src/client/components/main-window.vala (MainWindow::set_styling): Work
  around GtkFlowBoxChild padding issue.

* src/client/conversation-viewer/conversation-message.vala
  (ConversationMessage): Updated to populate new header labels, add
  addresses to GtkFlowBoxes.

* ui/conversation-message.ui: Make date always visible and
  right-aligned. Remove label for sender address. Use GtkFlowBoxes for
  sender/to/cc/bcc.
This commit is contained in:
Michael James Gratton 2016-06-10 10:56:18 -07:00
parent 6253001c4c
commit a97a371826
4 changed files with 230 additions and 210 deletions

View file

@ -79,26 +79,28 @@ public class ConversationMessage : Gtk.Box {
[GtkChild]
private Gtk.Image preview_avatar;
[GtkChild]
private Gtk.Label from_preview;
private Gtk.Label preview_from;
[GtkChild]
private Gtk.Label body_preview;
private Gtk.Label preview_date;
[GtkChild]
private Gtk.Label preview_body;
[GtkChild]
private Gtk.Revealer header_revealer;
[GtkChild]
private Gtk.Image header_avatar;
[GtkChild]
private Gtk.Box from_header;
private Gtk.FlowBox from;
[GtkChild]
private Gtk.Label subject;
[GtkChild]
private Gtk.Label date;
[GtkChild]
private Gtk.Box to_header;
[GtkChild]
private Gtk.Box cc_header;
[GtkChild]
private Gtk.Box bcc_header;
[GtkChild]
private Gtk.Box subject_header;
[GtkChild]
private Gtk.Box date_header;
[GtkChild]
private Gtk.Revealer body_revealer;
@ -201,36 +203,31 @@ public class ConversationMessage : Gtk.Box {
// Preview headers
from_preview.set_text(format_addresses(message.from));
string preview_str = message.get_preview();
preview_str = Geary.String.reduce_whitespace(preview_str);
body_preview.set_text(preview_str);
// Full headers
set_header_text(from_header, format_addresses(message.from));
if (message.to != null) {
set_header_text(to_header, format_addresses(message.to));
}
if (message.cc != null) {
set_header_text(cc_header, format_addresses(message.cc));
}
if (message.bcc != null) {
set_header_text(bcc_header, format_addresses(message.bcc));
}
if (message.subject != null) {
set_header_text(subject_header, message.subject.value);
}
string? message_date = null;
if (message.date != null) {
Date.ClockFormat clock_format =
GearyApplication.instance.config.clock_format;
set_header_text(
date_header,
Date.pretty_print_verbose(message.date.value, clock_format)
);
message_date = Date.pretty_print(message.date.value, clock_format);
}
preview_from.set_markup(format_sender_preview(message.from));
preview_date.set_text(message_date ?? "");
string preview_str = message.get_preview();
preview_str = Geary.String.reduce_whitespace(preview_str);
preview_body.set_text(preview_str);
// Full headers
set_flowbox_addresses(from, message.from, "bold");
date.set_text(message_date ?? "");
if (message.subject != null) {
subject.set_text(message.subject.value);
subject.set_visible(true);
}
set_header_addresses(to_header, message.to);
set_header_addresses(cc_header, message.cc);
set_header_addresses(bcc_header, message.bcc);
// Web view
web_view = new ConversationWebView();
@ -376,26 +373,77 @@ public class ConversationMessage : Gtk.Box {
}
}
// Appends email address fields to the header.
private string format_addresses(Geary.RFC822.MailboxAddresses? addresses) {
private void set_header_addresses(Gtk.Box header,
Geary.RFC822.MailboxAddresses? addresses) {
if (addresses != null && addresses.size > 0) {
Gtk.FlowBox box = header.get_children().nth(1).data as Gtk.FlowBox;
if (box != null) {
set_flowbox_addresses(box, addresses);
}
header.set_visible(true);
}
}
private void set_flowbox_addresses(Gtk.FlowBox address_box,
Geary.RFC822.MailboxAddresses? addresses,
string weight = "normal") {
string dim_color = GtkUtil.pango_color_from_theme(
address_box.get_style_context(), "insensitive_fg_color"
);
foreach (Geary.RFC822.MailboxAddress addr in addresses) {
Gtk.Label label = new Gtk.Label(null);
//label.set_halign(Gtk.Align.START);
//label.set_valign(Gtk.Align.BASELINE);
//label.set_ellipsize(Pango.EllipsizeMode.END);
//label.set_xalign(0.0f);
string name = Geary.HTML.escape_markup(addr.name);
string address = Geary.HTML.escape_markup(addr.address);
if (!Geary.String.is_empty(addr.name) && name != address) {
label.set_markup(
"<span weight=\"%s\">%s</span> <span color=\"%s\">%s</span>"
.printf(weight, name, dim_color, address)
);
} else {
label.set_markup(
"<span weight=\"%s\">%s</span>".printf(weight, address)
);
}
Gtk.FlowBoxChild child = new Gtk.FlowBoxChild();
child.add(label);
child.set_halign(Gtk.Align.START);
//child.set_valign(Gtk.Align.START);
child.show_all();
address_box.add(child);
}
}
private string format_sender_preview(Geary.RFC822.MailboxAddresses? addresses) {
string dim_color = GtkUtil.pango_color_from_theme(
get_style_context(), "insensitive_fg_color"
);
int i = 0;
string value = "";
Gee.List<Geary.RFC822.MailboxAddress> list = addresses.get_all();
foreach (Geary.RFC822.MailboxAddress a in list) {
value += a.to_string();
foreach (Geary.RFC822.MailboxAddress addr in list) {
string address = Geary.HTML.escape_markup(addr.address);
if (!Geary.String.is_empty(addr.name)) {
string name = Geary.HTML.escape_markup(addr.name);
value += "<span weight=\"bold\">%s</span> <span color=\"%s\">%s</span>".printf(
name, dim_color, address
);
} else {
value += "<span weight=\"bold\">%s</span>".printf(address);
}
if (++i < list.size)
value += ", ";
}
return value;
}
private static void set_header_text(Gtk.Box header, string text) {
((Gtk.Label) header.get_children().nth(1).data).set_text(text);
header.set_visible(true);
}
private void set_avatar(uint8[] image_data) {
Gdk.Pixbuf avatar = null;
Gdk.PixbufLoader loader = new Gdk.PixbufLoader();

View file

@ -120,6 +120,19 @@ void apply_style(Gtk.Widget widget, string style) {
}
}
/**
* Returns a Pango markup-compatible string for a GTK+ CSS theme color name.
*/
string pango_color_from_theme(Gtk.StyleContext style, string name) {
Gdk.RGBA colour = new Gdk.RGBA();
style.lookup_color(name, out colour);
return "#%02x%02x%02x".printf(
(uint) (256.0 * colour.red),
(uint) (256.0 * colour.green),
(uint) (256.0 * colour.blue)
);
}
/**
* This is not bound in Vala < 0.26.
*/

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
<requires lib="gtk+" version="3.12"/>
<requires lib="gtk+" version="3.14"/>
<template class="ConversationMessage" parent="GtkBox">
<property name="name">ConversationMessage</property>
<property name="visible">True</property>
@ -45,20 +45,50 @@
</packing>
</child>
<child>
<object class="GtkBox">
<object class="GtkBox" id="preview_bod">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkLabel" id="from_preview">
<object class="GtkBox">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">From &lt;email&gt;</property>
<property name="ellipsize">end</property>
<style>
<class name="header-value"/>
</style>
<child>
<object class="GtkLabel" id="preview_from">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">From &lt;email&gt;</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<style>
<class name="header-value"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="preview_date">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="valign">baseline</property>
<property name="margin_top">3</property>
<property name="label" translatable="yes">1/1/1970 </property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="xalign">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
@ -67,12 +97,13 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="body_preview">
<object class="GtkLabel" id="preview_body">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Preview body text.</property>
<property name="ellipsize">end</property>
<property name="xalign">0</property>
<style>
<class name="preview-value"/>
</style>
@ -85,7 +116,7 @@
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
@ -126,7 +157,7 @@
</packing>
</child>
<child>
<object class="GtkBox" id="header_box">
<object class="GtkBox" id="headers">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
@ -134,121 +165,101 @@
<object class="GtkBox" id="from_header">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkLabel" id="from_label">
<object class="GtkFlowBox" id="from">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">From:</property>
<property name="xalign">1</property>
<style>
<class name="header-label"/>
<class name="dim-label"/>
</style>
<property name="can_focus">True</property>
<property name="valign">baseline</property>
<property name="column_spacing">2</property>
<property name="min_children_per_line">1</property>
<property name="max_children_per_line">4</property>
<property name="selection_mode">none</property>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="from_text">
<object class="GtkLabel" id="date">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">From &lt;email&gt;</property>
<property name="valign">baseline</property>
<property name="label" translatable="yes">1/1/1970 </property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="xalign">1</property>
<style>
<class name="header-value"/>
<class name="geary-header-label"/>
</style>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox" id="to_header">
<object class="GtkLabel" id="subject">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="to_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">To:</property>
<property name="xalign">1</property>
<style>
<class name="header-label"/>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="to_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">To &lt;email&gt;</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<property name="halign">start</property>
<property name="valign">baseline</property>
<property name="label" translatable="yes">Subject</property>
<property name="wrap">True</property>
<property name="selectable">True</property>
<property name="xalign">0</property>
<style>
<class name="empty"/>
<class name="geary-header-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="cc_header">
<object class="GtkBox" id="to_header">
<property name="can_focus">False</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkLabel" id="cc_label">
<object class="GtkLabel" id="to_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Cc:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">To:</property>
<property name="yalign">0</property>
<style>
<class name="header-label"/>
<class name="dim-label"/>
<class name="geary-header-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="cc_text">
<object class="GtkFlowBox" id="to">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">CC &lt;email&gt;</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="can_focus">True</property>
<property name="valign">start</property>
<property name="hexpand">False</property>
<property name="column_spacing">2</property>
<property name="min_children_per_line">1</property>
<property name="max_children_per_line">4</property>
<property name="selection_mode">none</property>
</object>
<packing>
<property name="expand">True</property>
@ -256,44 +267,44 @@
<property name="position">1</property>
</packing>
</child>
<style>
<class name="empty"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkBox" id="bcc_header">
<object class="GtkBox" id="cc_header">
<property name="can_focus">False</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkLabel" id="bcc_label">
<object class="GtkLabel" id="cc_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Bcc:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Cc:</property>
<property name="yalign">0</property>
<style>
<class name="header-label"/>
<class name="dim-label"/>
<class name="geary-header-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="bcc_text">
<object class="GtkFlowBox" id="cc">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">BCC &lt;email&gt;</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="can_focus">True</property>
<property name="valign">start</property>
<property name="hexpand">False</property>
<property name="column_spacing">2</property>
<property name="min_children_per_line">1</property>
<property name="max_children_per_line">4</property>
<property name="selection_mode">none</property>
</object>
<packing>
<property name="expand">True</property>
@ -301,44 +312,44 @@
<property name="position">1</property>
</packing>
</child>
<style>
<class name="empty"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkBox" id="subject_header">
<object class="GtkBox" id="bcc_header">
<property name="can_focus">False</property>
<property name="baseline_position">top</property>
<child>
<object class="GtkLabel" id="subject_label">
<object class="GtkLabel" id="bcc_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Subject:</property>
<property name="xalign">1</property>
<property name="label" translatable="yes">Bcc:</property>
<property name="yalign">0</property>
<style>
<class name="header-label"/>
<class name="dim-label"/>
<class name="geary-header-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="subject_text">
<object class="GtkFlowBox" id="bcc">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Subject</property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
<property name="can_focus">True</property>
<property name="valign">start</property>
<property name="hexpand">False</property>
<property name="column_spacing">2</property>
<property name="min_children_per_line">2</property>
<property name="max_children_per_line">4</property>
<property name="selection_mode">none</property>
</object>
<packing>
<property name="expand">True</property>
@ -346,64 +357,19 @@
<property name="position">1</property>
</packing>
</child>
<style>
<class name="empty"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkBox" id="date_header">
<property name="can_focus">False</property>
<child>
<object class="GtkLabel" id="date_label">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Date:</property>
<property name="xalign">1</property>
<style>
<class name="header-label"/>
<class name="dim-label"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="date_text">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">1/1/1970 </property>
<property name="selectable">True</property>
<property name="ellipsize">end</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="empty"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">5</property>
</packing>
</child>
<style>
<class name="geary-headers"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
@ -575,17 +541,6 @@
</packing>
</child>
</template>
<object class="GtkSizeGroup" id="header_labels_sizegroup">
<property name="ignore_hidden">True</property>
<widgets>
<widget name="from_label"/>
<widget name="to_label"/>
<widget name="cc_label"/>
<widget name="bcc_label"/>
<widget name="subject_label"/>
<widget name="date_label"/>
</widgets>
</object>
<object class="GtkPopover" id="link_popover">
<property name="can_focus">False</property>
<property name="relative_to">body_box</property>

View file

@ -89,9 +89,13 @@ row.geary-folder-popover-list-row > label {
#ConversationMessage {
padding: 12px;
}
#ConversationMessage .header-label {
#ConversationMessage .geary-header-label {
margin-right: 6px;
}
#ConversationMessage .geary-headers flowboxchild {
margin: 0;
padding: 0;
}
#ConversationMessage separator {
margin: 12px 0;
}