Add unread indicator

Co-authored-by: Alexandre Jousset <mid@gtmp.org>
Co-authored-by: Aidan Epstein <aidan@jmad.org>
This commit is contained in:
fiaxh 2024-03-02 13:18:53 +01:00
parent 7e3cedaf3f
commit 4cc7e076e6
5 changed files with 100 additions and 0 deletions

View file

@ -192,6 +192,7 @@ SOURCES
src/ui/conversation_content_view/quote_widget.vala src/ui/conversation_content_view/quote_widget.vala
src/ui/conversation_content_view/reactions_widget.vala src/ui/conversation_content_view/reactions_widget.vala
src/ui/conversation_content_view/subscription_notification.vala src/ui/conversation_content_view/subscription_notification.vala
src/ui/conversation_content_view/unread_indicator_populator.vala
src/ui/chat_input/chat_input_controller.vala src/ui/chat_input/chat_input_controller.vala
src/ui/chat_input/chat_text_view.vala src/ui/chat_input/chat_text_view.vala

View file

@ -282,6 +282,13 @@ window.dino-main .dino-chatinput-button button:checked:backdrop {
color: alpha(@theme_unfocused_selected_bg_color, 0.8); color: alpha(@theme_unfocused_selected_bg_color, 0.8);
} }
.dino-unread-line label {
color: @theme_selected_bg_color;
}
.dino-unread-line separator {
background-color: @theme_selected_bg_color;
}
.dino-chatinput, .dino-chatinput,
.dino-chatinput textview, .dino-chatinput textview,

View file

@ -53,6 +53,7 @@ sources = files(
'src/ui/conversation_content_view/quote_widget.vala', 'src/ui/conversation_content_view/quote_widget.vala',
'src/ui/conversation_content_view/reactions_widget.vala', 'src/ui/conversation_content_view/reactions_widget.vala',
'src/ui/conversation_content_view/subscription_notification.vala', 'src/ui/conversation_content_view/subscription_notification.vala',
'src/ui/conversation_content_view/unread_indicator_populator.vala',
'src/ui/conversation_details.vala', 'src/ui/conversation_details.vala',
'src/ui/conversation_list_titlebar.vala', 'src/ui/conversation_list_titlebar.vala',
'src/ui/conversation_selector/conversation_selector.vala', 'src/ui/conversation_selector/conversation_selector.vala',

View file

@ -87,6 +87,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
Application app = GLib.Application.get_default() as Application; Application app = GLib.Application.get_default() as Application;
app.plugin_registry.register_conversation_addition_populator(new ChatStatePopulator(stream_interactor)); app.plugin_registry.register_conversation_addition_populator(new ChatStatePopulator(stream_interactor));
app.plugin_registry.register_conversation_addition_populator(new DateSeparatorPopulator(stream_interactor)); app.plugin_registry.register_conversation_addition_populator(new DateSeparatorPopulator(stream_interactor));
app.plugin_registry.register_conversation_addition_populator(new UnreadIndicatorPopulator(stream_interactor));
// Rather than connecting to the leave event of the main_event_box directly, // Rather than connecting to the leave event of the main_event_box directly,
// we connect to the parent event box that also wraps the overlaying message_menu_box. // we connect to the parent event box that also wraps the overlaying message_menu_box.
@ -382,6 +383,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
foreach (ContentMetaItem item in items) { foreach (ContentMetaItem item in items) {
do_insert_item(item); do_insert_item(item);
} }
Application app = GLib.Application.get_default() as Application; Application app = GLib.Application.get_default() as Application;
foreach (Plugins.NotificationPopulator populator in app.plugin_registry.notification_populators) { foreach (Plugins.NotificationPopulator populator in app.plugin_registry.notification_populators) {
populator.init(conversation, this, Plugins.WidgetType.GTK4); populator.init(conversation, this, Plugins.WidgetType.GTK4);
@ -398,6 +400,7 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
return; return;
} }
} }
do_insert_item(item); do_insert_item(item);
} }

View file

@ -0,0 +1,88 @@
using Gee;
using Gtk;
using Dino.Entities;
using Xmpp;
namespace Dino.Ui.ConversationSummary {
class UnreadIndicatorPopulator : Plugins.ConversationItemPopulator, Plugins.ConversationAdditionPopulator, Object {
public string id { get { return "unread_indicator"; } }
private StreamInteractor stream_interactor;
private Conversation? current_conversation;
private UnreadIndicatorItem? unread_indicator = null;
Plugins.ConversationItemCollection item_collection = null;
public UnreadIndicatorPopulator(StreamInteractor stream_interactor) {
this.stream_interactor = stream_interactor;
stream_interactor.get_module(ChatInteraction.IDENTITY).focused_out.connect(() => {
update_unread_indicator();
});
stream_interactor.get_module(ContentItemStore.IDENTITY).new_item.connect(() => {
if (!stream_interactor.get_module(ChatInteraction.IDENTITY).is_active_focus(current_conversation)) {
update_unread_indicator();
}
});
}
private void update_unread_indicator() {
if (current_conversation == null) return;
ContentItem? read_up_to_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_item_by_id(current_conversation, current_conversation.read_up_to_item);
int current_num_unread = stream_interactor.get_module(ChatInteraction.IDENTITY).get_num_unread(current_conversation);
if (current_num_unread == 0 && unread_indicator != null) {
item_collection.remove_item(unread_indicator);
unread_indicator = null;
}
if (read_up_to_item != null && current_num_unread > 0) {
if (unread_indicator != null) {
item_collection.remove_item(unread_indicator);
}
unread_indicator = new UnreadIndicatorItem(read_up_to_item);
item_collection.insert_item(unread_indicator);
}
}
public void init(Conversation conversation, Plugins.ConversationItemCollection item_collection, Plugins.WidgetType type) {
current_conversation = conversation;
this.item_collection = item_collection;
update_unread_indicator();
}
public void close(Conversation conversation) { }
public void populate_timespan(Conversation conversation, DateTime after, DateTime before) { }
}
private class UnreadIndicatorItem : Plugins.MetaConversationItem {
public UnreadIndicatorItem(ContentItem after_item) {
this.time = after_item.time;
this.secondary_sort_indicator = int.MAX;
}
public override Object? get_widget(Plugins.ConversationItemWidgetInterface outer, Plugins.WidgetType type) {
Box box = new Box(Orientation.HORIZONTAL, 10) { hexpand=true };
box.get_style_context().add_class("dino-unread-line");
Separator sep = new Separator(Orientation.HORIZONTAL) { valign=Align.CENTER, hexpand=true };
box.append(sep);
Label label = new Label(_("New")) { halign=Align.END, hexpand=false };
label.attributes = new Pango.AttrList();
label.attributes.insert(Pango.attr_weight_new(Pango.Weight.BOLD));
box.append(label);
return box;
}
public override Gee.List<Plugins.MessageAction>? get_item_actions(Plugins.WidgetType type) {
return null;
}
}
}