diff --git a/briar-gtk/briar_gtk/controllers/main_window.py b/briar-gtk/briar_gtk/controllers/main_window.py index 9a67c227a277fd2423a91bfbe475413897d6a8e4..772ec56ade58c4a4f53eb3834342b5a4d6fe606c 100644 --- a/briar-gtk/briar_gtk/controllers/main_window.py +++ b/briar-gtk/briar_gtk/controllers/main_window.py @@ -27,24 +27,36 @@ class MainWindowController: about_dialog.show() def open_change_contact_alias_dialog(self): - self._private_chat_controller.open_change_contact_alias_dialog() + if self._private_chat_controller is not None: + self._private_chat_controller.open_change_contact_alias_dialog() def open_delete_all_messages_dialog(self): - self._private_chat_controller.open_delete_all_messages_dialog() + if self._private_chat_controller is not None: + self._private_chat_controller.open_delete_all_messages_dialog() def open_delete_contact_dialog(self): - self._private_chat_controller.open_delete_contact_dialog() + if self._private_chat_controller is not None: + self._private_chat_controller.open_delete_contact_dialog() def close_private_chat(self): - self._private_chat_controller.close_private_chat() + if self._private_chat_controller is not None: + self._private_chat_controller.close_private_chat() + self._private_chat_controller = None def open_private_chat(self, contact_id): - self._private_chat_controller.open_private_chat(contact_id) + if self._private_chat_controller is not None: + raise Exception("Private Chat is already open") + private_chat_view = PrivateChatView(self._builder) + self._private_chat_controller = PrivateChatController( + contact_id, private_chat_view, self._sidebar_controller, + self._builder, APP().api) def _setup_children(self): self._setup_notification_handler() self._setup_sidebar_controller() - self._setup_private_chat_controller() + self._private_chat_controller = None + contact_name_label = self._builder.get_object("contact_name") + contact_name_label.set_text("") def _setup_notification_handler(self): self._notification_handler = NotificationHandler() @@ -54,12 +66,6 @@ class MainWindowController: self._sidebar_controller = SidebarController( sidebar_view, APP().api) - def _setup_private_chat_controller(self): - private_chat_view = PrivateChatView(self._builder) - self._private_chat_controller = PrivateChatController( - private_chat_view, self._sidebar_controller, - self._builder, APP().api) - def _setup_destroy_listener(self): self._main_window_view.connect("destroy", self._on_destroy) diff --git a/briar-gtk/briar_gtk/controllers/private_chat.py b/briar-gtk/briar_gtk/controllers/private_chat.py index 45bf8f7a40eca26de3a6843d1fe4a3f98f3c0e25..45e98a726f466e9e32f7f8d6700611684612a7e7 100644 --- a/briar-gtk/briar_gtk/controllers/private_chat.py +++ b/briar-gtk/briar_gtk/controllers/private_chat.py @@ -8,7 +8,6 @@ from gi.repository import Gtk from briar_wrapper.models.contacts import Contacts from briar_wrapper.models.private_chat import PrivateChat -from briar_gtk.private_chat_container import PrivateChatContainer from briar_gtk.define import APP from briar_gtk.widgets.edit_dialog import EditDialog @@ -16,11 +15,12 @@ from briar_gtk.widgets.edit_dialog import EditDialog class PrivateChatController: _current_contact_id = 0 - def __init__(self, private_chat_view, sidebar_controller, builder, api): + def __init__(self, contact_id, private_chat_view, sidebar_controller, builder, api): self._private_chat_view = private_chat_view self._sidebar_controller = sidebar_controller self._builder = builder self._api = api + self.open_private_chat(contact_id) def close_private_chat(self): # formerly `show_sidebar` main_window_leaflet = self._builder.get_object("main_window_leaflet") @@ -105,9 +105,10 @@ class PrivateChatController: confirmation_dialog.show_all() def open_private_chat(self, contact_id): + print(f"Contact id: {contact_id}") contact_name = self._get_contact_name(contact_id) self._prepare_chat_view(contact_name) - self._setup_private_chat_widget(contact_name, contact_id) + self._setup_private_chat_widget(contact_id) self._current_contact_id = contact_id @staticmethod @@ -167,11 +168,11 @@ class PrivateChatController: for child in children: child.destroy() - def _setup_private_chat_widget(self, contact_name, contact_id): - self._current_private_chat_widget = PrivateChatContainer( - contact_name, contact_id) + def _setup_private_chat_widget(self, contact_id): + self._private_chat_view.setup_view(contact_id) + self._private_chat_view.load_content() history_container = self._builder.get_object("history_container") - history_container.add(self._current_private_chat_widget) + history_container.add(self._private_chat_view) history_container.show_all() self._disconnect_chat_entry_signals() @@ -191,5 +192,5 @@ class PrivateChatController: def _on_chat_entry_activate(self, widget): if len(widget.get_text()) == 0: return - self._current_private_chat_widget.send_message(widget) + self._private_chat_view.send_message(widget) self._sidebar_controller.refresh_contacts() diff --git a/briar-gtk/briar_gtk/private_chat_container.py b/briar-gtk/briar_gtk/private_chat_container.py deleted file mode 100644 index 7a2d76893db414249429511cf1fb115ea120d3a4..0000000000000000000000000000000000000000 --- a/briar-gtk/briar_gtk/private_chat_container.py +++ /dev/null @@ -1,160 +0,0 @@ -# Copyright (c) 2019 Nico Alt -# SPDX-License-Identifier: AGPL-3.0-only -# License-Filename: LICENSE.md -# -# Initial version based on GNOME Fractal -# https://gitlab.gnome.org/GNOME/fractal/-/tags/4.2.2 -import os -import time - -from gi.repository import GLib, Gtk, Handy - -from briar_wrapper.models.private_chat import PrivateChat - -from briar_gtk.define import APP, RESOURCES_DIR -from briar_gtk.widgets.private_message import PrivateMessageWidget - - -class PrivateChatContainer(Gtk.Overlay): - - CONTAINER_UI = "private_chat.ui" - - def __init__(self, contact_name, contact_id): - super().__init__() - self.builder = Gtk.Builder() - - self._signals = list() - self._contact_name = contact_name - self._contact_id = contact_id - self._previous_message = dict() - - self._setup_view() - self._load_content() - - def send_message(self, widget): - message = widget.get_text() - private_chat = PrivateChat(APP().api, self._contact_id) - private_chat.send(message) - - self._add_message( - { - "text": message, - "local": True, - "sent": False, - "seen": False, - - # TODO: Remove once web events updating is implemented - "no_stored_indicator": True, - - "timestamp": int(round(time.time() * 1000)) - }) - widget.set_text("") - GLib.idle_add(self._scroll_to_bottom) - - def _setup_view(self): - self._add_from_resource(self.CONTAINER_UI) - - self._messages_box = Gtk.ListBox() - self._messages_box.get_style_context().add_class("messages-history") - self._messages_box.show() - - clamp = Handy.Clamp.new() - clamp.set_maximum_size(800) - clamp.set_tightening_threshold(600) - clamp.set_hexpand(True) - clamp.set_vexpand(True) - clamp.add(self._messages_box) - clamp.show() - - messages_column = self.builder.get_object("messages_column") - messages_column.get_style_context().add_class("messages-box") - messages_column.add(clamp) - messages_column.show() - - messages_scroll = self.builder.get_object("messages_scroll") - self._draw_signal_id = messages_scroll.connect( - "draw", self._on_message_scroll_draw - ) - self.add(messages_scroll) - - self.builder.connect_signals(self) - self._setup_destroy_listener() - - def _add_from_resource(self, ui_filename): - self.builder.add_from_resource( - os.path.join(RESOURCES_DIR, ui_filename) - ) - - def _setup_destroy_listener(self): - self.connect("destroy", self._on_destroy) - - # pylint: disable=unused-argument - def _on_destroy(self, widget): - self._disconnect_signals() - - def _disconnect_signals(self): - for signal in self._signals: - APP().api.socket_listener.disconnect(signal) - - def _load_content(self): - private_chat = PrivateChat(APP().api, self._contact_id) - messages_list = private_chat.get() - self._messages_count = len(messages_list) - for message in messages_list: - # Abusing idle_add function here because otherwise the message box - # is too small and scrolling cuts out messages - GLib.idle_add(self._add_message, message) - if message.get("read", True) is False: - GLib.idle_add(private_chat.mark_read, message["id"]) - socket_listener = APP().api.socket_listener - signal_id = socket_listener.connect("ConversationMessageReceivedEvent", - self._add_message_async) - self._signals.append(signal_id) - - def _add_message(self, message): - if self._is_not_message(message): - return - message_widget = PrivateMessageWidget( - self._contact_name, - message, - self._previous_message - ) - self._previous_message = message - self._messages_box.add(message_widget) - - @staticmethod - def _is_not_message(message): - return "text" not in message - - def _add_message_async(self, message): - if message["data"]["contactId"] != self._contact_id: - return - GLib.idle_add(self._add_message_and_scroll, message["data"]) - if message["data"].get("read", True) is False: - private_chat = PrivateChat(APP().api, self._contact_id) - GLib.idle_add(private_chat.mark_read, message["data"]["id"]) - - def _add_message_and_scroll(self, message): - self._add_message(message) - GLib.idle_add(self._scroll_to_bottom) - - # pylint: disable=unused-argument - def _on_message_scroll_draw(self, widget, cairo_context): - self._scroll_to_bottom() - if self._draw_signal_is_not_needed(): - widget.disconnect(self._draw_signal_id) - - def _scroll_to_bottom(self): - messages_scroll = self.builder.get_object("messages_scroll") - adjustment = messages_scroll.get_vadjustment() - adjustment.set_value( - adjustment.get_upper() - adjustment.get_page_size() - ) - - def _draw_signal_is_not_needed(self): - if self._messages_count == 0: - return True - - messages_scroll = self.builder.get_object("messages_scroll") - adjustment = messages_scroll.get_vadjustment() - return adjustment.get_value() != 0 diff --git a/briar-gtk/briar_gtk/views/private_chat.py b/briar-gtk/briar_gtk/views/private_chat.py index 2acb4f561e3f1a42fa929fded8fa79df1fcddc41..73ffea7dffb45249d4b424946967ea8b1af5f7b2 100644 --- a/briar-gtk/briar_gtk/views/private_chat.py +++ b/briar-gtk/briar_gtk/views/private_chat.py @@ -1,14 +1,158 @@ -# Copyright (c) 2020 Nico Alt +# Copyright (c) 2019-2020 Nico Alt # SPDX-License-Identifier: AGPL-3.0-only # License-Filename: LICENSE.md +# +# Initial version based on GNOME Fractal +# https://gitlab.gnome.org/GNOME/fractal/-/tags/4.2.2 +import os +import time +from gi.repository import GLib, Gtk, Handy -class PrivateChatView: +from briar_wrapper.models.private_chat import PrivateChat + +from briar_gtk.define import APP, RESOURCES_DIR +from briar_gtk.widgets.private_message import PrivateMessageWidget + + +class PrivateChatView(Gtk.Overlay): + + CONTAINER_UI = "private_chat.ui" def __init__(self, builder): - self._builder = builder - self._setup_view() + super().__init__() + self.builder = builder + + self._signals = list() + self._contact_name = "" + self._contact_id = -1 + self._previous_message = dict() + + def send_message(self, widget): + message = widget.get_text() + private_chat = PrivateChat(APP().api, self._contact_id) + private_chat.send(message) + + self._add_message( + { + "text": message, + "local": True, + "sent": False, + "seen": False, + + # TODO: Remove once web events updating is implemented + "no_stored_indicator": True, + + "timestamp": int(round(time.time() * 1000)) + }) + widget.set_text("") + GLib.idle_add(self._scroll_to_bottom) + + def setup_view(self, contact_id): + self._contact_id = contact_id + self._add_from_resource(self.CONTAINER_UI) + + self._messages_box = Gtk.ListBox() + self._messages_box.get_style_context().add_class("messages-history") + self._messages_box.show() + + clamp = Handy.Clamp.new() + clamp.set_maximum_size(800) + clamp.set_tightening_threshold(600) + clamp.set_hexpand(True) + clamp.set_vexpand(True) + clamp.add(self._messages_box) + clamp.show() + + messages_column = self.builder.get_object("messages_column") + messages_column.get_style_context().add_class("messages-box") + messages_column.add(clamp) + messages_column.show() + + messages_scroll = self.builder.get_object("messages_scroll") + self._draw_signal_id = messages_scroll.connect( + "draw", self._on_message_scroll_draw + ) + self.add(messages_scroll) + + self.builder.connect_signals(self) + self._setup_destroy_listener() + + def _add_from_resource(self, ui_filename): + self.builder.add_from_resource( + os.path.join(RESOURCES_DIR, ui_filename) + ) + + def _setup_destroy_listener(self): + self.connect("destroy", self._on_destroy) + + # pylint: disable=unused-argument + def _on_destroy(self, widget): + self._disconnect_signals() + + def _disconnect_signals(self): + for signal in self._signals: + APP().api.socket_listener.disconnect(signal) + + def load_content(self): + private_chat = PrivateChat(APP().api, self._contact_id) + messages_list = private_chat.get() + self._messages_count = len(messages_list) + for message in messages_list: + # Abusing idle_add function here because otherwise the message box + # is too small and scrolling cuts out messages + GLib.idle_add(self._add_message, message) + if message.get("read", True) is False: + GLib.idle_add(private_chat.mark_read, message["id"]) + socket_listener = APP().api.socket_listener + signal_id = socket_listener.connect("ConversationMessageReceivedEvent", + self._add_message_async) + self._signals.append(signal_id) + + def _add_message(self, message): + if self._is_not_message(message): + return + message_widget = PrivateMessageWidget( + self._contact_name, + message, + self._previous_message + ) + self._previous_message = message + self._messages_box.add(message_widget) + + @staticmethod + def _is_not_message(message): + return "text" not in message + + def _add_message_async(self, message): + if message["data"]["contactId"] != self._contact_id: + return + GLib.idle_add(self._add_message_and_scroll, message["data"]) + if message["data"].get("read", True) is False: + private_chat = PrivateChat(APP().api, self._contact_id) + GLib.idle_add(private_chat.mark_read, message["data"]["id"]) + + def _add_message_and_scroll(self, message): + self._add_message(message) + GLib.idle_add(self._scroll_to_bottom) + + # pylint: disable=unused-argument + def _on_message_scroll_draw(self, widget, cairo_context): + self._scroll_to_bottom() + if self._draw_signal_is_not_needed(): + widget.disconnect(self._draw_signal_id) + + def _scroll_to_bottom(self): + messages_scroll = self.builder.get_object("messages_scroll") + adjustment = messages_scroll.get_vadjustment() + adjustment.set_value( + adjustment.get_upper() - adjustment.get_page_size() + ) + + def _draw_signal_is_not_needed(self): + if self._messages_count == 0: + return True - def _setup_view(self): - contact_name_label = self._builder.get_object("contact_name") - contact_name_label.set_text("") + messages_scroll = self.builder.get_object("messages_scroll") + adjustment = messages_scroll.get_vadjustment() + return adjustment.get_value() != 0