From d3dfffd65256941ad5aeb1e9d065ec6600a93944 Mon Sep 17 00:00:00 2001 From: James Magahern Date: Sat, 3 May 2025 22:41:51 -0700 Subject: [PATCH] show dates in transcript --- src/meson.build | 1 + .../layouts/date-item-layout.vala | 48 +++++++++++++++++++ src/message-list/message-drawing-area.vala | 30 ++++++++---- src/message-list/message-list-model.vala | 2 +- src/models/message.vala | 6 +-- 5 files changed, 74 insertions(+), 13 deletions(-) create mode 100644 src/message-list/layouts/date-item-layout.vala diff --git a/src/meson.build b/src/meson.build index 882c1e5..8a7a252 100644 --- a/src/meson.build +++ b/src/meson.build @@ -34,6 +34,7 @@ sources = [ 'message-list/layouts/bubble-layout.vala', 'message-list/layouts/chat-item-layout.vala', + 'message-list/layouts/date-item-layout.vala', 'message-list/layouts/text-bubble-layout.vala', 'models/conversation.vala', diff --git a/src/message-list/layouts/date-item-layout.vala b/src/message-list/layouts/date-item-layout.vala new file mode 100644 index 0000000..a87a714 --- /dev/null +++ b/src/message-list/layouts/date-item-layout.vala @@ -0,0 +1,48 @@ +using Gtk; + +class DateItemLayout : Object, ChatItemLayout { + public bool from_me { get; set; } + + private Pango.Layout layout; + private float max_width; + + public DateItemLayout(string date_str, Widget parent, float max_width) { + this.max_width = max_width; + + layout = parent.create_pango_layout(date_str); + layout.set_font_description(Pango.FontDescription.from_string("Sans 9")); + layout.set_alignment(Pango.Alignment.CENTER); + } + + public float get_height() { + Pango.Rectangle ink_rect, logical_rect; + layout.get_pixel_extents(out ink_rect, out logical_rect); + + return logical_rect.height + 50.0f; + } + + public float get_width() { + return max_width; + } + + public void draw(Snapshot snapshot) { + snapshot.save(); + + Pango.Rectangle ink_rect, logical_rect; + layout.get_pixel_extents(out ink_rect, out logical_rect); + + snapshot.translate(Graphene.Point() { + x = (max_width - logical_rect.width) / 2, + y = (get_height() - logical_rect.height) / 2 + }); + + snapshot.append_layout(layout, Gdk.RGBA() { + red = 1.0f, + green = 1.0f, + blue = 1.0f, + alpha = 0.5f + }); + + snapshot.restore(); + } +} \ No newline at end of file diff --git a/src/message-list/message-drawing-area.vala b/src/message-list/message-drawing-area.vala index 7d0fce4..43490dd 100644 --- a/src/message-list/message-drawing-area.vala +++ b/src/message-list/message-drawing-area.vala @@ -53,8 +53,8 @@ private class MessageDrawingArea : Widget var container_width = get_width(); float y_offset = 0; _chat_items.foreach((chat_item) => { - var message_width = chat_item.get_width(); - var message_height = chat_item.get_height(); + var item_width = chat_item.get_width(); + var item_height = chat_item.get_height(); snapshot.save(); @@ -63,17 +63,17 @@ private class MessageDrawingArea : Widget // Translate to the correct position snapshot.translate(Graphene.Point() { - x = (chat_item.from_me ? (container_width - message_width - bubble_margin) : bubble_margin), + x = (chat_item.from_me ? (container_width - item_width - bubble_margin) : bubble_margin), y = y_offset }); // Undo the y-axis flip, origin is top left - snapshot.translate(Graphene.Point() { x = 0, y = -message_height }); + snapshot.translate(Graphene.Point() { x = 0, y = -item_height }); chat_item.draw(snapshot); snapshot.restore(); - y_offset -= message_height + bubble_padding; + y_offset -= item_height + bubble_padding; return true; }); @@ -85,12 +85,24 @@ private class MessageDrawingArea : Widget _chat_items.clear(); - var sorted_messages = _messages - .order_by((a, b) => (int)b.date - (int)a.date); // reverse order + var reversed_messages = _messages + .order_by((a, b) => b.date.compare(a.date)); // reverse order + + DateTime? last_date = null; + reversed_messages.foreach((message) => { + // Remember everything in here is backwards. + if (last_date == null) { + last_date = message.date; + } else if (last_date.difference(message.date) > (TimeSpan.MINUTE * 25)) { + var date_item = new DateItemLayout(last_date.to_local().format("%b %d, %Y at %H:%M"), this, max_width); + _chat_items.add(date_item); + last_date = message.date; + } + + var text_bubble = new TextBubbleLayout(message, this, max_width); + _chat_items.add(text_bubble); - sorted_messages.foreach((message) => { - _chat_items.add(new TextBubbleLayout(message, this, max_width)); return true; }); diff --git a/src/message-list/message-list-model.vala b/src/message-list/message-list-model.vala index 0f8b05a..b1d362f 100644 --- a/src/message-list/message-list-model.vala +++ b/src/message-list/message-list-model.vala @@ -15,7 +15,7 @@ public class MessageListModel : Object, ListModel public MessageListModel(string conversation_guid) { _messages = new TreeSet((a, b) => { // Sort by date in descending order (newest first) - return (int)(b.date - a.date); + return a.date.compare(b.date); }); Repository.get_instance().messages_updated.connect(got_messages_updated); diff --git a/src/models/message.vala b/src/models/message.vala index 8a1ff4b..e8ab948 100644 --- a/src/models/message.vala +++ b/src/models/message.vala @@ -4,7 +4,7 @@ public class Message : Object { public string guid { get; set; default = ""; } public string text { get; set; default = ""; } - public int64 date { get; set; default = 0; } + public DateTime date { get; set; default = new DateTime.now_local(); } public string sender { get; set; default = null; } public bool from_me { @@ -14,7 +14,7 @@ public class Message : Object } } - public Message(string text, int64 date, string? sender) { + public Message(string text, DateTime date, string? sender) { this.text = text; this.date = date; this.sender = sender; @@ -23,7 +23,7 @@ public class Message : Object public Message.from_hash_table(HashTable message_data) { guid = message_data["id"].get_string(); text = message_data["text"].get_string(); - date = message_data["date"].get_int64(); sender = message_data["sender"].get_string(); + date = new DateTime.from_unix_utc(message_data["date"].get_int64()); } } \ No newline at end of file