2017-08-27 21:55:49 +00:00
|
|
|
using Gee;
|
|
|
|
using Gtk;
|
2020-03-21 19:53:10 +00:00
|
|
|
using Gdk;
|
2017-08-27 21:55:49 +00:00
|
|
|
using Pango;
|
|
|
|
|
|
|
|
using Dino.Entities;
|
|
|
|
|
|
|
|
namespace Dino.Ui.ConversationSummary {
|
|
|
|
|
2020-02-21 01:49:53 +00:00
|
|
|
[GtkTemplate (ui = "/im/dino/Dino/conversation_content_view/view.ui")]
|
2018-06-19 10:52:00 +00:00
|
|
|
public class ConversationView : Box, Plugins.ConversationItemCollection, Plugins.NotificationCollection {
|
2017-08-27 21:55:49 +00:00
|
|
|
|
|
|
|
public Conversation? conversation { get; private set; }
|
|
|
|
|
2018-08-07 14:03:00 +00:00
|
|
|
[GtkChild] public ScrolledWindow scrolled;
|
2017-12-14 01:01:55 +00:00
|
|
|
[GtkChild] private Revealer notification_revealer;
|
2020-03-21 19:53:10 +00:00
|
|
|
[GtkChild] private Box message_menu_box;
|
2017-12-14 01:01:55 +00:00
|
|
|
[GtkChild] private Box notifications;
|
2017-08-27 21:55:49 +00:00
|
|
|
[GtkChild] private Box main;
|
2020-03-21 19:53:10 +00:00
|
|
|
[GtkChild] private EventBox main_event_box;
|
|
|
|
[GtkChild] private EventBox main_wrap_event_box;
|
2017-08-27 21:55:49 +00:00
|
|
|
[GtkChild] private Stack stack;
|
|
|
|
|
|
|
|
private StreamInteractor stream_interactor;
|
2018-06-23 09:59:21 +00:00
|
|
|
private Gee.TreeSet<Plugins.MetaConversationItem> content_items = new Gee.TreeSet<Plugins.MetaConversationItem>(compare_meta_items);
|
|
|
|
private Gee.TreeSet<Plugins.MetaConversationItem> meta_items = new TreeSet<Plugins.MetaConversationItem>(compare_meta_items);
|
2017-08-27 21:55:49 +00:00
|
|
|
private Gee.HashMap<Plugins.MetaConversationItem, ConversationItemSkeleton> item_item_skeletons = new Gee.HashMap<Plugins.MetaConversationItem, ConversationItemSkeleton>();
|
|
|
|
private Gee.HashMap<Plugins.MetaConversationItem, Widget> widgets = new Gee.HashMap<Plugins.MetaConversationItem, Widget>();
|
|
|
|
private Gee.List<ConversationItemSkeleton> item_skeletons = new Gee.ArrayList<ConversationItemSkeleton>();
|
2018-06-19 16:07:00 +00:00
|
|
|
private ContentProvider content_populator;
|
2017-12-14 01:01:55 +00:00
|
|
|
private SubscriptionNotitication subscription_notification;
|
2020-03-21 19:53:10 +00:00
|
|
|
private bool enable_menu_box = false;
|
2017-08-27 21:55:49 +00:00
|
|
|
|
|
|
|
private double? was_value;
|
|
|
|
private double? was_upper;
|
|
|
|
private double? was_page_size;
|
|
|
|
|
2017-10-23 14:10:15 +00:00
|
|
|
private Mutex reloading_mutex = Mutex();
|
2017-08-27 21:55:49 +00:00
|
|
|
private bool animate = false;
|
2018-04-24 12:59:28 +00:00
|
|
|
private bool firstLoad = true;
|
2018-06-23 09:59:21 +00:00
|
|
|
private bool at_current_content = true;
|
2018-07-25 18:41:51 +00:00
|
|
|
private bool reload_messages = true;
|
2020-03-21 19:53:10 +00:00
|
|
|
Widget currently_highlighted = null;
|
|
|
|
ContentItem current_highlighted_item = null;
|
|
|
|
bool mouse_inside = false;
|
|
|
|
int last_y_root = -1;
|
2017-08-27 21:55:49 +00:00
|
|
|
|
2018-07-04 21:38:28 +00:00
|
|
|
public ConversationView init(StreamInteractor stream_interactor) {
|
2017-08-27 21:55:49 +00:00
|
|
|
this.stream_interactor = stream_interactor;
|
|
|
|
scrolled.vadjustment.notify["upper"].connect_after(on_upper_notify);
|
|
|
|
scrolled.vadjustment.notify["value"].connect(on_value_notify);
|
|
|
|
|
2018-06-19 16:07:00 +00:00
|
|
|
content_populator = new ContentProvider(stream_interactor);
|
2017-12-14 01:01:55 +00:00
|
|
|
subscription_notification = new SubscriptionNotitication(stream_interactor);
|
2017-08-27 21:55:49 +00:00
|
|
|
|
2018-06-11 06:11:04 +00:00
|
|
|
add_meta_notification.connect(on_add_meta_notification);
|
|
|
|
remove_meta_notification.connect(on_remove_meta_notification);
|
2017-12-01 01:28:51 +00:00
|
|
|
|
2017-08-27 21:55:49 +00:00
|
|
|
Application app = GLib.Application.get_default() as Application;
|
2018-06-19 16:07:00 +00:00
|
|
|
app.plugin_registry.register_conversation_addition_populator(new ChatStatePopulator(stream_interactor));
|
|
|
|
app.plugin_registry.register_conversation_addition_populator(new DateSeparatorPopulator(stream_interactor));
|
2017-08-27 21:55:49 +00:00
|
|
|
|
|
|
|
Timeout.add_seconds(60, () => {
|
|
|
|
foreach (ConversationItemSkeleton item_skeleton in item_skeletons) {
|
|
|
|
item_skeleton.update_time();
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
2020-03-21 19:53:10 +00:00
|
|
|
|
|
|
|
main_wrap_event_box.events = EventMask.ENTER_NOTIFY_MASK;
|
|
|
|
main_wrap_event_box.events = EventMask.LEAVE_NOTIFY_MASK;
|
|
|
|
main_wrap_event_box.leave_notify_event.connect(on_leave_notify_event);
|
|
|
|
main_wrap_event_box.enter_notify_event.connect(on_enter_notify_event);
|
|
|
|
main_event_box.events = EventMask.POINTER_MOTION_MASK;
|
|
|
|
main_event_box.motion_notify_event.connect(on_motion_notify_event);
|
|
|
|
|
2018-07-04 21:38:28 +00:00
|
|
|
return this;
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
|
2020-03-21 19:53:10 +00:00
|
|
|
private bool on_enter_notify_event(Gdk.EventCrossing event) {
|
|
|
|
mouse_inside = true;
|
|
|
|
update_highlight((int)event.x_root, (int)event.y_root);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool on_leave_notify_event(Gdk.EventCrossing event) {
|
|
|
|
mouse_inside = false;
|
|
|
|
if (currently_highlighted != null) currently_highlighted.unset_state_flags(StateFlags.PRELIGHT);
|
|
|
|
message_menu_box.visible = false;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private bool on_motion_notify_event(Gdk.EventMotion event) {
|
|
|
|
mouse_inside = true;
|
|
|
|
update_highlight((int)event.x_root, (int)event.y_root);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
private void update_highlight(int x_root, int y_root) {
|
|
|
|
if ((last_y_root - y_root).abs() <= 2) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
last_y_root = y_root;
|
|
|
|
message_menu_box.visible = enable_menu_box;
|
|
|
|
|
|
|
|
// Get pointer location in main
|
|
|
|
int geometry_x, geometry_y, geometry_width, geometry_height, dest_x, dest_y;
|
|
|
|
Widget toplevel_widget = this.get_toplevel();
|
|
|
|
toplevel_widget.get_window().get_geometry(out geometry_x, out geometry_y, out geometry_width, out geometry_height);
|
|
|
|
toplevel_widget.translate_coordinates(main, x_root - geometry_x, y_root - geometry_y, out dest_x, out dest_y);
|
|
|
|
|
|
|
|
// Get widget under pointer
|
|
|
|
int h = 0;
|
|
|
|
bool @break = false;
|
|
|
|
Widget w = null;
|
|
|
|
main.@foreach((widget) => {
|
|
|
|
if (break) return;
|
|
|
|
|
|
|
|
h += widget.get_allocated_height();
|
|
|
|
w = widget;
|
|
|
|
if (h >= dest_y) {
|
|
|
|
@break = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// Get widget coordinates in main
|
|
|
|
int widget_x, widget_y;
|
|
|
|
w.translate_coordinates(main, 0, 0, out widget_x, out widget_y);
|
|
|
|
|
|
|
|
// Get MessageItem
|
|
|
|
var iter = widgets.map_iterator();
|
|
|
|
while (iter.next()) {
|
|
|
|
if (iter.get_value() == w) {
|
|
|
|
Plugins.MetaConversationItem meta_item = iter.get_key();
|
|
|
|
var meta_content_item = meta_item as ContentMetaItem;
|
|
|
|
if (meta_content_item == null) return;
|
|
|
|
current_highlighted_item = meta_content_item.content_item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Highlight widget
|
|
|
|
if (currently_highlighted != null) currently_highlighted.unset_state_flags(StateFlags.PRELIGHT);
|
|
|
|
w.set_state_flags(StateFlags.PRELIGHT, true);
|
|
|
|
currently_highlighted = w;
|
|
|
|
|
|
|
|
// Move message menu
|
|
|
|
message_menu_box.margin_top = widget_y - 10;
|
|
|
|
}
|
|
|
|
|
2017-08-27 21:55:49 +00:00
|
|
|
public void initialize_for_conversation(Conversation? conversation) {
|
2018-09-18 19:28:56 +00:00
|
|
|
// Workaround for rendering issues
|
2018-04-24 12:59:28 +00:00
|
|
|
if (firstLoad) {
|
2018-09-18 19:28:56 +00:00
|
|
|
main.visible = false;
|
|
|
|
Idle.add(() => {
|
|
|
|
main.visible=true;
|
2018-04-24 12:59:28 +00:00
|
|
|
return false;
|
|
|
|
});
|
|
|
|
firstLoad = false;
|
2018-07-25 18:41:51 +00:00
|
|
|
}
|
2018-09-18 19:28:56 +00:00
|
|
|
stack.set_visible_child_name("void");
|
2019-12-23 20:53:45 +00:00
|
|
|
clear();
|
2018-09-18 19:28:56 +00:00
|
|
|
initialize_for_conversation_(conversation);
|
|
|
|
display_latest();
|
|
|
|
stack.set_visible_child_name("main");
|
2020-03-21 19:53:10 +00:00
|
|
|
|
|
|
|
enable_menu_box = false;
|
2018-07-25 18:41:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void initialize_around_message(Conversation conversation, ContentItem content_item) {
|
|
|
|
stack.set_visible_child_name("void");
|
|
|
|
clear();
|
|
|
|
initialize_for_conversation_(conversation);
|
|
|
|
Gee.List<ContentMetaItem> before_items = content_populator.populate_before(conversation, content_item, 40);
|
|
|
|
foreach (ContentMetaItem item in before_items) {
|
|
|
|
do_insert_item(item);
|
|
|
|
}
|
|
|
|
ContentMetaItem meta_item = content_populator.get_content_meta_item(content_item);
|
|
|
|
meta_item.can_merge = false;
|
|
|
|
Widget w = insert_new(meta_item);
|
|
|
|
content_items.add(meta_item);
|
|
|
|
meta_items.add(meta_item);
|
|
|
|
|
|
|
|
Gee.List<ContentMetaItem> after_items = content_populator.populate_after(conversation, content_item, 40);
|
|
|
|
foreach (ContentMetaItem item in after_items) {
|
|
|
|
do_insert_item(item);
|
|
|
|
}
|
|
|
|
if (after_items.size == 40) {
|
|
|
|
at_current_content = false;
|
|
|
|
}
|
2018-04-24 12:59:28 +00:00
|
|
|
|
2019-06-01 14:00:21 +00:00
|
|
|
// Compute where to jump to for centered message, jump, highlight.
|
2018-07-25 18:41:51 +00:00
|
|
|
reload_messages = false;
|
|
|
|
Timeout.add(700, () => {
|
|
|
|
int h = 0, i = 0;
|
2019-06-01 14:00:21 +00:00
|
|
|
bool @break = false;
|
2018-07-25 18:41:51 +00:00
|
|
|
main.@foreach((widget) => {
|
2019-06-01 14:00:21 +00:00
|
|
|
if (widget == w || @break) {
|
|
|
|
@break = true;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
h += widget.get_allocated_height();
|
|
|
|
i++;
|
2018-07-25 18:41:51 +00:00
|
|
|
});
|
|
|
|
scrolled.vadjustment.value = h - scrolled.vadjustment.page_size * 1/3;
|
|
|
|
w.get_style_context().add_class("highlight-once");
|
|
|
|
reload_messages = true;
|
|
|
|
stack.set_visible_child_name("main");
|
|
|
|
return false;
|
|
|
|
});
|
2018-04-24 12:59:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void initialize_for_conversation_(Conversation? conversation) {
|
2018-09-11 12:41:51 +00:00
|
|
|
// Deinitialize old conversation
|
2017-12-01 01:28:51 +00:00
|
|
|
Dino.Application app = Dino.Application.get_default();
|
|
|
|
if (this.conversation != null) {
|
2018-06-19 16:07:00 +00:00
|
|
|
foreach (Plugins.ConversationItemPopulator populator in app.plugin_registry.conversation_addition_populators) {
|
2017-12-01 01:28:51 +00:00
|
|
|
populator.close(conversation);
|
|
|
|
}
|
2018-06-19 10:52:00 +00:00
|
|
|
foreach (Plugins.NotificationPopulator populator in app.plugin_registry.notification_populators) {
|
|
|
|
populator.close(conversation);
|
|
|
|
}
|
2017-12-01 01:28:51 +00:00
|
|
|
}
|
2018-09-11 12:41:51 +00:00
|
|
|
|
|
|
|
// Clear data structures
|
|
|
|
clear_notifications();
|
2017-08-27 21:55:49 +00:00
|
|
|
this.conversation = conversation;
|
2018-06-23 09:59:21 +00:00
|
|
|
|
2018-09-11 12:41:51 +00:00
|
|
|
// Init for new conversation
|
2018-06-23 09:59:21 +00:00
|
|
|
foreach (Plugins.ConversationItemPopulator populator in app.plugin_registry.conversation_addition_populators) {
|
|
|
|
populator.init(conversation, this, Plugins.WidgetType.GTK);
|
|
|
|
}
|
|
|
|
content_populator.init(this, conversation, Plugins.WidgetType.GTK);
|
|
|
|
subscription_notification.init(conversation, this);
|
|
|
|
|
2018-07-25 18:41:51 +00:00
|
|
|
animate = false;
|
|
|
|
Timeout.add(20, () => { animate = true; return false; });
|
2018-06-23 09:59:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void display_latest() {
|
2018-06-19 16:07:00 +00:00
|
|
|
Gee.List<ContentMetaItem> items = content_populator.populate_latest(conversation, 40);
|
|
|
|
foreach (ContentMetaItem item in items) {
|
2018-06-23 09:59:21 +00:00
|
|
|
do_insert_item(item);
|
2018-06-19 16:07:00 +00:00
|
|
|
}
|
2018-11-10 14:05:14 +00:00
|
|
|
Application app = GLib.Application.get_default() as Application;
|
2018-06-19 10:52:00 +00:00
|
|
|
foreach (Plugins.NotificationPopulator populator in app.plugin_registry.notification_populators) {
|
|
|
|
populator.init(conversation, this, Plugins.WidgetType.GTK);
|
|
|
|
}
|
2017-12-06 17:08:20 +00:00
|
|
|
Idle.add(() => { on_value_notify(); return false; });
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
|
2019-05-25 19:57:23 +00:00
|
|
|
public void insert_item(Plugins.MetaConversationItem item) {
|
2018-08-03 17:41:23 +00:00
|
|
|
if (meta_items.size > 0) {
|
2019-12-19 17:14:37 +00:00
|
|
|
bool after_last = meta_items.last().sort_time.compare(item.sort_time) <= 0;
|
2018-08-03 17:41:23 +00:00
|
|
|
bool within_range = meta_items.last().sort_time.compare(item.sort_time) > 0 && meta_items.first().sort_time.compare(item.sort_time) < 0;
|
|
|
|
bool accept = within_range || (at_current_content && after_last);
|
|
|
|
if (!accept) {
|
|
|
|
return;
|
|
|
|
}
|
2018-07-31 08:55:15 +00:00
|
|
|
}
|
2018-08-03 17:41:23 +00:00
|
|
|
do_insert_item(item);
|
2018-07-31 08:55:15 +00:00
|
|
|
}
|
|
|
|
|
2018-06-23 09:59:21 +00:00
|
|
|
public void do_insert_item(Plugins.MetaConversationItem item) {
|
2017-08-29 22:03:37 +00:00
|
|
|
lock (meta_items) {
|
2019-06-01 14:00:21 +00:00
|
|
|
insert_new(item);
|
|
|
|
if (item as ContentMetaItem != null) {
|
|
|
|
content_items.add(item);
|
2017-08-29 22:03:37 +00:00
|
|
|
}
|
2019-06-01 14:00:21 +00:00
|
|
|
meta_items.add(item);
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
2019-05-25 19:57:23 +00:00
|
|
|
|
|
|
|
inserted_item(item);
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
|
2019-05-25 19:57:23 +00:00
|
|
|
private void remove_item(Plugins.MetaConversationItem item) {
|
2018-06-23 09:59:21 +00:00
|
|
|
ConversationItemSkeleton? skeleton = item_item_skeletons[item];
|
2018-07-31 08:55:15 +00:00
|
|
|
if (skeleton != null) {
|
2019-06-01 14:00:21 +00:00
|
|
|
widgets[item].destroy();
|
|
|
|
widgets.unset(item);
|
|
|
|
skeleton.destroy();
|
|
|
|
item_skeletons.remove(skeleton);
|
|
|
|
item_item_skeletons.unset(item);
|
|
|
|
|
2018-07-31 08:55:15 +00:00
|
|
|
content_items.remove(item);
|
|
|
|
meta_items.remove(item);
|
2017-08-29 22:03:37 +00:00
|
|
|
}
|
2019-05-25 19:57:23 +00:00
|
|
|
|
|
|
|
removed_item(item);
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
|
2018-06-11 06:11:04 +00:00
|
|
|
public void on_add_meta_notification(Plugins.MetaConversationNotification notification) {
|
|
|
|
Widget? widget = (Widget) notification.get_widget(Plugins.WidgetType.GTK);
|
2018-06-19 10:52:00 +00:00
|
|
|
if (widget != null) {
|
2018-06-11 06:11:04 +00:00
|
|
|
add_notification(widget);
|
2018-06-19 10:52:00 +00:00
|
|
|
}
|
2018-06-11 06:11:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public void on_remove_meta_notification(Plugins.MetaConversationNotification notification){
|
|
|
|
Widget? widget = (Widget) notification.get_widget(Plugins.WidgetType.GTK);
|
2018-06-19 10:52:00 +00:00
|
|
|
if (widget != null) {
|
2018-06-11 06:11:04 +00:00
|
|
|
remove_notification(widget);
|
2018-06-19 10:52:00 +00:00
|
|
|
}
|
2018-06-11 06:11:04 +00:00
|
|
|
}
|
|
|
|
|
2017-12-14 01:01:55 +00:00
|
|
|
public void add_notification(Widget widget) {
|
|
|
|
notifications.add(widget);
|
|
|
|
Timeout.add(20, () => {
|
|
|
|
notification_revealer.transition_duration = 200;
|
|
|
|
notification_revealer.reveal_child = true;
|
|
|
|
return false;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public void remove_notification(Widget widget) {
|
|
|
|
notification_revealer.reveal_child = false;
|
|
|
|
widget.destroy();
|
|
|
|
}
|
|
|
|
|
2018-07-25 18:41:51 +00:00
|
|
|
private Widget insert_new(Plugins.MetaConversationItem item) {
|
2017-11-21 21:17:04 +00:00
|
|
|
Plugins.MetaConversationItem? lower_item = meta_items.lower(item);
|
|
|
|
|
|
|
|
// Fill datastructure
|
2020-03-21 19:53:10 +00:00
|
|
|
ConversationItemSkeleton item_skeleton = new ConversationItemSkeleton(stream_interactor, conversation, item, !animate) { visible=true };
|
2017-08-27 21:55:49 +00:00
|
|
|
item_item_skeletons[item] = item_skeleton;
|
|
|
|
int index = lower_item != null ? item_skeletons.index_of(item_item_skeletons[lower_item]) + 1 : 0;
|
|
|
|
item_skeletons.insert(index, item_skeleton);
|
|
|
|
|
2017-11-21 21:17:04 +00:00
|
|
|
// Insert widget
|
2020-03-21 19:53:10 +00:00
|
|
|
widgets[item] = item_skeleton;
|
|
|
|
main.add(item_skeleton);
|
|
|
|
main.reorder_child(item_skeleton, index);
|
2017-08-29 22:03:37 +00:00
|
|
|
|
2019-06-01 14:00:21 +00:00
|
|
|
if (lower_item != null) {
|
2019-11-13 16:42:47 +00:00
|
|
|
if (can_merge(item, lower_item)) {
|
|
|
|
ConversationItemSkeleton lower_skeleton = item_item_skeletons[lower_item];
|
2019-06-01 14:00:21 +00:00
|
|
|
item_skeleton.show_skeleton = false;
|
|
|
|
lower_skeleton.last_group_item = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-13 16:42:47 +00:00
|
|
|
Plugins.MetaConversationItem? upper_item = meta_items.higher(item);
|
|
|
|
if (upper_item != null) {
|
|
|
|
if (!can_merge(upper_item, item)) {
|
|
|
|
ConversationItemSkeleton upper_skeleton = item_item_skeletons[upper_item];
|
|
|
|
upper_skeleton.show_skeleton = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-21 21:17:04 +00:00
|
|
|
// If an item from the past was added, add everything between that item and the (post-)first present item
|
2017-08-29 22:03:37 +00:00
|
|
|
if (index == 0) {
|
|
|
|
Dino.Application app = Dino.Application.get_default();
|
|
|
|
if (item_skeletons.size == 1) {
|
2018-06-19 16:07:00 +00:00
|
|
|
foreach (Plugins.ConversationAdditionPopulator populator in app.plugin_registry.conversation_addition_populators) {
|
2017-08-31 16:40:58 +00:00
|
|
|
populator.populate_timespan(conversation, item.sort_time, new DateTime.now_utc());
|
2017-08-29 22:03:37 +00:00
|
|
|
}
|
|
|
|
} else {
|
2018-06-19 16:07:00 +00:00
|
|
|
foreach (Plugins.ConversationAdditionPopulator populator in app.plugin_registry.conversation_addition_populators) {
|
2017-08-31 16:40:58 +00:00
|
|
|
populator.populate_timespan(conversation, item.sort_time, meta_items.higher(item).sort_time);
|
2017-08-29 22:03:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2020-03-21 19:53:10 +00:00
|
|
|
return item_skeleton;
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
|
2019-11-13 16:42:47 +00:00
|
|
|
private bool can_merge(Plugins.MetaConversationItem upper_item /*more recent, displayed below*/, Plugins.MetaConversationItem lower_item /*less recent, displayed above*/) {
|
|
|
|
return upper_item.display_time != null && lower_item.display_time != null &&
|
|
|
|
upper_item.display_time.difference(lower_item.display_time) < TimeSpan.MINUTE &&
|
|
|
|
upper_item.jid.equals(lower_item.jid) &&
|
|
|
|
upper_item.encryption == lower_item.encryption &&
|
|
|
|
(upper_item.mark == Message.Marked.WONTSEND) == (lower_item.mark == Message.Marked.WONTSEND);
|
|
|
|
}
|
|
|
|
|
2017-08-27 21:55:49 +00:00
|
|
|
private void on_upper_notify() {
|
2018-08-07 14:03:00 +00:00
|
|
|
if (was_upper == null || scrolled.vadjustment.value > was_upper - was_page_size - 1) { // scrolled down or content smaller than page size
|
2018-06-23 09:59:21 +00:00
|
|
|
if (at_current_content) {
|
|
|
|
scrolled.vadjustment.value = scrolled.vadjustment.upper - scrolled.vadjustment.page_size; // scroll down
|
|
|
|
}
|
2017-08-27 21:55:49 +00:00
|
|
|
} else if (scrolled.vadjustment.value < scrolled.vadjustment.upper - scrolled.vadjustment.page_size - 1) {
|
|
|
|
scrolled.vadjustment.value = scrolled.vadjustment.upper - was_upper + scrolled.vadjustment.value; // stay at same content
|
|
|
|
}
|
|
|
|
was_upper = scrolled.vadjustment.upper;
|
|
|
|
was_page_size = scrolled.vadjustment.page_size;
|
2018-06-23 09:59:21 +00:00
|
|
|
was_value = scrolled.vadjustment.value;
|
2017-08-27 21:55:49 +00:00
|
|
|
reloading_mutex.trylock();
|
|
|
|
reloading_mutex.unlock();
|
|
|
|
}
|
|
|
|
|
|
|
|
private void on_value_notify() {
|
2018-06-23 09:59:21 +00:00
|
|
|
if (scrolled.vadjustment.value < 400) {
|
2017-08-27 21:55:49 +00:00
|
|
|
load_earlier_messages();
|
2018-06-23 09:59:21 +00:00
|
|
|
} else if (scrolled.vadjustment.upper - (scrolled.vadjustment.value + scrolled.vadjustment.page_size) < 400) {
|
|
|
|
load_later_messages();
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void load_earlier_messages() {
|
|
|
|
was_value = scrolled.vadjustment.value;
|
|
|
|
if (!reloading_mutex.trylock()) return;
|
2018-06-19 16:07:00 +00:00
|
|
|
if (meta_items.size > 0) {
|
2018-07-16 19:26:39 +00:00
|
|
|
Gee.List<ContentMetaItem> items = content_populator.populate_before(conversation, (content_items.first() as ContentMetaItem).content_item, 20);
|
2018-06-23 09:59:21 +00:00
|
|
|
foreach (ContentMetaItem item in items) {
|
|
|
|
do_insert_item(item);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
reloading_mutex.unlock();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private void load_later_messages() {
|
|
|
|
if (!reloading_mutex.trylock()) return;
|
|
|
|
if (meta_items.size > 0 && !at_current_content) {
|
2018-07-16 19:26:39 +00:00
|
|
|
Gee.List<ContentMetaItem> items = content_populator.populate_after(conversation, (content_items.last() as ContentMetaItem).content_item, 20);
|
2018-06-23 09:59:21 +00:00
|
|
|
if (items.size == 0) {
|
|
|
|
at_current_content = true;
|
|
|
|
}
|
2018-06-19 16:07:00 +00:00
|
|
|
foreach (ContentMetaItem item in items) {
|
2018-06-23 09:59:21 +00:00
|
|
|
do_insert_item(item);
|
2018-06-19 16:07:00 +00:00
|
|
|
}
|
2018-06-23 09:59:21 +00:00
|
|
|
} else {
|
|
|
|
reloading_mutex.unlock();
|
2018-06-19 16:07:00 +00:00
|
|
|
}
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
|
2018-06-23 09:59:21 +00:00
|
|
|
private static int compare_meta_items(Plugins.MetaConversationItem a, Plugins.MetaConversationItem b) {
|
2018-12-10 17:27:02 +00:00
|
|
|
int cmp1 = a.sort_time.compare(b.sort_time);
|
|
|
|
if (cmp1 == 0) {
|
|
|
|
double cmp2 = a.seccondary_sort_indicator - b.seccondary_sort_indicator;
|
|
|
|
if (cmp2 == 0) {
|
|
|
|
return (int) (a.tertiary_sort_indicator - b.tertiary_sort_indicator);
|
2018-08-03 17:41:23 +00:00
|
|
|
}
|
2018-12-10 17:27:02 +00:00
|
|
|
return (int) cmp2;
|
2017-08-31 20:22:44 +00:00
|
|
|
}
|
2018-12-10 17:27:02 +00:00
|
|
|
return cmp1;
|
2017-08-31 20:22:44 +00:00
|
|
|
}
|
|
|
|
|
2017-08-27 21:55:49 +00:00
|
|
|
private void clear() {
|
2018-07-25 18:41:51 +00:00
|
|
|
was_upper = null;
|
|
|
|
was_page_size = null;
|
2018-06-23 09:59:21 +00:00
|
|
|
content_items.clear();
|
2017-08-27 21:55:49 +00:00
|
|
|
meta_items.clear();
|
|
|
|
item_skeletons.clear();
|
|
|
|
item_item_skeletons.clear();
|
2017-11-22 20:09:39 +00:00
|
|
|
widgets.clear();
|
|
|
|
main.@foreach((widget) => { widget.destroy(); });
|
2018-09-11 12:41:51 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private void clear_notifications() {
|
2017-12-14 01:01:55 +00:00
|
|
|
notifications.@foreach((widget) => { widget.destroy(); });
|
|
|
|
notification_revealer.transition_duration = 0;
|
|
|
|
notification_revealer.set_reveal_child(false);
|
2017-08-27 21:55:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|