From e21fe0558de49425573fd3bf72386af73f6af3fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20H=C3=B6rist?= Date: Tue, 14 Nov 2023 20:06:58 +0000 Subject: feat: Add shortcuts for quoting previous messages --- gajim/data/gui/shortcuts_window.ui | 14 +++++++++++ gajim/data/other/shortcuts.json | 4 +++- gajim/gtk/chat_stack.py | 26 +++++++++++++++++++- gajim/gtk/const.py | 2 ++ gajim/gtk/control.py | 3 +++ gajim/gtk/conversation/view.py | 49 ++++++++++++++++++++++++++++++++++++-- gajim/gtk/message_actions_box.py | 11 +++++++++ 7 files changed, 105 insertions(+), 4 deletions(-) diff --git a/gajim/data/gui/shortcuts_window.ui b/gajim/data/gui/shortcuts_window.ui index 649934843..ed88ed604 100644 --- a/gajim/data/gui/shortcuts_window.ui +++ b/gajim/data/gui/shortcuts_window.ui @@ -108,6 +108,20 @@ Correct the last message + + + 1 + <primary><shift>Up + Quote previous message + + + + + 1 + <primary><shift>Down + Quote next message + + 1 diff --git a/gajim/data/other/shortcuts.json b/gajim/data/other/shortcuts.json index 4f26e891f..3139358fd 100644 --- a/gajim/data/other/shortcuts.json +++ b/gajim/data/other/shortcuts.json @@ -43,5 +43,7 @@ "win.reset-app-font-size": ["0", "KP_0"], "win.toggle-chat-list": ["R"], "win.scroll-view-up": ["Page_Up"], - "win.scroll-view-down": ["Page_Down"] + "win.scroll-view-down": ["Page_Down"], + "win.quote-prev": ["Up"], + "win.quote-next": ["Down"] } diff --git a/gajim/gtk/chat_stack.py b/gajim/gtk/chat_stack.py index b8050cedc..7ef7bf57b 100644 --- a/gajim/gtk/chat_stack.py +++ b/gajim/gtk/chat_stack.py @@ -65,6 +65,7 @@ class ChatStack(Gtk.Stack, EventHelper): self.set_hexpand(True) self._current_contact: ChatContactT | None = None + self._last_quoted_id: int | None = None self.add_named(ChatPlaceholderBox(), 'empty') @@ -185,6 +186,8 @@ class ChatStack(Gtk.Stack, EventHelper): clipboard = Gtk.Clipboard.get(Gdk.SELECTION_PRIMARY) old_primary_clipboard = clipboard.wait_for_text() + self._last_quoted_id = None + if self._current_contact is not None: self._current_contact.disconnect_all_from_obj(self) @@ -483,6 +486,8 @@ class ChatStack(Gtk.Stack, EventHelper): 'muc-change-role', 'muc-change-affiliation', 'muc-request-voice', + 'quote-next', + 'quote-prev', ] for action in actions: @@ -556,9 +561,14 @@ class ChatStack(Gtk.Stack, EventHelper): action: Gio.SimpleAction, param: GLib.Variant | None) -> None: + if self.get_visible_child_name() != 'controls': + return + action_name = action.get_name() contact = self._current_contact - assert contact is not None + if contact is None: + return + account = contact.account client = app.get_client(account) jid = contact.jid @@ -648,6 +658,18 @@ class ChatStack(Gtk.Stack, EventHelper): elif action_name == 'muc-request-voice': client.get_module('MUC').request_voice(contact.jid) + elif action_name.startswith('quote-'): + view = self._chat_control.get_conversation_view() + if action_name == 'quote-prev': + row = view.get_prev_message_row(self._last_quoted_id) + else: + row = view.get_next_message_row(self._last_quoted_id) + + if row is not None: + self._last_quoted_id = row.log_line_id + self._message_action_box.insert_as_quote( + row.get_text(), clear=True) + def _on_drag_data_received(self, _widget: Gtk.Widget, _context: Gdk.DragContext, @@ -788,6 +810,7 @@ class ChatStack(Gtk.Stack, EventHelper): client.send_message(message_) self._message_action_box.msg_textview.clear() + self._last_quoted_id = None app.storage.drafts.set(contact, '') def get_last_message_id(self, contact: ChatContactT) -> str | None: @@ -805,6 +828,7 @@ class ChatStack(Gtk.Stack, EventHelper): if self._current_contact is not None: self._current_contact.disconnect_all_from_obj(self) + self._last_quoted_id = None self.set_visible_child_name('empty') self._chat_banner.clear() self._message_action_box.clear() diff --git a/gajim/gtk/const.py b/gajim/gtk/const.py index 085eb449e..dd17857a0 100644 --- a/gajim/gtk/const.py +++ b/gajim/gtk/const.py @@ -223,6 +223,8 @@ MAIN_WIN_ACTIONS = [ ('copy-message', 's', True), ('retract-message', 'a{sv}', False), ('quote', 's', False), + ('quote-next', None, True), + ('quote-prev', None, True), ('mention', 's', False), ('send-file-httpupload', 'as', False), ('send-file-jingle', 'as', False), diff --git a/gajim/gtk/control.py b/gajim/gtk/control.py index 7480f32bb..ef2ddbbce 100644 --- a/gajim/gtk/control.py +++ b/gajim/gtk/control.py @@ -144,6 +144,9 @@ class ChatControl(EventHelper): def get_group_chat_roster(self) -> GroupchatRoster: return self._roster + def get_conversation_view(self) -> ConversationView: + return self._scrolled_view + def add_command_output(self, text: str, is_error: bool) -> None: self._scrolled_view.add_command_output(text, is_error) diff --git a/gajim/gtk/conversation/view.py b/gajim/gtk/conversation/view.py index d7cc32dff..fdbe85e4b 100644 --- a/gajim/gtk/conversation/view.py +++ b/gajim/gtk/conversation/view.py @@ -37,6 +37,7 @@ from nbxmpp.structs import MucSubject from gajim.common import app from gajim.common import events from gajim.common import types +from gajim.common.const import Direction from gajim.common.helpers import AdditionalDataDict from gajim.common.helpers import get_start_of_day from gajim.common.helpers import to_user_string @@ -390,8 +391,7 @@ class ConversationView(Gtk.ScrolledWindow): return None def get_last_message_row(self) -> MessageRow | None: - children = self._list_box.get_children() - children.reverse() + children = reversed(self._list_box.get_children()) for row in children: if isinstance(row, MessageRow): return row @@ -710,6 +710,51 @@ class ConversationView(Gtk.ScrolledWindow): def _get_row_by_message_id(self, id_: str) -> MessageRow | None: return self._message_id_row_map.get(id_) + def _get_message_row_by_direction( + self, + log_line_id: int, + direction: Direction | None = None + ) -> MessageRow | None: + + row = self.get_row_by_log_line_id(log_line_id) + if row is None: + return None + + if direction is None: + return row + + index = row.get_index() + while True: + if direction == Direction.PREV: + index -= 1 + else: + index += 1 + + row = self._list_box.get_row_at_index(index) + if row is None: + return None + + if isinstance(row, MessageRow): + return row + + def get_prev_message_row( + self, + log_line_id: int | None + ) -> MessageRow | None: + if log_line_id is None: + return self.get_last_message_row() + return self._get_message_row_by_direction( + log_line_id, direction=Direction.PREV) + + def get_next_message_row( + self, + log_line_id: int | None + ) -> MessageRow | None: + if log_line_id is None: + return None + return self._get_message_row_by_direction( + log_line_id, direction=Direction.NEXT) + def get_row_by_log_line_id(self, log_line_id: int) -> MessageRow | None: for row in cast(list[BaseRow], self._list_box.get_children()): if not isinstance(row, MessageRow): diff --git a/gajim/gtk/message_actions_box.py b/gajim/gtk/message_actions_box.py index dc9031e57..a377c5ecd 100644 --- a/gajim/gtk/message_actions_box.py +++ b/gajim/gtk/message_actions_box.py @@ -218,6 +218,17 @@ class MessageActionsBox(Gtk.Grid): def is_correcting(self) -> bool: return self.msg_textview.is_correcting + def insert_as_quote(self, text: str, *, clear: bool = False) -> None: + if self._contact is None: + return + + if not self.msg_textview.is_sensitive(): + return + + if clear: + self.msg_textview.clear() + self.msg_textview.insert_as_quote(text) + def toggle_message_correction(self) -> None: self.msg_textview.toggle_message_correction() -- cgit v1.2.3