From 6e1938b0893b47f0673bd773bdbfdbf6465ae018 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Fri, 12 Apr 2019 17:43:47 +0200 Subject: Clean up ConversationTitlebar --- .../ui/conversation_selector/conversation_row.vala | 277 --------------------- .../conversation_selector.vala | 167 +++++++++++++ .../conversation_selector_row.vala | 277 +++++++++++++++++++++ main/src/ui/conversation_selector/list.vala | 167 ------------- 4 files changed, 444 insertions(+), 444 deletions(-) delete mode 100644 main/src/ui/conversation_selector/conversation_row.vala create mode 100644 main/src/ui/conversation_selector/conversation_selector.vala create mode 100644 main/src/ui/conversation_selector/conversation_selector_row.vala delete mode 100644 main/src/ui/conversation_selector/list.vala (limited to 'main/src/ui/conversation_selector') diff --git a/main/src/ui/conversation_selector/conversation_row.vala b/main/src/ui/conversation_selector/conversation_row.vala deleted file mode 100644 index 0d0db23a..00000000 --- a/main/src/ui/conversation_selector/conversation_row.vala +++ /dev/null @@ -1,277 +0,0 @@ -using Gee; -using Gdk; -using Gtk; -using Pango; - -using Dino; -using Dino.Entities; -using Xmpp; - -namespace Dino.Ui.ConversationSelector { - -[GtkTemplate (ui = "/im/dino/Dino/conversation_selector/conversation_row.ui")] -public class ConversationRow : ListBoxRow { - - public signal void closed(); - - [GtkChild] protected AvatarImage image; - [GtkChild] protected Label name_label; - [GtkChild] protected Label time_label; - [GtkChild] protected Label nick_label; - [GtkChild] protected Label message_label; - [GtkChild] protected Button x_button; - [GtkChild] protected Revealer time_revealer; - [GtkChild] protected Revealer xbutton_revealer; - [GtkChild] public Revealer main_revealer; - - public Conversation conversation { get; private set; } - - protected const int AVATAR_SIZE = 40; - - protected ContentItem? last_content_item; - protected bool read = true; - - - protected StreamInteractor stream_interactor; - - construct { - name_label.attributes = new AttrList(); - } - - public ConversationRow(StreamInteractor stream_interactor, Conversation conversation) { - this.conversation = conversation; - this.stream_interactor = stream_interactor; - - switch (conversation.type_) { - case Conversation.Type.CHAT: - stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect((account, jid, roster_item) => { - if (conversation.account.equals(account) && conversation.counterpart.equals(jid)) { - update_name_label(); - } - }); - break; - case Conversation.Type.GROUPCHAT: - closed.connect(() => { - stream_interactor.get_module(MucManager.IDENTITY).part(conversation.account, conversation.counterpart); - }); - stream_interactor.get_module(MucManager.IDENTITY).room_name_set.connect((account, jid, room_name) => { - if (conversation != null && conversation.counterpart.equals_bare(jid) && conversation.account.equals(account)) { - update_name_label(); - } - }); - stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect((account, room, occupant) => { - if (conversation != null && conversation.counterpart.equals_bare(room.bare_jid) && conversation.account.equals(account)) { - update_name_label(); - } - }); - break; - case Conversation.Type.GROUPCHAT_PM: - break; - } - - // Set tooltip - switch (conversation.type_) { - case Conversation.Type.CHAT: - has_tooltip = true; - query_tooltip.connect ((x, y, keyboard_tooltip, tooltip) => { - tooltip.set_custom(generate_tooltip()); - return true; - }); - break; - case Conversation.Type.GROUPCHAT: - has_tooltip = true; - set_tooltip_text(conversation.counterpart.bare_jid.to_string()); - break; - case Conversation.Type.GROUPCHAT_PM: - break; - } - - stream_interactor.get_module(ContentItemStore.IDENTITY).new_item.connect((item, c) => { - if (conversation.equals(c)) { - content_item_received(item); - } - }); - last_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation); - - x_button.clicked.connect(close_conversation); - image.set_jid(stream_interactor, conversation.counterpart, conversation.account); - conversation.notify["read-up-to"].connect(update_read); - - update_name_label(); - content_item_received(); - } - - public void update() { - update_time_label(); - } - - public void content_item_received(ContentItem? ci = null) { - last_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation) ?? ci; - update_message_label(); - update_time_label(); - update_read(); - } - - protected void update_name_label() { - name_label.label = Util.get_conversation_display_name(stream_interactor, conversation); - } - - protected void update_time_label(DateTime? new_time = null) { - if (last_content_item != null) { - time_label.visible = true; - time_label.label = get_relative_time(last_content_item.display_time.to_local()); - } - } - - protected void update_message_label() { - if (last_content_item != null) { - switch (last_content_item.type_) { - case MessageItem.TYPE: - MessageItem message_item = last_content_item as MessageItem; - Message last_message = message_item.message; - - if (conversation.type_ == Conversation.Type.GROUPCHAT) { - nick_label.label = Util.get_message_display_name(stream_interactor, last_message, conversation.account) + ": "; - } else { - nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : ""; - } - - message_label.label = Markup.escape_text((/\s+/).replace_literal(last_message.body, -1, 0, " ")); - break; - case FileItem.TYPE: - FileItem file_item = last_content_item as FileItem; - FileTransfer transfer = file_item.file_transfer; - - if (conversation.type_ == Conversation.Type.GROUPCHAT) { - // TODO properly display nick for oneself - string nick = transfer.direction == Message.DIRECTION_SENT ? _("Me") : Util.get_display_name(stream_interactor, file_item.file_transfer.counterpart, conversation.account); - nick_label.label = nick + ": "; - } else { - nick_label.label = transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : ""; - } - - bool file_is_image = transfer.mime_type != null && transfer.mime_type.has_prefix("image"); - if (transfer.direction == Message.DIRECTION_SENT) { - message_label.label = "" + (file_is_image ? _("Image sent") : _("File sent") ) + ""; - } else { - message_label.label = "" + (file_is_image ? _("Image received") : _("File received") ) + ""; - } - break; - } - nick_label.visible = true; - message_label.visible = true; - } - } - - protected void update_read() { - MessageItem? message_item = last_content_item as MessageItem; - if (message_item == null) return; - Message last_message = message_item.message; - - bool read_was = read; - read = last_message == null || (conversation.read_up_to != null && last_message.equals(conversation.read_up_to)); - if (read == read_was) return; - if (read) { - name_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - time_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - nick_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - message_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); - } else { - name_label.attributes.insert(attr_weight_new(Weight.BOLD)); - time_label.attributes.insert(attr_weight_new(Weight.BOLD)); - nick_label.attributes.insert(attr_weight_new(Weight.BOLD)); - message_label.attributes.insert(attr_weight_new(Weight.BOLD)); - } - name_label.label = name_label.label; // TODO initializes redrawing, which would otherwise not happen. nicer? - time_label.label = time_label.label; - nick_label.label = nick_label.label; - message_label.label = message_label.label; - } - - protected Box get_fulljid_box(Jid full_jid) { - Box box = new Box(Orientation.HORIZONTAL, 5) { visible=true }; - - Show show = stream_interactor.get_module(PresenceManager.IDENTITY).get_last_show(full_jid, conversation.account); - Image image = new Image() { visible=true }; - if (show.as == Show.AWAY) { - image.set_from_icon_name("dino-status-away", IconSize.SMALL_TOOLBAR); - } else if (show.as == Show.XA || show.as == Show.DND) { - image.set_from_icon_name("dino-status-dnd", IconSize.SMALL_TOOLBAR); - } else if (show.as == Show.CHAT) { - image.set_from_icon_name("dino-status-chat", IconSize.SMALL_TOOLBAR); - } else { - image.set_from_icon_name("dino-status-online", IconSize.SMALL_TOOLBAR); - } - box.add(image); - - Label resource = new Label(full_jid.resourcepart) { visible=true }; - resource.xalign = 0; - box.add(resource); - box.show_all(); - return box; - } - - private void close_conversation() { - main_revealer.set_transition_type(RevealerTransitionType.SLIDE_UP); - main_revealer.set_reveal_child(false); - closed(); - main_revealer.notify["child-revealed"].connect(() => { - stream_interactor.get_module(ConversationManager.IDENTITY).close_conversation(conversation); - }); - } - - public override void state_flags_changed(StateFlags flags) { - StateFlags curr_flags = get_state_flags(); - if ((curr_flags & StateFlags.PRELIGHT) != 0) { - time_revealer.set_reveal_child(false); - xbutton_revealer.set_reveal_child(true); - } else { - time_revealer.set_reveal_child(true); - xbutton_revealer.set_reveal_child(false); - } - } - - private Widget generate_tooltip() { - Builder builder = new Builder.from_resource("/im/dino/Dino/conversation_selector/chat_row_tooltip.ui"); - Box main_box = builder.get_object("main_box") as Box; - Box inner_box = builder.get_object("inner_box") as Box; - Label jid_label = builder.get_object("jid_label") as Label; - - jid_label.label = conversation.counterpart.to_string(); - - Gee.List? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account); - if (full_jids != null) { - for (int i = 0; i < full_jids.size; i++) { - inner_box.add(get_fulljid_box(full_jids[i])); - } - } - return main_box; - } - - private static string get_relative_time(DateTime datetime) { - DateTime now = new DateTime.now_utc(); - TimeSpan timespan = now.difference(datetime); - if (timespan > 365 * TimeSpan.DAY) { - return datetime.get_year().to_string(); - } else if (timespan > 7 * TimeSpan.DAY) { - // Day and month - // xgettext:no-c-format - return datetime.format(_("%b %d")); - } else if (timespan > 2 * TimeSpan.DAY) { - return datetime.format("%a"); - } else if (datetime.get_day_of_month() != now.get_day_of_month()) { - return _("Yesterday"); - } else if (timespan > 9 * TimeSpan.MINUTE) { - return datetime.format(Util.is_24h_format() ? - /* xgettext:no-c-format */ /* Time in 24h format (w/o seconds) */ _("%H∶%M") : - /* xgettext:no-c-format */ /* Time in 12h format (w/o seconds) */ _("%l∶%M %p")); - } else if (timespan > 1 * TimeSpan.MINUTE) { - ulong mins = (ulong) (timespan.abs() / TimeSpan.MINUTE); - return n("%i min ago", "%i mins ago", mins).printf(mins); - } else { - return _("Just now"); - } - } -} - -} diff --git a/main/src/ui/conversation_selector/conversation_selector.vala b/main/src/ui/conversation_selector/conversation_selector.vala new file mode 100644 index 00000000..d795120b --- /dev/null +++ b/main/src/ui/conversation_selector/conversation_selector.vala @@ -0,0 +1,167 @@ +using Gee; +using Gtk; + +using Xmpp; +using Dino.Entities; + +namespace Dino.Ui { + +public class ConversationSelector : ListBox { + + public signal void conversation_selected(Conversation conversation); + + private StreamInteractor stream_interactor; + private string[]? filter_values; + private HashMap rows = new HashMap(Conversation.hash_func, Conversation.equals_func); + + public ConversationSelector init(StreamInteractor stream_interactor) { + this.stream_interactor = stream_interactor; + + stream_interactor.get_module(ConversationManager.IDENTITY).conversation_activated.connect(add_conversation); + stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(remove_conversation); + stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received); + stream_interactor.get_module(MessageProcessor.IDENTITY).message_sent.connect(on_message_received); + Timeout.add_seconds(60, () => { + foreach (ConversationSelectorRow row in rows.values) row.update(); + return true; + }); + + foreach (Conversation conversation in stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations()) { + add_conversation(conversation); + } + return this; + } + + construct { + this.stream_interactor = stream_interactor; + + get_style_context().add_class("sidebar"); + set_filter_func(filter); + set_header_func(header); + set_sort_func(sort); + + realize.connect(() => { + ListBoxRow? first_row = get_row_at_index(0); + if (first_row != null) { + select_row(first_row); + row_activated(first_row); + } + }); + } + + public override void row_activated(ListBoxRow r) { + ConversationSelectorRow? row = r as ConversationSelectorRow; + if (row != null) { + conversation_selected(row.conversation); + } + } + + public void set_filter_values(string[]? values) { + if (filter_values == values) { + return; + } + filter_values = values; + invalidate_filter(); + } + + public void on_conversation_selected(Conversation conversation) { + if (!rows.has_key(conversation)) { + add_conversation(conversation); + } + this.select_row(rows[conversation]); + } + + private void on_message_received(Entities.Message message, Conversation conversation) { + if (rows.has_key(conversation)) { + invalidate_sort(); + } + } + + private void add_conversation(Conversation conversation) { + ConversationSelectorRow row; + if (!rows.has_key(conversation)) { + row = new ConversationSelectorRow(stream_interactor, conversation); + rows[conversation] = row; + add(row); + row.closed.connect(() => { select_fallback_conversation(conversation); }); + row.main_revealer.set_reveal_child(true); + } + invalidate_sort(); + } + + private void select_fallback_conversation(Conversation conversation) { + if (get_selected_row() == rows[conversation]) { + int index = rows[conversation].get_index(); + ListBoxRow? next_select_row = get_row_at_index(index + 1); + if (next_select_row == null) { + next_select_row = get_row_at_index(index - 1); + } + if (next_select_row != null) { + select_row(next_select_row); + row_activated(next_select_row); + } + } + } + + private void remove_conversation(Conversation conversation) { + select_fallback_conversation(conversation); + if (rows.has_key(conversation) && !conversation.active) { + remove(rows[conversation]); + rows.unset(conversation); + } + } + + public void loop_conversations(bool backwards) { + int index = get_selected_row().get_index(); + int new_index = ((index + (backwards ? -1 : 1)) + rows.size) % rows.size; + ListBoxRow? next_select_row = get_row_at_index(new_index); + if (next_select_row != null) { + select_row(next_select_row); + row_activated(next_select_row); + } + } + + private void header(ListBoxRow row, ListBoxRow? before_row) { + if (row.get_header() == null && before_row != null) { + row.set_header(new Separator(Orientation.HORIZONTAL)); + } else if (row.get_header() != null && before_row == null) { + row.set_header(null); + } + } + + private bool filter(ListBoxRow r) { + ConversationSelectorRow? row = r as ConversationSelectorRow; + if (row != null) { + if (filter_values != null && filter_values.length != 0) { + foreach (string filter in filter_values) { + if (!(Util.get_conversation_display_name(stream_interactor, row.conversation).down().contains(filter.down()) || + row.conversation.counterpart.to_string().down().contains(filter.down()))) { + return false; + } + } + } + } + return true; + } + + private int sort(ListBoxRow row1, ListBoxRow row2) { + ConversationSelectorRow cr1 = row1 as ConversationSelectorRow; + ConversationSelectorRow cr2 = row2 as ConversationSelectorRow; + if (cr1 != null && cr2 != null) { + Conversation c1 = cr1.conversation; + Conversation c2 = cr2.conversation; + if (c1.last_active == null) return -1; + if (c2.last_active == null) return 1; + int comp = c2.last_active.compare(c1.last_active); + if (comp == 0) { + return Util.get_conversation_display_name(stream_interactor, c1) + .collate(Util.get_conversation_display_name(stream_interactor, c2)); + } else { + return comp; + } + } + return 0; + } +} + +} diff --git a/main/src/ui/conversation_selector/conversation_selector_row.vala b/main/src/ui/conversation_selector/conversation_selector_row.vala new file mode 100644 index 00000000..a1f0e706 --- /dev/null +++ b/main/src/ui/conversation_selector/conversation_selector_row.vala @@ -0,0 +1,277 @@ +using Gee; +using Gdk; +using Gtk; +using Pango; + +using Dino; +using Dino.Entities; +using Xmpp; + +namespace Dino.Ui { + +[GtkTemplate (ui = "/im/dino/Dino/conversation_selector/conversation_row.ui")] +public class ConversationSelectorRow : ListBoxRow { + + public signal void closed(); + + [GtkChild] protected AvatarImage image; + [GtkChild] protected Label name_label; + [GtkChild] protected Label time_label; + [GtkChild] protected Label nick_label; + [GtkChild] protected Label message_label; + [GtkChild] protected Button x_button; + [GtkChild] protected Revealer time_revealer; + [GtkChild] protected Revealer xbutton_revealer; + [GtkChild] public Revealer main_revealer; + + public Conversation conversation { get; private set; } + + protected const int AVATAR_SIZE = 40; + + protected ContentItem? last_content_item; + protected bool read = true; + + + protected StreamInteractor stream_interactor; + + construct { + name_label.attributes = new AttrList(); + } + + public ConversationSelectorRow(StreamInteractor stream_interactor, Conversation conversation) { + this.conversation = conversation; + this.stream_interactor = stream_interactor; + + switch (conversation.type_) { + case Conversation.Type.CHAT: + stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect((account, jid, roster_item) => { + if (conversation.account.equals(account) && conversation.counterpart.equals(jid)) { + update_name_label(); + } + }); + break; + case Conversation.Type.GROUPCHAT: + closed.connect(() => { + stream_interactor.get_module(MucManager.IDENTITY).part(conversation.account, conversation.counterpart); + }); + stream_interactor.get_module(MucManager.IDENTITY).room_name_set.connect((account, jid, room_name) => { + if (conversation != null && conversation.counterpart.equals_bare(jid) && conversation.account.equals(account)) { + update_name_label(); + } + }); + stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect((account, room, occupant) => { + if (conversation != null && conversation.counterpart.equals_bare(room.bare_jid) && conversation.account.equals(account)) { + update_name_label(); + } + }); + break; + case Conversation.Type.GROUPCHAT_PM: + break; + } + + // Set tooltip + switch (conversation.type_) { + case Conversation.Type.CHAT: + has_tooltip = true; + query_tooltip.connect ((x, y, keyboard_tooltip, tooltip) => { + tooltip.set_custom(generate_tooltip()); + return true; + }); + break; + case Conversation.Type.GROUPCHAT: + has_tooltip = true; + set_tooltip_text(conversation.counterpart.bare_jid.to_string()); + break; + case Conversation.Type.GROUPCHAT_PM: + break; + } + + stream_interactor.get_module(ContentItemStore.IDENTITY).new_item.connect((item, c) => { + if (conversation.equals(c)) { + content_item_received(item); + } + }); + last_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation); + + x_button.clicked.connect(close_conversation); + image.set_jid(stream_interactor, conversation.counterpart, conversation.account); + conversation.notify["read-up-to"].connect(update_read); + + update_name_label(); + content_item_received(); + } + + public void update() { + update_time_label(); + } + + public void content_item_received(ContentItem? ci = null) { + last_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation) ?? ci; + update_message_label(); + update_time_label(); + update_read(); + } + + protected void update_name_label() { + name_label.label = Util.get_conversation_display_name(stream_interactor, conversation); + } + + protected void update_time_label(DateTime? new_time = null) { + if (last_content_item != null) { + time_label.visible = true; + time_label.label = get_relative_time(last_content_item.display_time.to_local()); + } + } + + protected void update_message_label() { + if (last_content_item != null) { + switch (last_content_item.type_) { + case MessageItem.TYPE: + MessageItem message_item = last_content_item as MessageItem; + Message last_message = message_item.message; + + if (conversation.type_ == Conversation.Type.GROUPCHAT) { + nick_label.label = Util.get_message_display_name(stream_interactor, last_message, conversation.account) + ": "; + } else { + nick_label.label = last_message.direction == Message.DIRECTION_SENT ? _("Me") + ": " : ""; + } + + message_label.label = Markup.escape_text((/\s+/).replace_literal(last_message.body, -1, 0, " ")); + break; + case FileItem.TYPE: + FileItem file_item = last_content_item as FileItem; + FileTransfer transfer = file_item.file_transfer; + + if (conversation.type_ == Conversation.Type.GROUPCHAT) { + // TODO properly display nick for oneself + string nick = transfer.direction == Message.DIRECTION_SENT ? _("Me") : Util.get_display_name(stream_interactor, file_item.file_transfer.counterpart, conversation.account); + nick_label.label = nick + ": "; + } else { + nick_label.label = transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : ""; + } + + bool file_is_image = transfer.mime_type != null && transfer.mime_type.has_prefix("image"); + if (transfer.direction == Message.DIRECTION_SENT) { + message_label.label = "" + (file_is_image ? _("Image sent") : _("File sent") ) + ""; + } else { + message_label.label = "" + (file_is_image ? _("Image received") : _("File received") ) + ""; + } + break; + } + nick_label.visible = true; + message_label.visible = true; + } + } + + protected void update_read() { + MessageItem? message_item = last_content_item as MessageItem; + if (message_item == null) return; + Message last_message = message_item.message; + + bool read_was = read; + read = last_message == null || (conversation.read_up_to != null && last_message.equals(conversation.read_up_to)); + if (read == read_was) return; + if (read) { + name_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); + time_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); + nick_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); + message_label.attributes.filter((attr) => attr.equal(attr_weight_new(Weight.BOLD))); + } else { + name_label.attributes.insert(attr_weight_new(Weight.BOLD)); + time_label.attributes.insert(attr_weight_new(Weight.BOLD)); + nick_label.attributes.insert(attr_weight_new(Weight.BOLD)); + message_label.attributes.insert(attr_weight_new(Weight.BOLD)); + } + name_label.label = name_label.label; // TODO initializes redrawing, which would otherwise not happen. nicer? + time_label.label = time_label.label; + nick_label.label = nick_label.label; + message_label.label = message_label.label; + } + + protected Box get_fulljid_box(Jid full_jid) { + Box box = new Box(Orientation.HORIZONTAL, 5) { visible=true }; + + Show show = stream_interactor.get_module(PresenceManager.IDENTITY).get_last_show(full_jid, conversation.account); + Image image = new Image() { visible=true }; + if (show.as == Show.AWAY) { + image.set_from_icon_name("dino-status-away", IconSize.SMALL_TOOLBAR); + } else if (show.as == Show.XA || show.as == Show.DND) { + image.set_from_icon_name("dino-status-dnd", IconSize.SMALL_TOOLBAR); + } else if (show.as == Show.CHAT) { + image.set_from_icon_name("dino-status-chat", IconSize.SMALL_TOOLBAR); + } else { + image.set_from_icon_name("dino-status-online", IconSize.SMALL_TOOLBAR); + } + box.add(image); + + Label resource = new Label(full_jid.resourcepart) { visible=true }; + resource.xalign = 0; + box.add(resource); + box.show_all(); + return box; + } + + private void close_conversation() { + main_revealer.set_transition_type(RevealerTransitionType.SLIDE_UP); + main_revealer.set_reveal_child(false); + closed(); + main_revealer.notify["child-revealed"].connect(() => { + stream_interactor.get_module(ConversationManager.IDENTITY).close_conversation(conversation); + }); + } + + public override void state_flags_changed(StateFlags flags) { + StateFlags curr_flags = get_state_flags(); + if ((curr_flags & StateFlags.PRELIGHT) != 0) { + time_revealer.set_reveal_child(false); + xbutton_revealer.set_reveal_child(true); + } else { + time_revealer.set_reveal_child(true); + xbutton_revealer.set_reveal_child(false); + } + } + + private Widget generate_tooltip() { + Builder builder = new Builder.from_resource("/im/dino/Dino/conversation_selector/chat_row_tooltip.ui"); + Box main_box = builder.get_object("main_box") as Box; + Box inner_box = builder.get_object("inner_box") as Box; + Label jid_label = builder.get_object("jid_label") as Label; + + jid_label.label = conversation.counterpart.to_string(); + + Gee.List? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account); + if (full_jids != null) { + for (int i = 0; i < full_jids.size; i++) { + inner_box.add(get_fulljid_box(full_jids[i])); + } + } + return main_box; + } + + private static string get_relative_time(DateTime datetime) { + DateTime now = new DateTime.now_utc(); + TimeSpan timespan = now.difference(datetime); + if (timespan > 365 * TimeSpan.DAY) { + return datetime.get_year().to_string(); + } else if (timespan > 7 * TimeSpan.DAY) { + // Day and month + // xgettext:no-c-format + return datetime.format(_("%b %d")); + } else if (timespan > 2 * TimeSpan.DAY) { + return datetime.format("%a"); + } else if (datetime.get_day_of_month() != now.get_day_of_month()) { + return _("Yesterday"); + } else if (timespan > 9 * TimeSpan.MINUTE) { + return datetime.format(Util.is_24h_format() ? + /* xgettext:no-c-format */ /* Time in 24h format (w/o seconds) */ _("%H∶%M") : + /* xgettext:no-c-format */ /* Time in 12h format (w/o seconds) */ _("%l∶%M %p")); + } else if (timespan > 1 * TimeSpan.MINUTE) { + ulong mins = (ulong) (timespan.abs() / TimeSpan.MINUTE); + return n("%i min ago", "%i mins ago", mins).printf(mins); + } else { + return _("Just now"); + } + } +} + +} diff --git a/main/src/ui/conversation_selector/list.vala b/main/src/ui/conversation_selector/list.vala deleted file mode 100644 index 95e5aae7..00000000 --- a/main/src/ui/conversation_selector/list.vala +++ /dev/null @@ -1,167 +0,0 @@ -using Gee; -using Gtk; - -using Xmpp; -using Dino.Entities; - -namespace Dino.Ui.ConversationSelector { - -public class List : ListBox { - - public signal void conversation_selected(Conversation conversation); - - private StreamInteractor stream_interactor; - private string[]? filter_values; - private HashMap rows = new HashMap(Conversation.hash_func, Conversation.equals_func); - - public List init(StreamInteractor stream_interactor) { - this.stream_interactor = stream_interactor; - - stream_interactor.get_module(ConversationManager.IDENTITY).conversation_activated.connect(add_conversation); - stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(remove_conversation); - stream_interactor.get_module(MessageProcessor.IDENTITY).message_received.connect(on_message_received); - stream_interactor.get_module(MessageProcessor.IDENTITY).message_sent.connect(on_message_received); - Timeout.add_seconds(60, () => { - foreach (ConversationRow row in rows.values) row.update(); - return true; - }); - - foreach (Conversation conversation in stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations()) { - add_conversation(conversation); - } - return this; - } - - construct { - this.stream_interactor = stream_interactor; - - get_style_context().add_class("sidebar"); - set_filter_func(filter); - set_header_func(header); - set_sort_func(sort); - - realize.connect(() => { - ListBoxRow? first_row = get_row_at_index(0); - if (first_row != null) { - select_row(first_row); - row_activated(first_row); - } - }); - } - - public override void row_activated(ListBoxRow r) { - if (r.get_type().is_a(typeof(ConversationRow))) { - ConversationRow row = r as ConversationRow; - conversation_selected(row.conversation); - } - } - - public void set_filter_values(string[]? values) { - if (filter_values == values) { - return; - } - filter_values = values; - invalidate_filter(); - } - - public void on_conversation_selected(Conversation conversation) { - if (!rows.has_key(conversation)) { - add_conversation(conversation); - } - this.select_row(rows[conversation]); - } - - private void on_message_received(Entities.Message message, Conversation conversation) { - if (rows.has_key(conversation)) { - invalidate_sort(); - } - } - - private void add_conversation(Conversation conversation) { - ConversationRow row; - if (!rows.has_key(conversation)) { - row = new ConversationRow(stream_interactor, conversation); - rows[conversation] = row; - add(row); - row.closed.connect(() => { select_fallback_conversation(conversation); }); - row.main_revealer.set_reveal_child(true); - } - invalidate_sort(); - } - - private void select_fallback_conversation(Conversation conversation) { - if (get_selected_row() == rows[conversation]) { - int index = rows[conversation].get_index(); - ListBoxRow? next_select_row = get_row_at_index(index + 1); - if (next_select_row == null) { - next_select_row = get_row_at_index(index - 1); - } - if (next_select_row != null) { - select_row(next_select_row); - row_activated(next_select_row); - } - } - } - - private void remove_conversation(Conversation conversation) { - select_fallback_conversation(conversation); - if (rows.has_key(conversation) && !conversation.active) { - remove(rows[conversation]); - rows.unset(conversation); - } - } - - public void loop_conversations(bool backwards) { - int index = get_selected_row().get_index(); - int new_index = ((index + (backwards ? -1 : 1)) + rows.size) % rows.size; - ListBoxRow? next_select_row = get_row_at_index(new_index); - if (next_select_row != null) { - select_row(next_select_row); - row_activated(next_select_row); - } - } - - private void header(ListBoxRow row, ListBoxRow? before_row) { - if (row.get_header() == null && before_row != null) { - row.set_header(new Separator(Orientation.HORIZONTAL)); - } else if (row.get_header() != null && before_row == null) { - row.set_header(null); - } - } - - private bool filter(ListBoxRow r) { - if (r.get_type().is_a(typeof(ConversationRow))) { - ConversationRow row = r as ConversationRow; - if (filter_values != null && filter_values.length != 0) { - foreach (string filter in filter_values) { - if (!(Util.get_conversation_display_name(stream_interactor, row.conversation).down().contains(filter.down()) || - row.conversation.counterpart.to_string().down().contains(filter.down()))) { - return false; - } - } - } - } - return true; - } - - private int sort(ListBoxRow row1, ListBoxRow row2) { - ConversationRow cr1 = row1 as ConversationRow; - ConversationRow cr2 = row2 as ConversationRow; - if (cr1 != null && cr2 != null) { - Conversation c1 = cr1.conversation; - Conversation c2 = cr2.conversation; - if (c1.last_active == null) return -1; - if (c2.last_active == null) return 1; - int comp = c2.last_active.compare(c1.last_active); - if (comp == 0) { - return Util.get_conversation_display_name(stream_interactor, c1) - .collate(Util.get_conversation_display_name(stream_interactor, c2)); - } else { - return comp; - } - } - return 0; - } -} - -} -- cgit v1.2.3-54-g00ecf