aboutsummaryrefslogtreecommitdiff
path: root/main/src/ui/conversation_list
diff options
context:
space:
mode:
authorfiaxh <git@lightrise.org>2022-05-14 14:45:59 +0200
committerfiaxh <git@lightrise.org>2022-07-27 20:34:20 +0200
commitf44cbe02c17df1f02ad49c63cd784fec0ea02d85 (patch)
tree4cab9b5f84d88769d19b0698e24b318f50b6144e /main/src/ui/conversation_list
parent2b3ce5fc95c63ed7d54e207db0585c8b8bbcd603 (diff)
downloaddino-f44cbe02c17df1f02ad49c63cd784fec0ea02d85.tar.gz
dino-f44cbe02c17df1f02ad49c63cd784fec0ea02d85.zip
Improve Gtk4 port
Diffstat (limited to 'main/src/ui/conversation_list')
-rw-r--r--main/src/ui/conversation_list/conversation_list_item_factory.vala245
-rw-r--r--main/src/ui/conversation_list/conversation_list_model.vala141
-rw-r--r--main/src/ui/conversation_list/conversation_list_row.vala41
3 files changed, 0 insertions, 427 deletions
diff --git a/main/src/ui/conversation_list/conversation_list_item_factory.vala b/main/src/ui/conversation_list/conversation_list_item_factory.vala
deleted file mode 100644
index dc26d2f1..00000000
--- a/main/src/ui/conversation_list/conversation_list_item_factory.vala
+++ /dev/null
@@ -1,245 +0,0 @@
-using Gtk;
-using Dino.Entities;
-using Dino;
-using Gee;
-using Pango;
-using Xmpp;
-
-namespace Dino.Ui.ConversationList {
-
- public static ListItemFactory get_item_factory() {
- SignalListItemFactory item_factory = new SignalListItemFactory();
- item_factory.setup.connect((list_item) => { on_setup(list_item); });
- item_factory.bind.connect((list_item) => { on_bind(list_item); });
- return item_factory;
- }
-
- public static void on_setup(ListItem listitem) {
- listitem.child = new ConversationListRow();
- }
-
- public static void on_bind(ListItem listitem) {
- ConversationViewModel list_model = (ConversationViewModel) listitem.get_item();
- ConversationListRow view = (ConversationListRow) listitem.get_child();
- StreamInteractor stream_interactor = list_model.stream_interactor;
-
- list_model.bind_property("name", view.name_label, "label");
- list_model.notify["latest-content-item"].connect((obj, _) => {
- update_content_item(view, list_model.conversation, stream_interactor, ((ConversationViewModel) obj).latest_content_item);
- });
- list_model.notify["unread-count"].connect((obj, _) => {
- update_read(view, list_model.conversation, stream_interactor, (int) obj);
- });
-
- view.x_button.clicked.connect(() => list_model.closed() );
-
- ConversationViewModel view_model = (ConversationViewModel) listitem.get_item();
- view.name_label.label = view_model.name;
- if (view_model.latest_content_item != null) {
- update_content_item(view, view_model.conversation, stream_interactor, view_model.latest_content_item);
- }
- update_read(view, view_model.conversation, stream_interactor, view_model.unread_count);
- }
-
- private static void update_content_item(ConversationListRow view, Conversation conversation, StreamInteractor stream_interactor, ContentItem last_content_item) {
- view.time_label.label = get_relative_time(last_content_item.time.to_local());
- view.image.set_conversation(stream_interactor, conversation);
-
- Label nick_label = view.nick_label;
- Label message_label = view.message_label;
-
- switch (last_content_item.type_) {
- case MessageItem.TYPE:
- MessageItem message_item = last_content_item as MessageItem;
- Message last_message = message_item.message;
-
- string body = last_message.body;
- bool me_command = body.has_prefix("/me ");
-
- /* If we have a /me command, we always show the display
- * name, and we don't set me_is_me on
- * get_participant_display_name, since that will return
- * "Me" (internationalized), whereas /me commands expect to
- * be in the third person. We also omit the colon in this
- * case, and strip off the /me prefix itself. */
-
- if (conversation.type_ == Conversation.Type.GROUPCHAT || me_command) {
- nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, last_message.from, !me_command);
- } else if (last_message.direction == Message.DIRECTION_SENT) {
- nick_label.label = _("Me");
- } else {
- nick_label.label = "";
- }
-
- if (me_command) {
- /* Don't slice off the space after /me */
- body = body.slice("/me".length, body.length);
- } else if (nick_label.label.length > 0) {
- /* TODO: Is this valid for RTL languages? */
- nick_label.label += ": ";
- }
-
- message_label.attributes.filter((attr) => attr.equal(attr_style_new(Pango.Style.ITALIC)));
- message_label.label = Util.summarize_whitespaces_to_space(body);
-
- 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
- nick_label.label = Util.get_participant_display_name(stream_interactor, conversation, file_item.file_transfer.from, true) + ": ";
- } else {
- nick_label.label = transfer.direction == Message.DIRECTION_SENT ? _("Me") + ": " : "";
- }
-
- bool file_is_image = transfer.mime_type != null && transfer.mime_type.has_prefix("image");
- message_label.attributes.insert(attr_style_new(Pango.Style.ITALIC));
- 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;
- case CallItem.TYPE:
- CallItem call_item = (CallItem) last_content_item;
- Call call = call_item.call;
-
- nick_label.label = call.direction == Call.DIRECTION_OUTGOING ? _("Me") + ": " : "";
- message_label.attributes.insert(attr_style_new(Pango.Style.ITALIC));
- message_label.label = call.direction == Call.DIRECTION_OUTGOING ? _("Outgoing call") : _("Incoming call");
- break;
- }
- nick_label.visible = true;
- message_label.visible = true;
- }
-
- private void update_read(ConversationListRow view, Conversation conversation, StreamInteractor stream_interactor, int num_unread) {
- Label unread_count_label = view.unread_count_label;
- Label name_label = view.name_label;
- Label time_label = view.time_label;
- Label nick_label = view.nick_label;
- Label message_label = view.message_label;
- if (num_unread == 0) {
- unread_count_label.visible = false;
-
- 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 {
- unread_count_label.label = num_unread.to_string();
- unread_count_label.visible = true;
-
- if (conversation.get_notification_setting(stream_interactor) == Conversation.NotifySetting.ON) {
- unread_count_label.get_style_context().add_class("unread-count-notify");
- unread_count_label.get_style_context().remove_class("unread-count");
- } else {
- unread_count_label.get_style_context().add_class("unread-count");
- unread_count_label.get_style_context().remove_class("unread-count-notify");
- }
-
- 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;
- }
-
- private Widget generate_tooltip(StreamInteractor stream_interactor, Conversation conversation) {
- Grid grid = new Grid() { row_spacing=5, column_homogeneous=false, column_spacing=5, margin_start=7, margin_end=7, margin_top=7, margin_bottom=7 };
-
- Label label = new Label(conversation.counterpart.to_string()) { valign=Align.START, xalign=0, visible=true };
- label.attributes = new AttrList();
- label.attributes.insert(attr_weight_new(Weight.BOLD));
-
- grid.attach(label, 0, 0, 2, 1);
-
- Gee.List<Jid>? full_jids = stream_interactor.get_module(PresenceManager.IDENTITY).get_full_jids(conversation.counterpart, conversation.account);
- if (full_jids == null) return grid;
-
- for (int i = 0; i < full_jids.size; i++) {
- Jid full_jid = full_jids[i];
- string? show = stream_interactor.get_module(PresenceManager.IDENTITY).get_last_show(full_jid, conversation.account);
- if (show == null) continue;
-
- int i_cache = i;
- stream_interactor.get_module(EntityInfo.IDENTITY).get_identity.begin(conversation.account, full_jid, (_, res) => {
- Xep.ServiceDiscovery.Identity? identity = stream_interactor.get_module(EntityInfo.IDENTITY).get_identity.end(res);
-
- Image image = new Image() { hexpand=false, valign=Align.CENTER, visible=true };
- if (identity != null && (identity.type_ == Xep.ServiceDiscovery.Identity.TYPE_PHONE || identity.type_ == Xep.ServiceDiscovery.Identity.TYPE_TABLET)) {
- image.set_from_icon_name("dino-device-phone-symbolic");
- } else {
- image.set_from_icon_name("dino-device-desktop-symbolic");
- }
-
- if (show == Presence.Stanza.SHOW_AWAY) {
- Util.force_color(image, "#FF9800");
- } else if (show == Presence.Stanza.SHOW_XA || show == Presence.Stanza.SHOW_DND) {
- Util.force_color(image, "#FF5722");
- } else {
- Util.force_color(image, "#4CAF50");
- }
-
- string? status = null;
- if (show == Presence.Stanza.SHOW_AWAY) {
- status = "away";
- } else if (show == Presence.Stanza.SHOW_XA) {
- status = "not available";
- } else if (show == Presence.Stanza.SHOW_DND) {
- status = "do not disturb";
- }
-
- var sb = new StringBuilder();
- if (identity != null && identity.name != null) {
- sb.append(identity.name);
- } else if (full_jid.resourcepart != null) {
- sb.append(full_jid.resourcepart);
- } else {
- return;
- }
- if (status != null) {
- sb.append(" <i>(").append(status).append(")</i>");
- }
-
- Label resource = new Label(sb.str) { use_markup=true, hexpand=true, xalign=0, visible=true };
-
- grid.attach(image, 0, i_cache + 1, 1, 1);
- grid.attach(resource, 1, i_cache + 1, 1, 1);
- });
- }
- return grid;
- }
-
- 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.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");
- }
- }
-} \ No newline at end of file
diff --git a/main/src/ui/conversation_list/conversation_list_model.vala b/main/src/ui/conversation_list/conversation_list_model.vala
deleted file mode 100644
index 9412e64a..00000000
--- a/main/src/ui/conversation_list/conversation_list_model.vala
+++ /dev/null
@@ -1,141 +0,0 @@
-using Gtk;
-using Dino.Entities;
-using Dino;
-using Gee;
-using Xmpp;
-
-public class Dino.Ui.ConversationViewModel : Object {
- public signal void closed();
-
- public StreamInteractor stream_interactor { get; set; }
- public Conversation conversation { get; set; }
- public string name { get; set; }
- public ContentItem? latest_content_item { get; set; }
- public int unread_count { get; set; }
-}
-
-public class Dino.Ui.ConversationListModel : Object, ListModel {
-
- public signal void closed_conversation(Conversation conversation);
-
- private HashMap<Conversation, ConversationViewModel> conversation_view_model_hm = new HashMap<Conversation, ConversationViewModel>(Conversation.hash_func, Conversation.equals_func);
- private ArrayList<ConversationViewModel> view_models = new ArrayList<ConversationViewModel>();
- private StreamInteractor stream_interactor;
-
- public ConversationListModel(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(ContentItemStore.IDENTITY).new_item.connect(on_content_item_received);
-
- foreach (Conversation conversation in stream_interactor.get_module(ConversationManager.IDENTITY).get_active_conversations()) {
- var view_model = create_view_model(conversation);
- view_models.add(view_model);
- conversation_view_model_hm[conversation] = view_model;
- }
- view_models.sort(sort);
- items_changed(0, 0, get_n_items());
-
- stream_interactor.get_module(RosterManager.IDENTITY).updated_roster_item.connect((account, jid, roster_item) => {
- ConversationViewModel? view_model = get_view_model(account, jid, Conversation.Type.CHAT);
- if (view_model == null) return;
- view_model.name = Util.get_conversation_display_name(stream_interactor, view_model.conversation);
- });
- stream_interactor.get_module(MucManager.IDENTITY).room_info_updated.connect((account, jid) => {
- ConversationViewModel? view_model = get_view_model(account, jid, Conversation.Type.GROUPCHAT);
- if (view_model == null) return;
- view_model.name = Util.get_conversation_display_name(stream_interactor, view_model.conversation);
- // bubble color might have changed
- view_model.unread_count = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(view_model.conversation);
- });
- stream_interactor.get_module(MucManager.IDENTITY).private_room_occupant_updated.connect((account, room, occupant) => {
- ConversationViewModel? view_model = get_view_model(account, room.bare_jid, Conversation.Type.GROUPCHAT);
- if (view_model == null) return;
- view_model.name = Util.get_conversation_display_name(stream_interactor, view_model.conversation);
- });
- }
-
- public GLib.Object? get_item (uint position) {
- if (position >= view_models.size) return null;
- return view_models[(int)position];
- }
-
- public GLib.Type get_item_type () {
- return GLib.Type.OBJECT;
- }
-
- public uint get_n_items () {
- return view_models.size;
- }
-
- private ConversationViewModel create_view_model(Conversation conversation) {
- var view_model = new ConversationViewModel();
- view_model.stream_interactor = stream_interactor;
- view_model.conversation = conversation;
- view_model.name = Util.get_conversation_display_name(stream_interactor, conversation);
- view_model.latest_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation);
- view_model.unread_count = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(conversation);
- view_model.closed.connect(() => closed_conversation(conversation));
-
- return view_model;
- }
-
- private void add_conversation(Conversation conversation) {
- var view_model = create_view_model(conversation);
-
- view_models.add(view_model);
- conversation_view_model_hm[conversation] = view_model;
- view_models.sort(sort);
-
- int idx = view_models.index_of(view_model);
- items_changed(idx, 0, 1);
- }
-
- private async void remove_conversation(Conversation conversation) {
- ConversationViewModel? view_model = conversation_view_model_hm[conversation];
- if (view_model == null) return;
-
- int idx = view_models.index_of(view_model);
- view_models.remove(view_model);
- conversation_view_model_hm.unset(conversation);
- items_changed(idx, 1, 0);
- }
-
- private void on_content_item_received(ContentItem item, Conversation conversation) {
- ConversationViewModel? view_model = conversation_view_model_hm[conversation];
- if (view_model == null) return;
-
- view_model.latest_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_latest(conversation);
- view_model.unread_count = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(conversation);
-
- view_models.sort(sort);
- items_changed(0, view_models.size, view_models.size); // TODO better
- }
-
- private ConversationViewModel? get_view_model(Account account, Jid jid, Conversation.Type? conversation_ty) {
- foreach (ConversationViewModel view_model in view_models) {
- Conversation conversation = view_model.conversation;
- if (conversation.account.equals(account) && conversation.counterpart.equals(jid)) {
- if (conversation_ty != null && conversation.type_ != conversation_ty) continue;
- return view_model;
- }
- }
- return null;
- }
-
- private int sort(ConversationViewModel vm1, ConversationViewModel vm2) {
- Conversation c1 = vm1.conversation;
- Conversation c2 = vm2.conversation;
-
- if (c1 == null || c2 == null) return 0;
- 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 comp;
-
- return Util.get_conversation_display_name(stream_interactor, c1)
- .collate(Util.get_conversation_display_name(stream_interactor, c2));
- }
-} \ No newline at end of file
diff --git a/main/src/ui/conversation_list/conversation_list_row.vala b/main/src/ui/conversation_list/conversation_list_row.vala
deleted file mode 100644
index ab4e8cee..00000000
--- a/main/src/ui/conversation_list/conversation_list_row.vala
+++ /dev/null
@@ -1,41 +0,0 @@
-using Gee;
-using Gdk;
-using Gtk;
-using Pango;
-
-using Dino;
-using Dino.Entities;
-using Xmpp;
-
-[GtkTemplate (ui = "/im/dino/Dino/conversation_row.ui")]
-public class Dino.Ui.ConversationListRow : ListBoxRow {
-
- [GtkChild] public unowned AvatarImage image;
- [GtkChild] public unowned Label name_label;
- [GtkChild] public unowned Label time_label;
- [GtkChild] public unowned Label nick_label;
- [GtkChild] public unowned Label message_label;
- [GtkChild] public unowned Label unread_count_label;
- [GtkChild] public unowned Button x_button;
- [GtkChild] public unowned Revealer time_revealer;
- [GtkChild] public unowned Revealer xbutton_revealer;
- [GtkChild] public unowned Revealer unread_count_revealer;
- [GtkChild] public unowned Revealer main_revealer;
-
- construct {
- name_label.attributes = new AttrList();
- }
-
- 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);
- unread_count_revealer.set_reveal_child(false);
- xbutton_revealer.set_reveal_child(true);
- } else {
- time_revealer.set_reveal_child(true);
- unread_count_revealer.set_reveal_child(true);
- xbutton_revealer.set_reveal_child(false);
- }
- }
-} \ No newline at end of file