diff --git a/gajim/data/gui/account_page.ui b/gajim/data/gui/account_page.ui index 25776df3ae1f83b785dfed7cacca3f9e27844088..6742ebcc5ea2d89be11002f509efe557af930e53 100644 --- a/gajim/data/gui/account_page.ui +++ b/gajim/data/gui/account_page.ui @@ -235,7 +235,7 @@ <object class="GtkLabel"> <property name="visible">True</property> <property name="can-focus">False</property> - <property name="label" translatable="yes">Contact Requests</property> + <property name="label" translatable="yes">Notifications</property> <style> <class name="bold16"/> </style> diff --git a/gajim/gtk/account_page.py b/gajim/gtk/account_page.py index 755248ccfdec1f4eb705563092775ec3c70172c1..84b2f875fbff8dd60890782d50f71268927e551c 100644 --- a/gajim/gtk/account_page.py +++ b/gajim/gtk/account_page.py @@ -23,7 +23,7 @@ from .roster import Roster from .status_selector import StatusSelector -from .subscription_manager import SubscriptionManager +from .notification_manager import NotificationManager from .util import get_builder from .util import open_window @@ -49,8 +49,8 @@ def __init__(self, account): self._status_selector.set_halign(Gtk.Align.CENTER) self._ui.account_action_box.add(self._status_selector) - self._subscription_manager = SubscriptionManager(account) - self._ui.account_box.add(self._subscription_manager) + self._notification_manager = NotificationManager(account) + self._ui.account_box.add(self._notification_manager) self._roster = Roster(account) self._ui.roster_box.add(self._roster) @@ -66,9 +66,12 @@ def __init__(self, account): self._ui.connect_signals(self) self.show_all() + # pylint: disable=line-too-long self.register_events([ - ('subscribe-presence-received', ged.GUI1, self._on_subscribe_received), + ('subscribe-presence-received', ged.GUI1, self._subscribe_received), + ('unsubscribed-presence-received', ged.GUI1, self._unsubscribed_received), ]) + # pylint: enable=line-too-long self.update() @@ -105,9 +108,12 @@ def update(self): self._status_selector.update() - def _on_subscribe_received(self, event): - self._subscription_manager.add_request( + def _subscribe_received(self, event): + self._notification_manager.add_subscription_request( event.jid, event.status, user_nick=event.user_nick) + def _unsubscribed_received(self, event): + self._notification_manager.add_unsubscribed(event.jid) + def process_event(self, event): self._roster.process_event(event) diff --git a/gajim/gtk/subscription_manager.py b/gajim/gtk/notification_manager.py similarity index 60% rename from gajim/gtk/subscription_manager.py rename to gajim/gtk/notification_manager.py index 4b6c87d4188463f5631b5cf236c00207f4b02da8..cab98377103743e4e327c311348db89e5cab93d4 100644 --- a/gajim/gtk/subscription_manager.py +++ b/gajim/gtk/notification_manager.py @@ -20,23 +20,21 @@ from gajim.common import app from gajim.common.i18n import _ -from gajim.gui_menu_builder import get_subscription_manager_menu +from gajim.gui_menu_builder import get_subscription_menu from .add_contact import AddNewContactWindow -class SubscriptionManager(Gtk.ScrolledWindow): +class NotificationManager(Gtk.ScrolledWindow): def __init__(self, account): Gtk.ScrolledWindow.__init__(self) self._account = account self._client = app.get_client(account) - self.set_hexpand(True) self.set_size_request(400, 200) self._listbox = Gtk.ListBox() self._listbox.set_selection_mode(Gtk.SelectionMode.NONE) - self._listbox.get_style_context().add_class('subscription-listbox') self._set_placeholder() self.add(self._listbox) @@ -88,7 +86,7 @@ def _remove_actions(self): app.window.remove_action(f'{action}-{self._account}') def _set_placeholder(self): - label = Gtk.Label(label=_('No pending requests.')) + label = Gtk.Label(label=_('No Notifications')) label.set_valign(Gtk.Align.START) label.get_style_context().add_class('dim-label') label.show() @@ -96,7 +94,7 @@ def _set_placeholder(self): def _on_subscription_accept(self, _action, param): jid = param.get_string() - row = self._get_request_row(jid) + row = self._get_notification_row(jid) self._client.get_module('Presence').subscribed(jid) contact = self._client.get_module('Contacts').get_contact(jid) if not contact.is_in_roster: @@ -108,7 +106,7 @@ def _on_subscription_block(self, _action, param): app.events.remove_events(self._account, jid) self._deny_request(jid) self._client.get_module('Blocking').block([jid]) - row = self._get_request_row(jid) + row = self._get_notification_row(jid) self._listbox.remove(row) def _on_subscription_report(self, _action, param): @@ -116,81 +114,148 @@ def _on_subscription_report(self, _action, param): app.events.remove_events(self._account, jid) self._deny_request(jid) self._client.get_module('Blocking').block([jid], report='spam') - row = self._get_request_row(jid) + row = self._get_notification_row(jid) self._listbox.remove(row) def _on_subscription_deny(self, _action, param): jid = param.get_string() self._deny_request(jid) - row = self._get_request_row(jid) + row = self._get_notification_row(jid) self._listbox.remove(row) def _deny_request(self, jid): self._client.get_module('Presence').unsubscribed(jid) - def _get_request_row(self, jid): + def _get_notification_row(self, jid): for child in self._listbox.get_children(): if child.jid == jid: return child return None - def add_request(self, jid, text, user_nick=None): - if self._get_request_row(jid) is None: - self._listbox.add(RequestRow(self._account, jid, text, user_nick)) + def add_subscription_request(self, jid, text, user_nick=None): + row = self._get_notification_row(jid) + if row is None: + self._listbox.add(SubscriptionRequestRow( + self._account, jid, text, user_nick)) + elif row.type == 'unsubscribed': + self._listbox.remove(row) + def add_unsubscribed(self, jid): + row = self._get_notification_row(jid) + if row is None: + self._listbox.add(UnsubscribedRow(self._account, jid)) + elif row.type == 'subscribe': + self._listbox.remove(row) -class RequestRow(Gtk.ListBoxRow): - def __init__(self, account, jid, text, user_nick): + +class NotificationRow(Gtk.ListBoxRow): + def __init__(self, account, jid): Gtk.ListBoxRow.__init__(self) self._account = account + self._client = app.get_client(account) self.jid = jid - self.user_nick = user_nick self.get_style_context().add_class('padding-6') - grid = Gtk.Grid(column_spacing=12) + self.grid = Gtk.Grid(column_spacing=12) + self.add(self.grid) + + @staticmethod + def _generate_label(): + label = Gtk.Label() + label.set_halign(Gtk.Align.START) + label.set_xalign(0) + label.set_ellipsize(Pango.EllipsizeMode.END) + label.set_max_width_chars(30) + return label + + +class SubscriptionRequestRow(NotificationRow): + def __init__(self, account, jid, text, user_nick): + NotificationRow.__init__(self, account, jid) + self.type = 'subscribe' + image = Gtk.Image.new_from_icon_name( 'avatar-default-symbolic', Gtk.IconSize.DND) image.set_valign(Gtk.Align.CENTER) - grid.attach(image, 1, 1, 1, 2) + self.grid.attach(image, 1, 1, 1, 2) if user_nick is not None: escaped_nick = GLib.markup_escape_text(user_nick) nick_markup = f'<b>{escaped_nick}</b> ({jid})' else: nick_markup = f'<b>{jid}</b>' - nick_label = Gtk.Label() - nick_label.set_halign(Gtk.Align.START) - nick_label.set_ellipsize(Pango.EllipsizeMode.END) - nick_label.set_max_width_chars(30) + + nick_label = self._generate_label() nick_label.set_tooltip_markup(nick_markup) nick_label.set_markup(nick_markup) - grid.attach(nick_label, 2, 1, 1, 1) + self.grid.attach(nick_label, 2, 1, 1, 1) message_text = GLib.markup_escape_text(text) - text_label = Gtk.Label(label=message_text) - text_label.set_halign(Gtk.Align.START) - text_label.set_ellipsize(Pango.EllipsizeMode.END) - text_label.set_max_width_chars(30) + text_label = self._generate_label() + text_label.set_text(message_text) text_label.set_tooltip_text(message_text) text_label.get_style_context().add_class('dim-label') - grid.attach(text_label, 2, 2, 1, 1) + self.grid.attach(text_label, 2, 2, 1, 1) accept_button = Gtk.Button.new_with_label(label=_('Accept')) accept_button.set_valign(Gtk.Align.CENTER) accept_button.set_action_name( f'win.subscription-accept-{self._account}') accept_button.set_action_target_value(GLib.Variant('s', str(self.jid))) - grid.attach(accept_button, 3, 1, 1, 2) + self.grid.attach(accept_button, 3, 1, 1, 2) more_image = Gtk.Image.new_from_icon_name( 'view-more-symbolic', Gtk.IconSize.MENU) more_button = Gtk.MenuButton() more_button.set_valign(Gtk.Align.CENTER) more_button.add(more_image) - subscription_menu = get_subscription_manager_menu( - self._account, self.jid) + subscription_menu = get_subscription_menu(self._account, self.jid) more_button.set_menu_model(subscription_menu) - grid.attach(more_button, 4, 1, 1, 2) + self.grid.attach(more_button, 4, 1, 1, 2) - self.add(grid) self.show_all() + + +class UnsubscribedRow(NotificationRow): + def __init__(self, account, jid): + NotificationRow.__init__(self, account, jid) + self.type = 'unsubscribed' + + image = Gtk.Image.new_from_icon_name( + 'avatar-default-symbolic', Gtk.IconSize.DND) + image.set_valign(Gtk.Align.CENTER) + self.grid.attach(image, 1, 1, 1, 2) + + contact = self._client.get_module('Contacts').get_contact(jid) + nick_markup = f'<b>{contact.name}</b>' + nick_label = self._generate_label() + nick_label.set_tooltip_markup(nick_markup) + nick_label.set_markup(nick_markup) + self.grid.attach(nick_label, 2, 1, 1, 1) + + message_text = _('Stopped sharing their status') + text_label = self._generate_label() + text_label.set_text(message_text) + text_label.set_tooltip_text(message_text) + text_label.get_style_context().add_class('dim-label') + self.grid.attach(text_label, 2, 2, 1, 1) + + remove_button = Gtk.Button.new_with_label(label=_('Remove')) + remove_button.set_valign(Gtk.Align.CENTER) + remove_button.set_tooltip_text('Remove from contact list') + remove_button.set_action_name( + f'win.remove-contact-{self._account}') + remove_button.set_action_target_value(GLib.Variant('s', str(self.jid))) + self.grid.attach(remove_button, 3, 1, 1, 2) + + dismiss_button = Gtk.Button.new_from_icon_name( + 'window-close-symbolic', Gtk.IconSize.BUTTON) + dismiss_button.set_valign(Gtk.Align.CENTER) + dismiss_button.set_tooltip_text(_('Remove Notification')) + dismiss_button.connect('clicked', self._on_dismiss) + self.grid.attach(dismiss_button, 4, 1, 1, 2) + + self.show_all() + + def _on_dismiss(self, _button): + self.get_parent().remove(self) diff --git a/gajim/gui_interface.py b/gajim/gui_interface.py index 9693b7286abb51aa354d3678881b9e8c3bd5a9d6..fd4310efb30dafa2160c164f0cc378889457e3cc 100644 --- a/gajim/gui_interface.py +++ b/gajim/gui_interface.py @@ -301,26 +301,6 @@ def handle_event_msgnotsent(obj): obj.session.roster_message(obj.jid, msg, obj.time_, obj.conn.name, msg_type='error') - def show_unsubscribed_dialog(self, account, contact): - def _remove(): - self.roster.on_req_usub(None, [(contact, account)]) - - name = contact.get_shown_name() - jid = contact.jid - ConfirmationDialog( - _('Subscription Removed'), - _('%(name)s (%(jid)s) has removed subscription from you') % { - 'name': name, 'jid': jid}, - _('You will always see this contact as offline.\n' - 'Do you want to remove them from your contact list?'), - [DialogButton.make('Cancel', - text=_('_No')), - DialogButton.make('Remove', - callback=_remove)]).show() - - # FIXME: Per RFC 3921, we can "deny" ack as well, but the GUI does - # not show deny - def handle_event_gc_decline(self, event): gc_control = self.msg_win_mgr.get_gc_control(str(event.muc), event.account) @@ -1191,14 +1171,14 @@ def handle_event(self, account, fjid, type_): return # TODO: Show account page app.events.remove_events(account, jid, event) - self.roster.draw_contact(jid, account) + # self.roster.draw_contact(jid, account) elif type_ == 'unsubscribed': event = app.events.get_first_event(account, jid, type_) if event is None: return - self.show_unsubscribed_dialog(account, event.contact) + # TODO: Show account page app.events.remove_events(account, jid, event) - self.roster.draw_contact(jid, account) + # self.roster.draw_contact(jid, account) if w: w.set_active_tab(ctrl) w.window.present() diff --git a/gajim/gui_menu_builder.py b/gajim/gui_menu_builder.py index 0f5e0f1b778152e4bb5a5adeedde90a3f269447c..69047a85627cef774f03b1b11221b90636783821 100644 --- a/gajim/gui_menu_builder.py +++ b/gajim/gui_menu_builder.py @@ -816,7 +816,7 @@ def get_roster_menu(account, jid): return menu -def get_subscription_manager_menu(account, jid): +def get_subscription_menu(account, jid): menu = Gio.Menu() action_name = 'win.add-chat'