aboutsummaryrefslogtreecommitdiff
path: root/main/src
diff options
context:
space:
mode:
Diffstat (limited to 'main/src')
-rw-r--r--main/src/ui/chat_input/chat_input_controller.vala37
-rw-r--r--main/src/ui/chat_input/view.vala15
-rw-r--r--main/src/ui/conversation_content_view/conversation_item_skeleton.vala22
-rw-r--r--main/src/ui/conversation_content_view/conversation_view.vala6
-rw-r--r--main/src/ui/conversation_content_view/message_widget.vala29
-rw-r--r--main/src/ui/conversation_content_view/quote_widget.vala73
-rw-r--r--main/src/ui/conversation_content_view/reactions_widget.vala3
-rw-r--r--main/src/ui/conversation_selector/conversation_selector_row.vala2
-rw-r--r--main/src/ui/main_window_controller.vala15
9 files changed, 176 insertions, 26 deletions
diff --git a/main/src/ui/chat_input/chat_input_controller.vala b/main/src/ui/chat_input/chat_input_controller.vala
index 7b260695..de75cdf8 100644
--- a/main/src/ui/chat_input/chat_input_controller.vala
+++ b/main/src/ui/chat_input/chat_input_controller.vala
@@ -24,6 +24,8 @@ public class ChatInputController : Object {
private Plugins.InputFieldStatus input_field_status;
private ChatTextViewController chat_text_view_controller;
+ private ContentItem? quoted_content_item = null;
+
public ChatInputController(ChatInput.View chat_input, StreamInteractor stream_interactor) {
this.chat_input = chat_input;
this.status_description_label = chat_input.chat_input_status;
@@ -58,12 +60,34 @@ public class ChatInputController : Object {
}
return true;
});
+
+ SimpleAction quote_action = new SimpleAction("quote", new VariantType.tuple(new VariantType[]{VariantType.INT32, VariantType.INT32}));
+ quote_action.activate.connect((variant) => {
+ int conversation_id = variant.get_child_value(0).get_int32();
+ Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(conversation_id);
+ if (conversation == null || !this.conversation.equals(conversation)) return;
+
+ int content_item_id = variant.get_child_value(1).get_int32();
+ ContentItem? content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_item_by_id(conversation, content_item_id);
+ if (content_item == null) return;
+
+ quoted_content_item = content_item;
+ var quote_model = new Quote.Model.from_content_item(content_item, conversation, stream_interactor) { can_abort = true };
+ quote_model.aborted.connect(() => {
+ content_item = null;
+ chat_input.unset_quoted_message();
+ });
+ chat_input.set_quoted_message(Quote.get_widget(quote_model));
+ });
+ GLib.Application.get_default().add_action(quote_action);
}
public void set_conversation(Conversation conversation) {
- this.conversation = conversation;
-
+ this.quoted_content_item = null;
reset_input_field_status();
+ chat_input.unset_quoted_message();
+
+ this.conversation = conversation;
chat_input.encryption_widget.set_conversation(conversation);
@@ -111,7 +135,10 @@ public class ChatInputController : Object {
}
string text = chat_input.chat_text_view.text_view.buffer.text;
+
chat_input.chat_text_view.text_view.buffer.text = "";
+ chat_input.unset_quoted_message();
+
if (text.has_prefix("/")) {
string[] token = text.split(" ", 2);
switch(token[0]) {
@@ -164,7 +191,11 @@ public class ChatInputController : Object {
break;
}
}
- stream_interactor.get_module(MessageProcessor.IDENTITY).send_text(text, conversation);
+ Message out_message = stream_interactor.get_module(MessageProcessor.IDENTITY).create_out_message(text, conversation);
+ if (quoted_content_item != null) {
+ stream_interactor.get_module(Replies.IDENTITY).set_message_is_reply_to(out_message, quoted_content_item);
+ }
+ stream_interactor.get_module(MessageProcessor.IDENTITY).send_message(out_message, conversation);
}
private void on_text_input_changed() {
diff --git a/main/src/ui/chat_input/view.vala b/main/src/ui/chat_input/view.vala
index 4be4455b..e16b4085 100644
--- a/main/src/ui/chat_input/view.vala
+++ b/main/src/ui/chat_input/view.vala
@@ -20,8 +20,8 @@ public class View : Box {
private HashMap<Conversation, string> entry_cache = new HashMap<Conversation, string>(Conversation.hash_func, Conversation.equals_func);
[GtkChild] public unowned Frame frame;
+ [GtkChild] public unowned Box quote_box;
[GtkChild] public unowned ChatTextView chat_text_view;
- [GtkChild] public unowned Box outer_box;
[GtkChild] public unowned Button file_button;
[GtkChild] public unowned MenuButton emoji_button;
[GtkChild] public unowned MenuButton encryption_button;
@@ -94,6 +94,19 @@ public class View : Box {
});
}
+ public void set_quoted_message(Widget quote_widget) {
+ Widget? quote_box_child = quote_box.get_first_child();
+ if (quote_box_child != null) quote_box.remove(quote_box_child);
+ quote_box.append(quote_widget);
+ quote_box.visible = true;
+ }
+
+ public void unset_quoted_message() {
+ Widget? quote_box_child = quote_box.get_first_child();
+ if (quote_box_child != null) quote_box.remove(quote_box_child);
+ quote_box.visible = false;
+ }
+
public void do_focus() {
chat_text_view.text_view.grab_focus();
}
diff --git a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala
index 7113b3b7..00c88db3 100644
--- a/main/src/ui/conversation_content_view/conversation_item_skeleton.vala
+++ b/main/src/ui/conversation_content_view/conversation_item_skeleton.vala
@@ -16,7 +16,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface,
public Image encryption_image { get; set; }
public Image received_image { get; set; }
- public Widget? content_widget = null;
+ private HashMap<int, Widget> content_widgets = new HashMap<int, Widget>();
private bool show_skeleton_ = false;
public bool show_skeleton {
@@ -58,7 +58,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface,
widget = item.get_widget(this, Plugins.WidgetType.GTK4) as Widget;
if (widget != null) {
widget.valign = Align.END;
- set_widget(widget, Plugins.WidgetType.GTK4);
+ set_widget(widget, Plugins.WidgetType.GTK4, 2);
}
if (item.requires_header) {
@@ -72,7 +72,7 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface,
if (content_meta_item != null) {
reactions_controller = new ReactionsController(conversation, content_meta_item.content_item, stream_interactor);
reactions_controller.box_activated.connect((widget) => {
- main_grid.attach(widget, 1, 2, 4, 1);
+ set_widget(widget, Plugins.WidgetType.GTK4, 3);
});
reactions_controller.init();
}
@@ -103,12 +103,18 @@ public class ConversationItemSkeleton : Plugins.ConversationItemWidgetInterface,
update_received_mark();
}
- public void set_widget(Object object, Plugins.WidgetType type) {
- if (content_widget != null) content_widget.unparent();
+ public void set_widget(Object object, Plugins.WidgetType type, int priority) {
+ foreach (var content_widget in content_widgets.values) {
+ content_widget.unparent();
+ }
- Widget widget = (Widget) object;
- content_widget = widget;
- main_grid.attach(widget, 1, 1, 4, 1);
+ content_widgets[priority] = (Widget) object;
+ int row_no = 1;
+ for (int i = 0; i < 5; i++) {
+ if (!content_widgets.has_key(i)) continue;
+ main_grid.attach(content_widgets[i], 1, row_no, 4, 1);
+ row_no++;
+ }
}
private void update_margin() {
diff --git a/main/src/ui/conversation_content_view/conversation_view.vala b/main/src/ui/conversation_content_view/conversation_view.vala
index f0f6e118..70115512 100644
--- a/main/src/ui/conversation_content_view/conversation_view.vala
+++ b/main/src/ui/conversation_content_view/conversation_view.vala
@@ -18,7 +18,6 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
[GtkChild] private unowned Box notifications;
[GtkChild] private unowned Box main;
[GtkChild] private unowned Box main_wrap_box;
- [GtkChild] private unowned Stack stack;
private ArrayList<Widget> action_buttons = new ArrayList<Widget>();
private Gee.List<Dino.Plugins.MessageAction>? message_actions = null;
@@ -208,7 +207,6 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
Button button = new Button();
button.icon_name = message_action.icon_name;
button.clicked.connect(() => {
- print(@"$(current_meta_item.jid) skdfj \n");
message_action.callback(button, current_meta_item, currently_highlighted);
});
action_buttons.add(button);
@@ -233,15 +231,12 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
});
firstLoad = false;
}
- stack.set_visible_child_name("void");
clear();
initialize_for_conversation_(conversation);
display_latest();
- stack.set_visible_child_name("main");
}
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);
@@ -277,7 +272,6 @@ public class ConversationView : Widget, Plugins.ConversationItemCollection, Plug
scrolled.vadjustment.value = h - scrolled.vadjustment.page_size * 1/3;
w.add_css_class("highlight-once");
reload_messages = true;
- stack.set_visible_child_name("main");
return false;
});
}
diff --git a/main/src/ui/conversation_content_view/message_widget.vala b/main/src/ui/conversation_content_view/message_widget.vala
index 1f027c89..f4e1d22c 100644
--- a/main/src/ui/conversation_content_view/message_widget.vala
+++ b/main/src/ui/conversation_content_view/message_widget.vala
@@ -82,7 +82,8 @@ public class MessageMetaItem : ContentMetaItem {
bool theme_dependent = false;
- string markup_text = message.body;
+ string markup_text = Dino.message_body_without_reply_fallback(message);
+
if (markup_text.length > 10000) {
markup_text = markup_text.substring(0, 10000) + " [" + _("Message too long") + "]";
}
@@ -169,7 +170,7 @@ public class MessageMetaItem : ContentMetaItem {
edit_mode.cancelled.connect(() => {
in_edit_mode = false;
- outer.set_widget(label, Plugins.WidgetType.GTK4);
+ outer.set_widget(label, Plugins.WidgetType.GTK4, 2);
});
edit_mode.send.connect(() => {
if (((MessageItem) content_item).message.body != edit_mode.chat_text_view.text_view.buffer.text) {
@@ -178,18 +179,31 @@ public class MessageMetaItem : ContentMetaItem {
// edit_cancelled();
}
in_edit_mode = false;
- outer.set_widget(label, Plugins.WidgetType.GTK4);
+ outer.set_widget(label, Plugins.WidgetType.GTK4, 2);
});
edit_mode.chat_text_view.text_view.buffer.text = message.body;
- outer.set_widget(edit_mode, Plugins.WidgetType.GTK4);
+ outer.set_widget(edit_mode, Plugins.WidgetType.GTK4, 2);
edit_mode.chat_text_view.text_view.grab_focus();
} else {
this.in_edit_mode = false;
}
});
+ outer.set_widget(label, Plugins.WidgetType.GTK4, 2);
+
+ if (message_item.message.quoted_item_id > 0) {
+ var quoted_content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_item_by_id(message_item.conversation, message_item.message.quoted_item_id);
+ if (quoted_content_item != null) {
+ var quote_model = new Quote.Model.from_content_item(quoted_content_item, message_item.conversation, stream_interactor);
+ quote_model.jump_to.connect(() => {
+ GLib.Application.get_default().activate_action("jump-to-conversation-message", new GLib.Variant.tuple(new GLib.Variant[] { new GLib.Variant.int32(message_item.conversation.id), new GLib.Variant.int32(message_item.id) }));
+ });
+ var quote_widget = Quote.get_widget(quote_model);
+ outer.set_widget(quote_widget, Plugins.WidgetType.GTK4, 1);
+ }
+ }
return label;
}
@@ -209,6 +223,13 @@ public class MessageMetaItem : ContentMetaItem {
actions.add(action1);
}
+ Plugins.MessageAction reply_action = new Plugins.MessageAction();
+ reply_action.icon_name = "mail-reply-sender-symbolic";
+ reply_action.callback = (button, content_meta_item_activated, widget) => {
+ GLib.Application.get_default().activate_action("quote", new GLib.Variant.tuple(new GLib.Variant[] { new GLib.Variant.int32(message_item.conversation.id), new GLib.Variant.int32(message_item.id) }));
+ };
+ actions.add(reply_action);
+
if (supports_reaction) {
Plugins.MessageAction action2 = new Plugins.MessageAction();
action2.icon_name = "dino-emoticon-add-symbolic";
diff --git a/main/src/ui/conversation_content_view/quote_widget.vala b/main/src/ui/conversation_content_view/quote_widget.vala
new file mode 100644
index 00000000..f627c852
--- /dev/null
+++ b/main/src/ui/conversation_content_view/quote_widget.vala
@@ -0,0 +1,73 @@
+using Dino.Ui.ConversationSummary;
+using Gee;
+using Gtk;
+using Xmpp;
+
+using Dino.Entities;
+
+namespace Dino.Ui.Quote {
+
+ public class Model : Object {
+ public signal void aborted();
+ public signal void jump_to();
+
+ public string display_name { get; set; }
+ public string message { get; set; }
+ public DateTime message_time { get; set; }
+
+ public StreamInteractor stream_interactor { get; set; }
+ public Conversation conversation { get; set; }
+ public Jid author_jid { get; set; }
+
+ public bool can_abort { get; set; default=false; }
+
+ public Model.from_content_item(ContentItem content_item, Conversation conversation, StreamInteractor stream_interactor) {
+ this.display_name = Util.get_participant_display_name(stream_interactor, conversation, content_item.jid, true);
+ if (content_item.type_ == MessageItem.TYPE) {
+ var message = ((MessageItem) content_item).message;
+ this.message = Dino.message_body_without_reply_fallback(message);
+ } else if (content_item.type_ == FileItem.TYPE) {
+ this.message = "[File]";
+ }
+ this.message_time = content_item.time;
+
+ this.stream_interactor = stream_interactor;
+ this.conversation = conversation;
+ this.author_jid = content_item.jid;
+ }
+ }
+
+ public Widget get_widget(Model model) {
+ Builder builder = new Builder.from_resource("/im/dino/Dino/quote.ui");
+ AvatarImage avatar = (AvatarImage) builder.get_object("avatar");
+ Label author = (Label) builder.get_object("author");
+ Label time = (Label) builder.get_object("time");
+ Label message = (Label) builder.get_object("message");
+ Button abort_button = (Button) builder.get_object("abort-button");
+
+ avatar.set_conversation_participant(model.stream_interactor, model.conversation, model.author_jid);
+ model.bind_property("display-name", author, "label", BindingFlags.SYNC_CREATE);
+ model.bind_property("message-time", time, "label", BindingFlags.SYNC_CREATE, (_, from_value, ref to_value) => {
+ DateTime message_time = (DateTime) from_value;
+ to_value = ConversationItemSkeleton.get_relative_time(message_time);
+ return true;
+ });
+ model.bind_property("message", message, "label", BindingFlags.SYNC_CREATE);
+ model.bind_property("can-abort", abort_button, "visible", BindingFlags.SYNC_CREATE);
+
+ abort_button.clicked.connect(() => {
+ model.aborted();
+ });
+
+ Widget outer = builder.get_object("outer") as Widget;
+
+ GestureClick gesture_click_controller = new GestureClick();
+ outer.add_controller(gesture_click_controller);
+ gesture_click_controller.pressed.connect(() => {
+ model.jump_to();
+ });
+
+ return outer;
+ }
+}
+
diff --git a/main/src/ui/conversation_content_view/reactions_widget.vala b/main/src/ui/conversation_content_view/reactions_widget.vala
index c9f93f66..890c1206 100644
--- a/main/src/ui/conversation_content_view/reactions_widget.vala
+++ b/main/src/ui/conversation_content_view/reactions_widget.vala
@@ -27,9 +27,6 @@ public class ReactionsController : Object {
public void init() {
Gee.List<ReactionUsers> reactions = stream_interactor.get_module(Reactions.IDENTITY).get_item_reactions(conversation, content_item);
- if (reactions.size > 0) {
- initialize_widget();
- }
foreach (ReactionUsers reaction_users in reactions) {
foreach (Jid jid in reaction_users.jids) {
reaction_added(reaction_users.reaction, jid);
diff --git a/main/src/ui/conversation_selector/conversation_selector_row.vala b/main/src/ui/conversation_selector/conversation_selector_row.vala
index a2588d9a..bd2b0747 100644
--- a/main/src/ui/conversation_selector/conversation_selector_row.vala
+++ b/main/src/ui/conversation_selector/conversation_selector_row.vala
@@ -149,7 +149,7 @@ public class ConversationSelectorRow : ListBoxRow {
MessageItem message_item = last_content_item as MessageItem;
Message last_message = message_item.message;
- string body = last_message.body;
+ string body = Dino.message_body_without_reply_fallback(last_message);
bool me_command = body.has_prefix("/me ");
/* If we have a /me command, we always show the display
diff --git a/main/src/ui/main_window_controller.vala b/main/src/ui/main_window_controller.vala
index 38ebcc9c..9e7e8ce7 100644
--- a/main/src/ui/main_window_controller.vala
+++ b/main/src/ui/main_window_controller.vala
@@ -23,6 +23,21 @@ public class MainWindowController : Object {
stream_interactor.get_module(ConversationManager.IDENTITY).conversation_deactivated.connect(check_unset_conversation);
stream_interactor.account_removed.connect(check_unset_conversation);
+
+ SimpleAction jump_to_conversatio_message_action = new SimpleAction("jump-to-conversation-message", new VariantType.tuple(new VariantType[]{VariantType.INT32, VariantType.INT32}));
+ jump_to_conversatio_message_action.activate.connect((variant) => {
+ int conversation_id = variant.get_child_value(0).get_int32();
+ Conversation? conversation = stream_interactor.get_module(ConversationManager.IDENTITY).get_conversation_by_id(conversation_id);
+ if (conversation == null || !this.conversation.equals(conversation)) return;
+
+ int item_id = variant.get_child_value(1).get_int32();
+ ContentItem? content_item = stream_interactor.get_module(ContentItemStore.IDENTITY).get_item_by_id(conversation, item_id);
+
+ select_conversation(conversation, false, false);
+ window.conversation_view.conversation_frame.initialize_around_message(conversation, content_item);
+ });
+ app.add_action(jump_to_conversatio_message_action);
+
}
public void set_window(MainWindow window) {