diff options
Diffstat (limited to 'main/src/ui/conversation_content_view/conversation_item_skeleton.vala')
-rw-r--r-- | main/src/ui/conversation_content_view/conversation_item_skeleton.vala | 221 |
1 files changed, 221 insertions, 0 deletions
diff --git a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala new file mode 100644 index 00000000..dbba2276 --- /dev/null +++ b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala @@ -0,0 +1,221 @@ +using Gee; +using Gdk; +using Gtk; +using Markup; + +using Dino.Entities; + +namespace Dino.Ui.ConversationSummary { + +public class ConversationItemSkeleton : EventBox { + + private AvatarImage image = new AvatarImage() { margin_top=2, valign=Align.START, visible=true, allow_gray = false }; + + public bool show_skeleton { get; set; } + public bool last_group_item { get; set; } + + public StreamInteractor stream_interactor; + public Conversation conversation { get; set; } + public Plugins.MetaConversationItem item; + + private Box image_content_box = new Box(Orientation.HORIZONTAL, 8) { visible=true }; + private Box header_content_box = new Box(Orientation.VERTICAL, 0) { visible=true }; + private ItemMetaDataHeader metadata_header; + + public ConversationItemSkeleton(StreamInteractor stream_interactor, Conversation conversation, Plugins.MetaConversationItem item) { + this.stream_interactor = stream_interactor; + this.conversation = conversation; + this.item = item; + this.get_style_context().add_class("message-box"); + + if (item.requires_avatar) { + image.set_conversation_participant(stream_interactor, conversation, item.jid); + image_content_box.add(image); + } + if (item.requires_header) { + metadata_header = new ItemMetaDataHeader(stream_interactor, conversation, item) { visible=true }; + header_content_box.add(metadata_header); + } + + Widget? widget = item.get_widget(Plugins.WidgetType.GTK) as Widget; + if (widget != null) { + widget.valign = Align.END; + header_content_box.add(widget); + } + + image_content_box.add(header_content_box); + this.add(image_content_box); + + if (item.get_type().is_a(typeof(ContentMetaItem))) { + this.motion_notify_event.connect((event) => { + this.set_state_flags(StateFlags.PRELIGHT, false); + return false; + }); + this.enter_notify_event.connect((event) => { + this.set_state_flags(StateFlags.PRELIGHT, false); + return false; + }); + this.leave_notify_event.connect((event) => { + this.unset_state_flags(StateFlags.PRELIGHT); + return false; + }); + } + + this.notify["show-skeleton"].connect(update_margin); + this.notify["last-group-item"].connect(update_margin); + + this.show_skeleton = true; + this.last_group_item = true; + update_margin(); + this.notify["show-skeleton"].connect(update_margin); + } + + public void update_time() { + if (metadata_header != null) { + metadata_header.update_time(); + } + } + + public void update_margin() { + image.visible = this.show_skeleton; + if (metadata_header != null) { + metadata_header.visible = this.show_skeleton; + } + image_content_box.margin_start = this.show_skeleton ? 15 : 58; + image_content_box.margin_end = 15; + + if (this.show_skeleton && this.last_group_item) { + image_content_box.margin_top = 8; + image_content_box.margin_bottom = 8; + } else { + image_content_box.margin_top = 4; + image_content_box.margin_bottom = 4; + } + } +} + +[GtkTemplate (ui = "/im/dino/Dino/conversation_content_view/item_metadata_header.ui")] +public class ItemMetaDataHeader : Box { + [GtkChild] public Label name_label; + [GtkChild] public Label dot_label; + [GtkChild] public Label time_label; + [GtkChild] public Image encryption_image; + [GtkChild] public Image received_image; + + public static IconSize ICON_SIZE_HEADER = Gtk.icon_size_register("im.dino.Dino.HEADER_ICON", 17, 12); + + private StreamInteractor stream_interactor; + private Conversation conversation; + private Plugins.MetaConversationItem item; + private ArrayList<Plugins.MetaConversationItem> items = new ArrayList<Plugins.MetaConversationItem>(); + + public ItemMetaDataHeader(StreamInteractor stream_interactor, Conversation conversation, Plugins.MetaConversationItem item) { + this.stream_interactor = stream_interactor; + this.conversation = conversation; + this.item = item; + items.add(item); + + update_name_label(); + name_label.style_updated.connect(update_name_label); + if (item.encryption != Encryption.NONE) { + encryption_image.visible = true; + encryption_image.set_from_icon_name("dino-changes-prevent-symbolic", ICON_SIZE_HEADER); + } + update_time(); + + item.notify["mark"].connect_after(update_received_mark); + update_received_mark(); + } + + public void update_time() { + if (item.display_time != null) { + time_label.label = get_relative_time(item.display_time.to_local()).to_string(); + } + } + + private void update_name_label() { + string display_name = Markup.escape_text(Util.get_participant_display_name(stream_interactor, conversation, item.jid)); + string color = Util.get_name_hex_color(stream_interactor, conversation.account, item.jid, Util.is_dark_theme(name_label)); + name_label.label = @"<span foreground=\"#$color\">$display_name</span>"; + } + + private void update_received_mark() { + bool all_received = true; + bool all_read = true; + bool all_sent = true; + foreach (Plugins.MetaConversationItem item in items) { + if (item.mark == Message.Marked.WONTSEND) { + received_image.visible = true; + received_image.set_from_icon_name("dialog-warning-symbolic", ICON_SIZE_HEADER); + Util.force_error_color(received_image); + Util.force_error_color(encryption_image); + Util.force_error_color(time_label); + string error_text = _("Unable to send message"); + received_image.tooltip_text = error_text; + encryption_image.tooltip_text = error_text; + time_label.tooltip_text = error_text; + return; + } else if (item.mark != Message.Marked.READ) { + all_read = false; + if (item.mark != Message.Marked.RECEIVED) { + all_received = false; + if (item.mark == Message.Marked.UNSENT) { + all_sent = false; + } + } + } + } + if (all_read) { + received_image.visible = true; + received_image.set_from_icon_name("dino-double-tick-symbolic", ICON_SIZE_HEADER); + } else if (all_received) { + received_image.visible = true; + received_image.set_from_icon_name("dino-tick-symbolic", ICON_SIZE_HEADER); + } else if (!all_sent) { + received_image.visible = true; + received_image.set_from_icon_name("image-loading-symbolic", ICON_SIZE_HEADER); + } else if (received_image.visible) { + received_image.set_from_icon_name("image-loading-symbolic", ICON_SIZE_HEADER); + + } + } + + public static string format_time(DateTime datetime, string format_24h, string format_12h) { + string format = Util.is_24h_format() ? format_24h : format_12h; + if (!get_charset(null)) { + // No UTF-8 support, use simple colon for time instead + format = format.replace("∶", ":"); + } + return datetime.format(format); + } + + public static string get_relative_time(DateTime datetime) { + DateTime now = new DateTime.now_local(); + TimeSpan timespan = now.difference(datetime); + if (timespan > 365 * TimeSpan.DAY) { + return format_time(datetime, + /* xgettext:no-c-format */ /* Date + time in 24h format (w/o seconds) */ _("%x, %H∶%M"), + /* xgettext:no-c-format */ /* Date + time in 12h format (w/o seconds)*/ _("%x, %l∶%M %p")); + } else if (timespan > 7 * TimeSpan.DAY) { + return format_time(datetime, + /* xgettext:no-c-format */ /* Month, day and time in 24h format (w/o seconds) */ _("%b %d, %H∶%M"), + /* xgettext:no-c-format */ /* Month, day and time in 12h format (w/o seconds) */ _("%b %d, %l∶%M %p")); + } else if (datetime.get_day_of_month() != now.get_day_of_month()) { + return format_time(datetime, + /* xgettext:no-c-format */ /* Day of week and time in 24h format (w/o seconds) */ _("%a, %H∶%M"), + /* xgettext:no-c-format */ /* Day of week and time in 12h format (w/o seconds) */_("%a, %l∶%M %p")); + } else if (timespan > 9 * TimeSpan.MINUTE) { + return format_time(datetime, + /* 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 > TimeSpan.MINUTE) { + ulong mins = (ulong) (timespan.abs() / TimeSpan.MINUTE); + /* xgettext:this is the beginning of a sentence. */ + return n("%i min ago", "%i mins ago", mins).printf(mins); + } else { + return _("Just now"); + } + } +} + +} |