From f277db6cb459c6e7456fb75722b9d57f734c4db6 Mon Sep 17 00:00:00 2001 From: fiaxh Date: Wed, 15 Mar 2017 21:37:49 +0100 Subject: Display /me differently fixes #12 --- .../ui/conversation_summary/conversation_item.vala | 34 ++++ .../conversation_summary/merged_message_item.vala | 180 +++------------------ .../conversation_summary/merged_status_item.vala | 31 ---- main/src/ui/conversation_summary/message_item.vala | 112 +++++++++++++ .../ui/conversation_summary/message_textview.vala | 87 ++++++++++ main/src/ui/conversation_summary/slashme_item.vala | 43 +++++ main/src/ui/conversation_summary/status_item.vala | 2 +- main/src/ui/conversation_summary/view.vala | 43 ++--- 8 files changed, 318 insertions(+), 214 deletions(-) create mode 100644 main/src/ui/conversation_summary/conversation_item.vala delete mode 100644 main/src/ui/conversation_summary/merged_status_item.vala create mode 100644 main/src/ui/conversation_summary/message_item.vala create mode 100644 main/src/ui/conversation_summary/message_textview.vala create mode 100644 main/src/ui/conversation_summary/slashme_item.vala (limited to 'main/src/ui/conversation_summary') diff --git a/main/src/ui/conversation_summary/conversation_item.vala b/main/src/ui/conversation_summary/conversation_item.vala new file mode 100644 index 00000000..480ccd48 --- /dev/null +++ b/main/src/ui/conversation_summary/conversation_item.vala @@ -0,0 +1,34 @@ +using Dino.Entities; + +namespace Dino.Ui.ConversationSummary { + +public enum MessageKind { + TEXT, + ME_COMMAND +} + +public MessageKind get_message_kind(Message message) { + if (message.body.has_prefix("/me ")) { + return MessageKind.ME_COMMAND; + } else { + return MessageKind.TEXT; + } +} + +public interface ConversationItem : Gtk.Widget { + public abstract bool merge(Entities.Message message); + + public static ConversationItem create_for_message(StreamInteractor stream_interactor, Conversation conversation, Message message) { + switch (get_message_kind(message)) { + case MessageKind.TEXT: + return new MergedMessageItem(stream_interactor, conversation, message); + break; + case MessageKind.ME_COMMAND: + return new SlashMeItem(stream_interactor, conversation, message); + break; + } + return null; + } +} + +} \ No newline at end of file diff --git a/main/src/ui/conversation_summary/merged_message_item.vala b/main/src/ui/conversation_summary/merged_message_item.vala index b00dc18e..fa87ec59 100644 --- a/main/src/ui/conversation_summary/merged_message_item.vala +++ b/main/src/ui/conversation_summary/merged_message_item.vala @@ -7,176 +7,46 @@ using Dino.Entities; namespace Dino.Ui.ConversationSummary { -[GtkTemplate (ui = "/org/dino-im/conversation_summary/message_item.ui")] -public class MergedMessageItem : Grid { +public class MergedMessageItem : MessageItem { - public Conversation conversation { get; set; } - public Jid from { get; private set; } - public DateTime initial_time { get; private set; } - public ArrayList messages = new ArrayList(Message.equals_func); - - [GtkChild] private Image image; - [GtkChild] private Label time_label; - [GtkChild] private Label name_label; - [GtkChild] private Image encryption_image; - [GtkChild] private Image received_image; - [GtkChild] private TextView message_text_view; - - private StreamInteractor stream_interactor; - private TextTag link_tag; + private Label name_label = new Label("") { xalign=0, visible=true }; + private MessageTextView textview = new MessageTextView() { visible=true }; public MergedMessageItem(StreamInteractor stream_interactor, Conversation conversation, Message message) { - this.conversation = conversation; - this.from = message.from; - this.initial_time = message.time; - this.stream_interactor = stream_interactor; - setup_tags(); - add_message(message); + base(stream_interactor, conversation, message); + set_main_widget(textview); + set_title_widget(name_label); - time_label.label = get_relative_time(initial_time.to_local()); - Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(30, 30, image.scale_factor)).draw_message(stream_interactor, message)); - if (message.encryption != Encryption.NONE) { - encryption_image.visible = true; - encryption_image.set_from_icon_name("changes-prevent-symbolic", IconSize.SMALL_TOOLBAR); - } - name_label.label = Util.get_message_display_name(stream_interactor, message, conversation.account); + add_message(message); + string display_name = Util.get_message_display_name(stream_interactor, message, conversation.account); + name_label.set_markup(@"$display_name"); + textview.style_updated.connect(update_display_style); update_display_style(); - Util.force_base_background(message_text_view, "textview, text:not(:selected)"); - message_text_view.style_updated.connect(update_display_style); } - private void update_display_style() { - RGBA bg = message_text_view.get_style_context().get_background_color(StateFlags.NORMAL); - bool dark_theme = (bg.red < 0.5 && bg.green < 0.5 && bg.blue < 0.5); - - string display_name = Util.get_message_display_name(stream_interactor, messages[0], conversation.account); - name_label.set_markup(@"$display_name"); - - LinkButton lnk = new LinkButton("http://example.com"); - RGBA link_color = lnk.get_style_context().get_color(StateFlags.LINK); - link_tag.foreground_rgba = link_color; - } - - public void update() { - time_label.label = get_relative_time(initial_time.to_local()); + public override void add_message(Message message) { + base.add_message(message); + if (messages.size > 1) textview.add_text("\n"); + textview.add_text(message.body); } - public void add_message(Message message) { - TextIter end; - message_text_view.buffer.get_end_iter(out end); - if (messages.size > 0) { - message_text_view.buffer.insert(ref end, "\n", -1); - } - message_text_view.buffer.insert(ref end, message.body, -1); - format_suffix_urls(message.body); - messages.add(message); - message.notify["marked"].connect_after(() => { - Idle.add(() => { update_received(); return false; }); - }); - update_received(); - } - - private void update_received() { - bool all_received = true; - bool all_read = true; - foreach (Message message in messages) { - if (message.marked == Message.Marked.WONTSEND) { - received_image.visible = true; - received_image.set_from_icon_name("dialog-warning-symbolic", IconSize.SMALL_TOOLBAR); - Util.force_error_color(received_image); - Util.force_error_color(encryption_image); - Util.force_error_color(time_label); - return; - } else if (message.marked != Message.Marked.READ) { - all_read = false; - if (message.marked != Message.Marked.RECEIVED) { - all_received = false; - } - } - } - if (all_read) { - received_image.visible = true; - received_image.set_from_icon_name("dino-double-tick-symbolic", IconSize.SMALL_TOOLBAR); - } else if (all_received) { - received_image.visible = true; - received_image.set_from_icon_name("dino-tick-symbolic", IconSize.SMALL_TOOLBAR); - } else if (received_image.visible) { - received_image.set_from_icon_name("image-loading-symbolic", IconSize.SMALL_TOOLBAR); - } - } - - private void format_suffix_urls(string text) { - int absolute_start = message_text_view.buffer.text.length - text.length; - - Regex url_regex = new Regex("""(?i)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))"""); - MatchInfo match_info; - url_regex.match(text, 0, out match_info); - for (; match_info.matches(); match_info.next()) { - string? url = match_info.fetch(0); - int start; - int end; - match_info.fetch_pos(0, out start, out end); - start = text[0:start].char_count(); - end = text[0:end].char_count(); - TextIter start_iter; - TextIter end_iter; - message_text_view.buffer.get_iter_at_offset(out start_iter, absolute_start + start); - message_text_view.buffer.get_iter_at_offset(out end_iter, absolute_start + end); - message_text_view.buffer.apply_tag_by_name("url", start_iter, end_iter); - } - } - - private void setup_tags() { - link_tag = message_text_view.buffer.create_tag("url", underline: Pango.Underline.SINGLE, foreground: "blue"); - message_text_view.button_release_event.connect(open_url); - message_text_view.motion_notify_event.connect(change_cursor_over_url); - } - - private bool open_url(EventButton event_button) { - int buffer_x, buffer_y; - message_text_view.window_to_buffer_coords(TextWindowType.TEXT, (int) event_button.x, (int) event_button.y, out buffer_x, out buffer_y); - TextIter iter; - message_text_view.get_iter_at_location(out iter, buffer_x, buffer_y); - TextIter start_iter = iter, end_iter = iter; - if (start_iter.backward_to_tag_toggle(null) && end_iter.forward_to_tag_toggle(null)) { - string url = start_iter.get_text(end_iter); - try{ - AppInfo.launch_default_for_uri(url, null); - } catch (Error err) { - print("Tryed to open " + url); - } + public override bool merge(Message message) { + if (get_message_kind(message) == MessageKind.TEXT && + this.from.equals(message.from) && + this.messages[0].encryption == message.encryption && + message.time.difference(initial_time) < TimeSpan.MINUTE && + this.messages[0].marked != Entities.Message.Marked.WONTSEND) { + add_message(message); + return true; } return false; - } - private bool change_cursor_over_url(EventMotion event_motion) { - TextIter iter; - message_text_view.get_iter_at_location(out iter, (int) event_motion.x, (int) event_motion.y); - if (iter.has_tag(message_text_view.buffer.tag_table.lookup("url"))) { - event_motion.window.set_cursor(new Cursor.for_display(get_display(), CursorType.HAND2)); - } else { - event_motion.window.set_cursor(new Cursor.for_display(get_display(), CursorType.XTERM)); - } - return false; } - private static string get_relative_time(DateTime datetime) { - DateTime now = new DateTime.now_local(); - TimeSpan timespan = now.difference(datetime); - if (timespan > 365 * TimeSpan.DAY) { - return datetime.format("%d.%m.%Y %H:%M"); - } else if (timespan > 7 * TimeSpan.DAY) { - return datetime.format("%d.%m %H:%M"); - } else if (timespan > 1 * TimeSpan.DAY) { - return datetime.format("%a, %H:%M"); - } else if (timespan > 9 * TimeSpan.MINUTE) { - return datetime.format("%H:%M"); - } else if (timespan > TimeSpan.MINUTE) { - return (timespan / TimeSpan.MINUTE).to_string() + " min ago"; - } else { - return "Just now"; - } + private void update_display_style() { + string display_name = Util.get_message_display_name(stream_interactor, messages[0], conversation.account); + name_label.set_markup(@"$display_name"); } } diff --git a/main/src/ui/conversation_summary/merged_status_item.vala b/main/src/ui/conversation_summary/merged_status_item.vala deleted file mode 100644 index 1fe8ecf3..00000000 --- a/main/src/ui/conversation_summary/merged_status_item.vala +++ /dev/null @@ -1,31 +0,0 @@ -using Gee; -using Gtk; - -using Dino.Entities; - -namespace Dino.Ui.ConversationSummary { - -private class MergedStatusItem : Expander { - - private StreamInteractor stream_interactor; - private Conversation conversation; - private ArrayList statuses = new ArrayList(); - - public MergedStatusItem(StreamInteractor stream_interactor, Conversation conversation, Show show) { - set_hexpand(true); - add_status(show); - } - - public void add_status(Show show) { - statuses.add(show); - StatusItem status_item = new StatusItem(stream_interactor, conversation, @"is $(show.as)"); - if (statuses.size == 1) { - label = show.as; - } else { - label = @"changed their status $(statuses.size) times"; - add(new Label(show.as)); - } - } -} - -} \ No newline at end of file diff --git a/main/src/ui/conversation_summary/message_item.vala b/main/src/ui/conversation_summary/message_item.vala new file mode 100644 index 00000000..fed67945 --- /dev/null +++ b/main/src/ui/conversation_summary/message_item.vala @@ -0,0 +1,112 @@ +using Gee; +using Gdk; +using Gtk; +using Markup; + +using Dino.Entities; + +namespace Dino.Ui.ConversationSummary { + +[GtkTemplate (ui = "/org/dino-im/conversation_summary/message_item.ui")] +public class MessageItem : Grid, ConversationItem { + + [GtkChild] private Image image; + [GtkChild] private Label time_label; + [GtkChild] private Image encryption_image; + [GtkChild] private Image received_image; + + public StreamInteractor stream_interactor; + public Conversation conversation { get; set; } + public Jid from { get; private set; } + public DateTime initial_time { get; private set; } + public ArrayList messages = new ArrayList(Message.equals_func); + + public MessageItem(StreamInteractor stream_interactor, Conversation conversation, Message message) { + this.conversation = conversation; + this.stream_interactor = stream_interactor; + this.initial_time = message.time; + this.from = message.from; + + if (message.encryption != Encryption.NONE) { + encryption_image.visible = true; + encryption_image.set_from_icon_name("changes-prevent-symbolic", IconSize.SMALL_TOOLBAR); + } + + time_label.label = get_relative_time(initial_time.to_local()); + Util.image_set_from_scaled_pixbuf(image, (new AvatarGenerator(30, 30, image.scale_factor)).draw_message(stream_interactor, message)); + } + + public void set_title_widget(Widget w) { + attach(w, 1, 0, 1, 1); + } + + public void set_main_widget(Widget w) { + attach(w, 1, 1, 2, 1); + } + + public void update() { + time_label.label = get_relative_time(initial_time.to_local()); + } + + public virtual void add_message(Message message) { + messages.add(message); + + message.notify["marked"].connect_after(() => { + Idle.add(() => { update_received(); return false; }); + }); + update_received(); + } + + public virtual bool merge(Message message) { + return false; + } + + private void update_received() { + bool all_received = true; + bool all_read = true; + foreach (Message message in messages) { + if (message.marked == Message.Marked.WONTSEND) { + received_image.visible = true; + received_image.set_from_icon_name("dialog-warning-symbolic", IconSize.SMALL_TOOLBAR); + Util.force_error_color(received_image); + Util.force_error_color(encryption_image); + Util.force_error_color(time_label); + return; + } else if (message.marked != Message.Marked.READ) { + all_read = false; + if (message.marked != Message.Marked.RECEIVED) { + all_received = false; + } + } + } + if (all_read) { + received_image.visible = true; + received_image.set_from_icon_name("dino-double-tick-symbolic", IconSize.SMALL_TOOLBAR); + } else if (all_received) { + received_image.visible = true; + received_image.set_from_icon_name("dino-tick-symbolic", IconSize.SMALL_TOOLBAR); + } else if (received_image.visible) { + received_image.set_from_icon_name("image-loading-symbolic", IconSize.SMALL_TOOLBAR); + } + } + + private static string get_relative_time(DateTime datetime) { + DateTime now = new DateTime.now_local(); + TimeSpan timespan = now.difference(datetime); + if (timespan > 365 * TimeSpan.DAY) { + return datetime.format("%d.%m.%Y %H:%M"); + } else if (timespan > 7 * TimeSpan.DAY) { + return datetime.format("%d.%m %H:%M"); + } else if (timespan > 1 * TimeSpan.DAY) { + return datetime.format("%a, %H:%M"); + } else if (timespan > 9 * TimeSpan.MINUTE) { + return datetime.format("%H:%M"); + } else if (timespan > TimeSpan.MINUTE) { + return (timespan / TimeSpan.MINUTE).to_string() + " min ago"; + } else { + return "Just now"; + } + } +} + +} diff --git a/main/src/ui/conversation_summary/message_textview.vala b/main/src/ui/conversation_summary/message_textview.vala new file mode 100644 index 00000000..6474a1a3 --- /dev/null +++ b/main/src/ui/conversation_summary/message_textview.vala @@ -0,0 +1,87 @@ +using Gdk; +using Gtk; + +using Dino.Entities; + +namespace Dino.Ui.ConversationSummary { + +public class MessageTextView : TextView { + + private TextTag link_tag; + + public MessageTextView() { + Object(editable:false, hexpand:true, wrap_mode:WrapMode.WORD_CHAR); + + link_tag = buffer.create_tag("url", underline: Pango.Underline.SINGLE, foreground: "blue"); + button_release_event.connect(open_url); + motion_notify_event.connect(change_cursor_over_url); + + update_display_style(); + Util.force_base_background(this, "textview, text:not(:selected)"); + style_updated.connect(update_display_style); + } + + public void add_text(string text) { + TextIter end; + buffer.get_end_iter(out end); + buffer.insert(ref end, text, -1); + format_suffix_urls(text); + } + + private void update_display_style() { + LinkButton lnk = new LinkButton("http://example.com"); + RGBA link_color = lnk.get_style_context().get_color(StateFlags.LINK); + link_tag.foreground_rgba = link_color; + } + + private void format_suffix_urls(string text) { + int absolute_start = buffer.text.length - text.length; + + Regex url_regex = new Regex("""(?i)\b((?:[a-z][\w-]+:(?:\/{1,3}|[a-z0-9%])|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}\/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:'".,<>?«»“”‘’]))"""); + MatchInfo match_info; + url_regex.match(text, 0, out match_info); + for (; match_info.matches(); match_info.next()) { + string? url = match_info.fetch(0); + int start; + int end; + match_info.fetch_pos(0, out start, out end); + start = text[0:start].char_count(); + end = text[0:end].char_count(); + TextIter start_iter; + TextIter end_iter; + buffer.get_iter_at_offset(out start_iter, absolute_start + start); + buffer.get_iter_at_offset(out end_iter, absolute_start + end); + buffer.apply_tag_by_name("url", start_iter, end_iter); + } + } + + private bool open_url(EventButton event_button) { + int buffer_x, buffer_y; + window_to_buffer_coords(TextWindowType.TEXT, (int) event_button.x, (int) event_button.y, out buffer_x, out buffer_y); + TextIter iter; + get_iter_at_location(out iter, buffer_x, buffer_y); + TextIter start_iter = iter, end_iter = iter; + if (start_iter.backward_to_tag_toggle(null) && end_iter.forward_to_tag_toggle(null)) { + string url = start_iter.get_text(end_iter); + try{ + AppInfo.launch_default_for_uri(url, null); + } catch (Error err) { + print("Tryed to open " + url); + } + } + return false; + } + + private bool change_cursor_over_url(EventMotion event_motion) { + TextIter iter; + get_iter_at_location(out iter, (int) event_motion.x, (int) event_motion.y); + if (iter.has_tag(buffer.tag_table.lookup("url"))) { + event_motion.window.set_cursor(new Cursor.for_display(get_display(), CursorType.HAND2)); + } else { + event_motion.window.set_cursor(new Cursor.for_display(get_display(), CursorType.XTERM)); + } + return false; + } +} + +} \ No newline at end of file diff --git a/main/src/ui/conversation_summary/slashme_item.vala b/main/src/ui/conversation_summary/slashme_item.vala new file mode 100644 index 00000000..cd387bc9 --- /dev/null +++ b/main/src/ui/conversation_summary/slashme_item.vala @@ -0,0 +1,43 @@ +using Gdk; +using Gtk; + +using Dino.Entities; + +namespace Dino.Ui.ConversationSummary { + +public class SlashMeItem : MessageItem { + + private Box box = new Box(Orientation.VERTICAL, 0) { visible=true, vexpand=true }; + private MessageTextView textview = new MessageTextView() { visible=true }; + private string text; + private TextTag nick_tag; + + public SlashMeItem(StreamInteractor stream_interactor, Conversation conversation, Message message) { + base(stream_interactor, conversation, message); + box.set_center_widget(textview); + set_title_widget(box); + text = message.body.substring(3); + + string display_name = Util.get_message_display_name(stream_interactor, message, conversation.account); + nick_tag = textview.buffer.create_tag("nick", foreground: @"#$(Util.get_name_hex_color(display_name, false))"); + TextIter iter; + textview.buffer.get_start_iter(out iter); + textview.buffer.insert_with_tags(ref iter, display_name, display_name.length, nick_tag); + textview.add_text(text); + add_message(message); + + textview.style_updated.connect(update_display_style); + update_display_style(); + } + + public override bool merge(Message message) { + return false; + } + + private void update_display_style() { + string display_name = Util.get_message_display_name(stream_interactor, messages[0], conversation.account); + nick_tag.foreground = @"#$(Util.get_name_hex_color(display_name, Util.is_dark_theme(textview)))"; + } +} + +} diff --git a/main/src/ui/conversation_summary/status_item.vala b/main/src/ui/conversation_summary/status_item.vala index 0775d8f3..1704356c 100644 --- a/main/src/ui/conversation_summary/status_item.vala +++ b/main/src/ui/conversation_summary/status_item.vala @@ -22,7 +22,7 @@ private class StatusItem : Grid { attach(image, 0, 0, 1, 1); attach(label, 1, 0, 1, 1); string display_name = Util.get_display_name(stream_interactor, conversation.counterpart, conversation.account); - label.set_markup(@" $(escape_text(display_name)) $text "); + label.set_markup(@"$(escape_text(display_name)) $text"); show_all(); } } diff --git a/main/src/ui/conversation_summary/view.vala b/main/src/ui/conversation_summary/view.vala index 2cf695b2..d884a04a 100644 --- a/main/src/ui/conversation_summary/view.vala +++ b/main/src/ui/conversation_summary/view.vala @@ -11,13 +11,13 @@ namespace Dino.Ui.ConversationSummary { public class View : Box { public Conversation? conversation { get; private set; } - public HashMap message_items = new HashMap(Entities.Message.hash_func, Entities.Message.equals_func); + public HashMap conversation_items = new HashMap(Entities.Message.hash_func, Entities.Message.equals_func); [GtkChild] private ScrolledWindow scrolled; [GtkChild] private Box main; private StreamInteractor stream_interactor; - private MergedMessageItem? last_message_item; + private ConversationItem? last_conversation_item; private StatusItem typing_status; private Entities.Message? earliest_message; double? was_value; @@ -44,8 +44,9 @@ public class View : Box { Idle.add(() => { on_show_received(show, jid, account); return false; }); }); Timeout.add_seconds(60, () => { - foreach (MergedMessageItem message_item in message_items.values) { - message_item.update(); + foreach (ConversationItem conversation_item in conversation_items.values) { + MessageItem message_item = conversation_item as MessageItem; + if (message_item != null) message_item.update(); } return true; }); @@ -56,10 +57,10 @@ public class View : Box { public void initialize_for_conversation(Conversation? conversation) { this.conversation = conversation; clear(); - message_items.clear(); + conversation_items.clear(); was_upper = null; was_page_size = null; - last_message_item = null; + last_conversation_item = null; ArrayList objects = new ArrayList(); Gee.List? messages = MessageManager.get_instance(stream_interactor).get_messages(conversation); @@ -158,13 +159,11 @@ public class View : Box { MergedMessageItem? current_item = null; int items_added = 0; for (int i = 0; i < messages.size; i++) { - if (current_item != null && should_merge_message(current_item, messages[i])) { - current_item.add_message(messages[i]); - } else { + if (current_item == null || !current_item.merge(messages[i])) { current_item = new MergedMessageItem(stream_interactor, conversation, messages[i]); force_alloc_width(current_item, main.get_allocated_width()); main.add(current_item); - message_items[messages[i]] = current_item; + conversation_items[messages[i]] = current_item; main.reorder_child(current_item, items_added); items_added++; } @@ -176,35 +175,25 @@ public class View : Box { private void show_message(Entities.Message message, Conversation conversation, bool animate = false) { if (this.conversation != null && this.conversation.equals(conversation)) { - if (should_merge_message(last_message_item, message)) { - last_message_item.add_message(message); - } else { - MergedMessageItem message_item = new MergedMessageItem(stream_interactor, conversation, message); + if (last_conversation_item == null || !last_conversation_item.merge(message)) { + ConversationItem conversation_item = ConversationItem.create_for_message(stream_interactor, conversation, message); if (animate) { Revealer revealer = new Revealer() {transition_duration = 200, transition_type = RevealerTransitionType.SLIDE_UP, visible = true}; - revealer.add(message_item); + revealer.add(conversation_item); force_alloc_width(revealer, main.get_allocated_width()); main.add(revealer); revealer.set_reveal_child(true); } else { - force_alloc_width(message_item, main.get_allocated_width()); - main.add(message_item); + force_alloc_width(conversation_item, main.get_allocated_width()); + main.add(conversation_item); } - last_message_item = message_item; + last_conversation_item = conversation_item; } - message_items[message] = last_message_item; + conversation_items[message] = last_conversation_item; update_chat_state(); } } - private bool should_merge_message(MergedMessageItem? message_item, Entities.Message message) { - return message_item != null && - message_item.from.equals(message.from) && - message_item.messages.get(0).encryption == message.encryption && - message.time.difference(message_item.initial_time) < TimeSpan.MINUTE && - (message_item.messages.get(0).marked == Entities.Message.Marked.WONTSEND) == (message.marked == Entities.Message.Marked.WONTSEND); - } - private void force_alloc_width(Widget widget, int width) { Allocation alloc = Allocation(); widget.get_preferred_width(out alloc.width, null); -- cgit v1.2.3-70-g09d2