diff --git a/data/application.css b/data/application.css index acccbdbbe..2f4f182cf 100644 --- a/data/application.css +++ b/data/application.css @@ -7,8 +7,27 @@ ); } -.card.collapsed { - margin-bottom: -64px; +.message-list list { + padding: 0 1rem 0.25rem; +} + +.message-list list > .h4 { + font-size: 1.25rem; + font-weight: 600; + padding: 0.75rem 0; +} + +.message-list list > .h4 + .h4 { + margin-bottom: 2.75em; +} + +.message-list-item { + margin: 0.75rem 0; +} + +.message-list-item.collapsed + .message-list-item { + margin-top: -3.25em; + margin-bottom: 1em; } .conversation-list-item { diff --git a/src/MessageList/MessageList.vala b/src/MessageList/MessageList.vala index 7432d6383..06ebda3c5 100644 --- a/src/MessageList/MessageList.vala +++ b/src/MessageList/MessageList.vala @@ -15,6 +15,7 @@ public class Mail.MessageList : Gtk.Box { construct { get_style_context ().add_class (Gtk.STYLE_CLASS_BACKGROUND); + get_style_context ().add_class ("message-list"); var application_instance = (Gtk.Application) GLib.Application.get_default (); @@ -169,6 +170,7 @@ public class Mail.MessageList : Gtk.Box { list_box.get_style_context ().add_class (Gtk.STYLE_CLASS_BACKGROUND); list_box.set_placeholder (placeholder); list_box.set_sort_func (message_sort_function); + list_box.set_header_func (message_header_func); scrolled_window = new Gtk.ScrolledWindow (null, null) { hscrollbar_policy = NEVER @@ -300,6 +302,35 @@ public class Mail.MessageList : Gtk.Box { ((SimpleAction) main_window.lookup_action (MainWindow.ACTION_MOVE_TO_TRASH)).set_enabled (enabled); } + private void message_header_func (Gtk.ListBoxRow row, Gtk.ListBoxRow? before) { + unowned var message = (MessageListItem) row; + unowned var message_before = (MessageListItem) before; + + var subject = message.message_info.subject; + + if (message_before == null || message_before != null && sanitize_subject (message_before.message_info.subject) != sanitize_subject (subject)) { + if (subject == "") { + subject = _("No Subject"); + } + + var header_label = new Granite.HeaderLabel (subject) { + wrap = true, + }; + + row.set_header (header_label); + } + } + + private string sanitize_subject (string _subject) { + var subject = _subject.down (); + subject = subject.replace (" ", ""); + subject = subject.replace (":", ""); + subject = subject.replace ("re", ""); + subject = subject.replace ("fwd", ""); + + return subject; + } + private static int message_sort_function (Gtk.ListBoxRow item1, Gtk.ListBoxRow item2) { unowned MessageListItem message1 = (MessageListItem)item1; unowned MessageListItem message2 = (MessageListItem)item2; diff --git a/src/MessageList/MessageListItem.vala b/src/MessageList/MessageListItem.vala index 3d61762d8..fe156b412 100644 --- a/src/MessageList/MessageListItem.vala +++ b/src/MessageList/MessageListItem.vala @@ -27,8 +27,8 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { private GLib.Cancellable loading_cancellable; private Gtk.InfoBar blocked_images_infobar; + private Gtk.Revealer fields_revealer; private Gtk.Revealer secondary_revealer; - private Gtk.Stack header_stack; private Gtk.StyleContext style_context; private Hdy.Avatar avatar; private Gtk.FlowBox attachment_bar = null; @@ -46,7 +46,7 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { } set { secondary_revealer.reveal_child = value; - header_stack.set_visible_child_name (value ? "large" : "small"); + fields_revealer.reveal_child = value; if (value) { if (!message_loaded) { get_message.begin (); @@ -63,10 +63,6 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { public MessageListItem (Camel.MessageInfo message_info) { Object ( - margin_top: 12, - margin_bottom: 12, - margin_start: 12, - margin_end: 12, message_info: message_info ); } @@ -81,6 +77,7 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { style_context = get_style_context (); style_context.add_class (Granite.STYLE_CLASS_CARD); + style_context.add_class ("message-list-item"); unowned string? parsed_address; unowned string? parsed_name; @@ -93,53 +90,59 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { parsed_name = parsed_address; } - avatar = new Hdy.Avatar (48, parsed_name, true) { - valign = Gtk.Align.START + avatar = new Hdy.Avatar (40, parsed_name, true) { + valign = START }; - var from_label = new Gtk.Label (_("From:")) { - halign = END, - valign = START + var from_label = new Gtk.Label (message_info.from) { + wrap = true, + xalign = 0 }; - from_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); var to_label = new Gtk.Label (_("To:")) { - halign = END, - valign = START + halign = END }; to_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - var subject_label = new Gtk.Label (_("Subject:")) { - halign = END, - valign = START - }; - subject_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - - var from_val_label = new Gtk.Label (message_info.from) { + var to_val_label = new Gtk.Label (message_info.to) { + hexpand = true, wrap = true, xalign = 0 }; - var to_val_label = new Gtk.Label (message_info.to) { - wrap = true, - xalign = 0 + var relevant_timestamp = message_info.date_received; + if (relevant_timestamp == 0) { + // Sent messages do not have a date_received timestamp. + relevant_timestamp = message_info.date_sent; + } + + var date_format = Granite.DateTime.get_default_date_format (false, true, true); + var time_format = Granite.DateTime.get_default_time_format (desktop_settings.get_enum ("clock-format") == 1, false); + + var datetime_label = new Gtk.Label ( + ///TRANSLATORS: The first %s represents the date and the second %s the time of the message (either when it was received or sent) + new DateTime.from_unix_utc (relevant_timestamp).to_local ().format (_("%s at %s").printf (date_format, time_format)) + ) { + halign = END, + valign = START }; + datetime_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - var subject_val_label = new Gtk.Label (message_info.subject) { - wrap = true, - xalign = 0 + var action_box = new Gtk.Box (HORIZONTAL, 6) { + halign = END, + hexpand = true }; var fields_grid = new Gtk.Grid () { - column_spacing = 6, - row_spacing = 6 + column_spacing = 3, + margin_top = 3 }; - fields_grid.attach (from_label, 0, 0, 1, 1); - fields_grid.attach (to_label, 0, 1, 1, 1); - fields_grid.attach (subject_label, 0, 3, 1, 1); - fields_grid.attach (from_val_label, 1, 0, 1, 1); - fields_grid.attach (to_val_label, 1, 1, 1, 1); - fields_grid.attach (subject_val_label, 1, 3, 1, 1); + fields_grid.attach (to_label, 0, 0); + fields_grid.attach (to_val_label, 1, 0); + fields_grid.attach (action_box, 2, 0); + + fields_revealer = new Gtk.Revealer (); + fields_revealer.add (fields_grid); var cc_info = message_info.cc; if (cc_info != null) { @@ -154,55 +157,25 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { xalign = 0 }; - fields_grid.attach (cc_label, 0, 2, 1, 1); - fields_grid.attach (cc_val_label, 1, 2, 1, 1); + fields_grid.attach (cc_label, 0, 1); + fields_grid.attach (cc_val_label, 1, 1); } - var small_from_label = new Gtk.Label (message_info.from) { - ellipsize = END, - xalign = 0 - }; - - var small_fields_grid = new Gtk.Grid (); - small_fields_grid.attach (small_from_label, 0, 0, 1, 1); + var starred_icon = new Gtk.Image (); - header_stack = new Gtk.Stack () { - homogeneous = false, - transition_type = CROSSFADE + var starred_button = new Gtk.Button () { + child = starred_icon }; - header_stack.add_named (fields_grid, "large"); - header_stack.add_named (small_fields_grid, "small"); - header_stack.show_all (); - - var relevant_timestamp = message_info.date_received; - if (relevant_timestamp == 0) { - // Sent messages do not have a date_received timestamp. - relevant_timestamp = message_info.date_sent; - } - - var date_format = Granite.DateTime.get_default_date_format (false, true, true); - var time_format = Granite.DateTime.get_default_time_format (desktop_settings.get_enum ("clock-format") == 1, false); - - ///TRANSLATORS: The first %s represents the date and the second %s the time of the message (either when it was received or sent) - var datetime_label = new Gtk.Label (new DateTime.from_unix_utc (relevant_timestamp).to_local ().format (_("%s at %s").printf (date_format, time_format))); - datetime_label.get_style_context ().add_class (Gtk.STYLE_CLASS_DIM_LABEL); - - var starred_icon = new Gtk.Image (); - starred_icon.icon_size = Gtk.IconSize.MENU; + starred_button.get_style_context ().add_class ("image-button"); if (Camel.MessageFlags.FLAGGED in (int) message_info.flags) { starred_icon.icon_name = "starred-symbolic"; - starred_icon.tooltip_text = _("Unstar message"); + starred_button.tooltip_text = _("Unstar message"); } else { starred_icon.icon_name = "non-starred-symbolic"; - starred_icon.tooltip_text = _("Star message"); + starred_button.tooltip_text = _("Star message"); } - var starred_button = new Gtk.Button () { - child = starred_icon - }; - starred_button.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); - var upper_section = new Menu (); upper_section.append (_("Reply"), Action.print_detailed_name ( MainWindow.ACTION_PREFIX + MainWindow.ACTION_REPLY, message_info.uid @@ -226,34 +199,26 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { var actions_menu_button = new Gtk.MenuButton () { image = new Gtk.Image.from_icon_name ("view-more-symbolic", Gtk.IconSize.MENU), tooltip_text = _("More"), - margin_top = 6, - valign = START, - halign = END, menu_model = actions_menu, use_popover = false }; actions_menu_button.get_style_context ().add_class (Gtk.STYLE_CLASS_FLAT); - var action_grid = new Gtk.Grid () { - column_spacing = 3, - hexpand = true, - halign = END, + var header_vgrid = new Gtk.Grid () { valign = START }; - action_grid.attach (datetime_label, 0, 0); - action_grid.attach (starred_button, 2, 0); - action_grid.attach (actions_menu_button, 2, 1); + header_vgrid.attach (from_label, 0, 0); + header_vgrid.attach (datetime_label, 1, 0); + header_vgrid.attach (fields_revealer, 0, 1, 2); - var header = new Gtk.Grid () { + var header = new Gtk.Box (HORIZONTAL, 12) { margin_top = 12, margin_bottom = 12, margin_start = 12, - margin_end = 12, - column_spacing = 12 + margin_end = 12 }; - header.attach (avatar, 0, 0, 1, 3); - header.attach (header_stack, 1, 0, 1, 3); - header.attach (action_grid, 2, 0); + header.add (avatar); + header.add (header_vgrid); var header_event_box = new Gtk.EventBox (); header_event_box.events |= Gdk.EventMask.ENTER_NOTIFY_MASK; @@ -315,10 +280,10 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { base_box.add (secondary_revealer); if (Camel.MessageFlags.ATTACHMENTS in (int) message_info.flags) { - var attachment_icon = new Gtk.Image.from_icon_name ("mail-attachment-symbolic", Gtk.IconSize.MENU); - attachment_icon.margin_start = 6; - attachment_icon.tooltip_text = _("This message contains one or more attachments"); - action_grid.attach (attachment_icon, 1, 0); + var attachment_icon = new Gtk.Image.from_icon_name ("mail-attachment-symbolic", Gtk.IconSize.MENU) { + tooltip_text = _("This message contains one or more attachments") + }; + action_box.add (attachment_icon); attachment_bar = new Gtk.FlowBox () { hexpand = true, @@ -329,6 +294,9 @@ public class Mail.MessageListItem : Gtk.ListBoxRow { secondary_box.add (attachment_bar); } + action_box.add (starred_button); + action_box.add (actions_menu_button); + add (base_box); expanded = false; show_all ();