Philipp Hörist pushed to branch master at gajim / gajim
Commits: da1849fb by lovetox at 2022-01-11T21:39:39+01:00 Scripts: Improve link-gtk.py
- - - - - 8bcc7abc by lovetox at 2022-01-11T21:39:39+01:00 Add decorators for action callbacks
- - - - - 43630cb5 by lovetox at 2022-01-11T21:41:33+01:00 Menus: Refactor
- Simplify code - Use structs for actions
- - - - - 8ddce2ab by lovetox at 2022-01-11T21:45:41+01:00 Update pyrightconfig.json
- - - - -
8 changed files:
- gajim/gtk/application.py - gajim/gtk/chat_list_stack.py - gajim/gtk/menus.py - gajim/gtk/structs.py - gajim/gtk/util.py - gajim/gtk/workspace_side_bar.py - pyrightconfig.json - scripts/ci/link-gtk.py
Changes:
===================================== gajim/gtk/application.py ===================================== @@ -75,9 +75,7 @@ from gajim.gui.dialogs import ShortcutsWindow from gajim.gui.about import AboutDialog from gajim.gui.discovery import ServiceDiscoveryWindow -from gajim.gui.structs import ForgetGroupchatActionParams -from gajim.gui.structs import OpenEventActionParams -from gajim.gtk.structs import RemoveHistoryActionParams +from gajim.gui import structs
ActionListT = list[tuple[str, @@ -712,9 +710,9 @@ def _on_file_transfer_action(_action: Gio.SimpleAction, ft.window.show_all()
@staticmethod + @structs.actionfunction def _on_open_event_action(_action: Gio.SimpleAction, - param: GLib.Variant) -> None: - params = OpenEventActionParams.from_variant(param) + params: structs.OpenEventActionParams) -> None:
if params.type in ('connection-failed', 'subscription-request', @@ -780,10 +778,10 @@ def _on_open_chat_action(_action: Gio.SimpleAction, app.interface.start_chat_from_jid(account, jid)
@staticmethod + @structs.actionfunction def _on_remove_history_action(_action: Gio.SimpleAction, - param: GLib.Variant) -> None: - - params = RemoveHistoryActionParams.from_variant(param) + params: structs.RemoveHistoryActionParams + ) -> None:
if params.jid is not None: app.storage.archive.remove_history(params.account, params.jid) @@ -795,10 +793,11 @@ def _on_remove_history_action(_action: Gio.SimpleAction, control.reset_view()
@staticmethod + @structs.actionfunction def _on_forget_groupchat_action(_action: Gio.SimpleAction, - param: GLib.Variant) -> None: + params: structs.ForgetGroupchatActionParams + ) -> None:
- params = ForgetGroupchatActionParams.from_variant(param) window = get_app_window('StartChatDialog') window.remove_row(params.account, str(params.jid))
===================================== gajim/gtk/chat_list_stack.py ===================================== @@ -12,6 +12,8 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
+from __future__ import annotations + from typing import Dict from typing import Optional from typing import cast @@ -26,6 +28,7 @@ from gajim.common import app from gajim.common.events import ApplicationEvent
+from . import structs from .chat_filter import ChatFilter from .chat_list import ChatList from .chat_list import ChatRow @@ -85,7 +88,7 @@ def __init__(self, def _add_actions(self) -> None: actions = [ ('toggle-chat-pinned', 'as', self._toggle_chat_pinned), - ('move-chat-to-workspace', 'as', self._move_chat_to_workspace), + ('move-chat-to-workspace', 'a{sv}', self._move_chat_to_workspace), ('mark-as-read', 'as', self._mark_as_read), ]
@@ -210,23 +213,22 @@ def _toggle_chat_pinned(self, chat_list.toggle_chat_pinned(account, jid) self.store_open_chats(workspace_id)
+ @structs.actionmethod def _move_chat_to_workspace(self, _action: Gio.SimpleAction, - param: GLib.Variant + params: structs.MoveChatToWorkspaceAP ) -> None: - new_workspace_id, account, jid = param.unpack() - jid = JID.from_string(jid)
current_chatlist = cast(ChatList, self.get_visible_child()) - type_ = current_chatlist.get_chat_type(account, jid) + type_ = current_chatlist.get_chat_type(params.account, params.jid) if type_ is None: return - current_chatlist.remove_chat(account, jid) + current_chatlist.remove_chat(params.account, params.jid)
- new_chatlist = self.get_chatlist(new_workspace_id) - new_chatlist.add_chat(account, jid, type_) + new_chatlist = self.get_chatlist(params.workspace_id) + new_chatlist.add_chat(params.account, params.jid, type_) self.store_open_chats(current_chatlist.workspace_id) - self.store_open_chats(new_workspace_id) + self.store_open_chats(params.workspace_id)
def _mark_as_read(self, _action: Gio.SimpleAction,
===================================== gajim/gtk/menus.py ===================================== @@ -15,7 +15,7 @@ # along with Gajim. If not, see http://www.gnu.org/licenses/.
from __future__ import annotations -from typing import Tuple + from typing import List from typing import Union from typing import Any @@ -40,13 +40,21 @@ from gajim.common.const import URIType from gajim.common.const import URIAction from gajim.common.structs import URI -from gajim.gtk.structs import AddChatActionParams +from gajim.common.structs import VariantMixin
+from gajim.gui.structs import AddChatActionParams from gajim.gui.structs import ForgetGroupchatActionParams +from gajim.gui.structs import MoveChatToWorkspaceAP from gajim.gui.structs import RemoveHistoryActionParams +from gajim.gui.util import make_menu_item +from gajim.gui.util import make_menu from gajim.gui.const import ControlType
+MenuValueT = Union[None, str, GLib.Variant, VariantMixin] +MenuItemListT = list[tuple[str, str, MenuValueT]] + + def get_singlechat_menu(control_id: str, account: str, jid: JID, @@ -477,55 +485,37 @@ def get_roster_menu(account: str, jid: str, gateway: bool = False) -> Gio.Menu:
def get_subscription_menu(account: str, jid: JID) -> Gio.Menu: - menu = Gio.Menu() - - add_chat = Gio.MenuItem.new(_('Start Chat')) params = AddChatActionParams(account=account, jid=jid, type='contact', select=True) - - add_chat.set_action_and_target_value('win.add-chat', params.to_variant()) - menu.append_item(add_chat) - - menu_items = [ - ('contact-info', _('Information')), - ('subscription-block', _('Block')), - ('subscription-report', _('Report')), - ('subscription-deny', _('Deny')), + value = f's("{jid}")' + menuitems: MenuItemListT = [ + (_('Start Chat'), 'win.add-chat', params), + (_('Information'), f'win.contact-info-{account}', value), + (_('Block'), f'win.subscription-block-{account}', value), + (_('Report'), f'win.subscription-report-{account}', value), + (_('Deny'), f'win.subscription-deny-{account}', value), ] - for item in menu_items: - action, label = item - action = f'win.{action}-{account}' - menuitem = Gio.MenuItem.new(label, action) - variant = GLib.Variant('s', str(jid)) - menuitem.set_action_and_target_value(action, variant) - menu.append_item(menuitem)
- return menu + return make_menu(menuitems)
def get_start_chat_row_menu(account: str, jid: JID) -> Gio.Menu: - menu_items: List[Tuple[str, str]] = [ - ('forget-groupchat', _('Forget this Group Chat')), + params = ForgetGroupchatActionParams(account=account, jid=jid) + menuitems: MenuItemListT = [ + (_('Forget this Group Chat'), 'app.forget-groupchat', params), ] - menu = Gio.Menu() - for item in menu_items: - action, label = item - action = f'app.{action}' - menuitem = Gio.MenuItem.new(label, action) - params = ForgetGroupchatActionParams(account=account, jid=jid) - menuitem.set_action_and_target_value(action, params.to_variant()) - menu.append_item(menuitem) - return menu + + return make_menu(menuitems)
def get_chat_list_row_menu(workspace_id: str, account: str, - jid: Union[JID, str], + jid: JID, pinned: bool ) -> Gio.Menu: - jid = str(jid) + client = app.get_client(account) contact = client.get_module('Contacts').get_contact(jid)
@@ -560,7 +550,7 @@ def get_chat_list_row_menu(workspace_id: str, action = f'win.{action}' menuitem = Gio.MenuItem.new(label, action) variant_list = GLib.Variant( - 'as', [workspace_id, account, jid]) + 'as', [workspace_id, account, str(jid)]) menuitem.set_action_and_target_value(action, variant_list) menu.append_item(menuitem) else: @@ -575,18 +565,19 @@ def get_chat_list_row_menu(workspace_id: str,
def build_workspaces_submenu(current_workspace_id: str, account: str, - jid: str + jid: JID ) -> Gio.Menu: submenu = Gio.Menu() for workspace_id in app.settings.get_workspaces(): if workspace_id == current_workspace_id: continue name = app.settings.get_workspace_setting(workspace_id, 'name') - action = 'win.move-chat-to-workspace' - menuitem = Gio.MenuItem.new(name, action) - variant_list = GLib.Variant('as', [workspace_id, account, jid]) - menuitem.set_action_and_target_value(action, variant_list) - submenu.append_item(menuitem) + params = MoveChatToWorkspaceAP(workspace_id=workspace_id, + account=account, + jid=jid) + + item = make_menu_item(name, 'win.move-chat-to-workspace', params) + submenu.append_item(item) return submenu
===================================== gajim/gtk/structs.py ===================================== @@ -14,9 +14,15 @@
from __future__ import annotations
+from typing import Any +from typing import Callable from typing import Optional
+import sys +import inspect +import functools from dataclasses import dataclass +from gi.repository import GLib, Gio
from nbxmpp.protocol import JID
@@ -49,3 +55,41 @@ class AddChatActionParams(VariantMixin): jid: JID type: str select: bool + + +@dataclass +class MoveChatToWorkspaceAP(VariantMixin): + workspace_id: str + account: str + jid: JID + + +def get_params_class(func: Callable[..., Any]) -> Any: + module = sys.modules[__name__] + params = inspect.signature(func).parameters + cls_string = params['params'].annotation + cls_string = cls_string.rsplit('.', maxsplit=1)[-1] + return getattr(module, cls_string) + + +def actionmethod(func: Callable[[Any, Gio.SimpleAction, Any], None] + ) -> Callable[[Any, Gio.SimpleAction, GLib.Variant], None]: + @functools.wraps(func) + def method_wrapper(obj: Any, + action: Gio.SimpleAction, + param: GLib.Variant) -> None: + params_cls = get_params_class(func) + params = params_cls.from_variant(param) + return func(obj, action, params) + return method_wrapper + + +def actionfunction(func: Callable[[Gio.SimpleAction, Any], None] + ) -> Callable[[Gio.SimpleAction, GLib.Variant], None]: + @functools.wraps(func) + def func_wrapper(action: Gio.SimpleAction, + param: GLib.Variant) -> None: + params_cls = get_params_class(func) + params = params_cls.from_variant(param) + return func(action, params) + return func_wrapper
===================================== gajim/gtk/util.py ===================================== @@ -15,6 +15,8 @@ # You should have received a copy of the GNU General Public License # along with Gajim. If not, see http://www.gnu.org/licenses/.
+from __future__ import annotations + from typing import Any from typing import List from typing import Tuple @@ -36,6 +38,7 @@ pass
from gi.repository import Gdk +from gi.repository import Gio from gi.repository import Gtk from gi.repository import GLib from gi.repository import Pango @@ -54,6 +57,7 @@ from gajim.common.const import StyleAttr from gajim.common.ged import EventHelper as CommonEventHelper from gajim.common.styling import PlainBlock +from gajim.common.structs import VariantMixin
from .const import GajimIconSet from .const import WINDOW_MODULES @@ -62,6 +66,9 @@ log = logging.getLogger('gajim.gui.util')
+MenuValueT = Union[None, str, GLib.Variant, VariantMixin] + + class NickCompletionGenerator: def __init__(self, self_nick: str) -> None: self.nick = self_nick @@ -901,3 +908,28 @@ def get_key_theme() -> Optional[str]: if settings is None: return None return settings.get_property('gtk-key-theme-name') + + +def make_menu_item(label: str, + action: str, + value: MenuValueT = None) -> Gio.MenuItem: + + if value is None: + return Gio.MenuItem.new(label, action) + + item = Gio.MenuItem.new(label) + if isinstance(value, str): + item.set_detailed_action(f'{action}::value') + elif isinstance(value, VariantMixin): + item.set_action_and_target_value(action, value.to_variant()) + else: + item.set_action_and_target_value(action, value) + return item + + +def make_menu(menuitems: list[tuple[str, str, MenuValueT]]) -> Gio.Menu: + menu = Gio.Menu() + for item in menuitems: + menuitem = make_menu_item(*item) + menu.append_item(menuitem) + return menu
===================================== gajim/gtk/workspace_side_bar.py ===================================== @@ -25,6 +25,7 @@ from gi.repository import Gio from gi.repository import GLib from gi.repository import Gtk +from nbxmpp.protocol import JID
from gajim.common import app from gajim.common.const import AvatarSize @@ -32,6 +33,7 @@
from .chat_list_stack import ChatListStack from .chat_page import ChatPage +from .structs import MoveChatToWorkspaceAP from .util import open_window
log = logging.getLogger('gajim.gui.workspace_sidebar') @@ -148,9 +150,11 @@ def _process_chat_list_drop(self, identifier: str, y_coord: int) -> None: if workspace_row.workspace_id == 'add': return
- app.window.activate_action( - 'move-chat-to-workspace', - GLib.Variant('as', [workspace_row.workspace_id, account, jid])) + params = MoveChatToWorkspaceAP(workspace_id=workspace_row.workspace_id, + account=account, + jid=JID.from_string(jid)) + app.window.activate_action('move-chat-to-workspace', + params.to_variant())
def _get_row_before(self, row): return self.get_row_at_index(row.get_index() - 1)
===================================== pyrightconfig.json ===================================== @@ -38,7 +38,8 @@ "gajim/gtk/conversation/scrolled.py", "gajim/gtk/main_stack.py", "gajim/gtk/notification.py", - "gajim/gtk/side_bar_switcher.py", + "gajim/gtk/structs.py", + "gajim/gtk/sidebar_switcher.py", "gajim/gtk/status_icon.py", "gajim/gtk/status_message_selector.py", "gajim/gtk/status_selector.py",
===================================== scripts/ci/link-gtk.py ===================================== @@ -21,6 +21,8 @@ def cleanup_dir(target_dir: Path) -> None: for path in target_dir.iterdir(): if path.name in IGNORED_FILES: continue + if path.name in IGNORED_DIRS: + continue path.unlink()
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/a916538ff7aa6519d33ad9239c8f1f7b...