Philipp Hörist pushed to branch master at gajim / gajim

Commits:

8 changed files:

Changes:

  • gajim/gtk/application.py
    ... ... @@ -75,9 +75,7 @@
    75 75
     from gajim.gui.dialogs import ShortcutsWindow
    
    76 76
     from gajim.gui.about import AboutDialog
    
    77 77
     from gajim.gui.discovery import ServiceDiscoveryWindow
    
    78
    -from gajim.gui.structs import ForgetGroupchatActionParams
    
    79
    -from gajim.gui.structs import OpenEventActionParams
    
    80
    -from gajim.gtk.structs import RemoveHistoryActionParams
    
    78
    +from gajim.gui import structs
    
    81 79
     
    
    82 80
     
    
    83 81
     ActionListT = list[tuple[str,
    
    ... ... @@ -712,9 +710,9 @@ def _on_file_transfer_action(_action: Gio.SimpleAction,
    712 710
                 ft.window.show_all()
    
    713 711
     
    
    714 712
         @staticmethod
    
    713
    +    @structs.actionfunction
    
    715 714
         def _on_open_event_action(_action: Gio.SimpleAction,
    
    716
    -                              param: GLib.Variant) -> None:
    
    717
    -        params = OpenEventActionParams.from_variant(param)
    
    715
    +                              params: structs.OpenEventActionParams) -> None:
    
    718 716
     
    
    719 717
             if params.type in ('connection-failed',
    
    720 718
                                'subscription-request',
    
    ... ... @@ -780,10 +778,10 @@ def _on_open_chat_action(_action: Gio.SimpleAction,
    780 778
             app.interface.start_chat_from_jid(account, jid)
    
    781 779
     
    
    782 780
         @staticmethod
    
    781
    +    @structs.actionfunction
    
    783 782
         def _on_remove_history_action(_action: Gio.SimpleAction,
    
    784
    -                                  param: GLib.Variant) -> None:
    
    785
    -
    
    786
    -        params = RemoveHistoryActionParams.from_variant(param)
    
    783
    +                                  params: structs.RemoveHistoryActionParams
    
    784
    +                                  ) -> None:
    
    787 785
     
    
    788 786
             if params.jid is not None:
    
    789 787
                 app.storage.archive.remove_history(params.account, params.jid)
    
    ... ... @@ -795,10 +793,11 @@ def _on_remove_history_action(_action: Gio.SimpleAction,
    795 793
                     control.reset_view()
    
    796 794
     
    
    797 795
         @staticmethod
    
    796
    +    @structs.actionfunction
    
    798 797
         def _on_forget_groupchat_action(_action: Gio.SimpleAction,
    
    799
    -                                    param: GLib.Variant) -> None:
    
    798
    +                                    params: structs.ForgetGroupchatActionParams
    
    799
    +                                    ) -> None:
    
    800 800
     
    
    801
    -        params = ForgetGroupchatActionParams.from_variant(param)
    
    802 801
             window = get_app_window('StartChatDialog')
    
    803 802
             window.remove_row(params.account, str(params.jid))
    
    804 803
     
    

  • gajim/gtk/chat_list_stack.py
    ... ... @@ -12,6 +12,8 @@
    12 12
     # You should have received a copy of the GNU General Public License
    
    13 13
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14 14
     
    
    15
    +from __future__ import annotations
    
    16
    +
    
    15 17
     from typing import Dict
    
    16 18
     from typing import Optional
    
    17 19
     from typing import cast
    
    ... ... @@ -26,6 +28,7 @@
    26 28
     from gajim.common import app
    
    27 29
     from gajim.common.events import ApplicationEvent
    
    28 30
     
    
    31
    +from . import structs
    
    29 32
     from .chat_filter import ChatFilter
    
    30 33
     from .chat_list import ChatList
    
    31 34
     from .chat_list import ChatRow
    
    ... ... @@ -85,7 +88,7 @@ def __init__(self,
    85 88
         def _add_actions(self) -> None:
    
    86 89
             actions = [
    
    87 90
                 ('toggle-chat-pinned', 'as', self._toggle_chat_pinned),
    
    88
    -            ('move-chat-to-workspace', 'as', self._move_chat_to_workspace),
    
    91
    +            ('move-chat-to-workspace', 'a{sv}', self._move_chat_to_workspace),
    
    89 92
                 ('mark-as-read', 'as', self._mark_as_read),
    
    90 93
             ]
    
    91 94
     
    
    ... ... @@ -210,23 +213,22 @@ def _toggle_chat_pinned(self,
    210 213
             chat_list.toggle_chat_pinned(account, jid)
    
    211 214
             self.store_open_chats(workspace_id)
    
    212 215
     
    
    216
    +    @structs.actionmethod
    
    213 217
         def _move_chat_to_workspace(self,
    
    214 218
                                     _action: Gio.SimpleAction,
    
    215
    -                                param: GLib.Variant
    
    219
    +                                params: structs.MoveChatToWorkspaceAP
    
    216 220
                                     ) -> None:
    
    217
    -        new_workspace_id, account, jid = param.unpack()
    
    218
    -        jid = JID.from_string(jid)
    
    219 221
     
    
    220 222
             current_chatlist = cast(ChatList, self.get_visible_child())
    
    221
    -        type_ = current_chatlist.get_chat_type(account, jid)
    
    223
    +        type_ = current_chatlist.get_chat_type(params.account, params.jid)
    
    222 224
             if type_ is None:
    
    223 225
                 return
    
    224
    -        current_chatlist.remove_chat(account, jid)
    
    226
    +        current_chatlist.remove_chat(params.account, params.jid)
    
    225 227
     
    
    226
    -        new_chatlist = self.get_chatlist(new_workspace_id)
    
    227
    -        new_chatlist.add_chat(account, jid, type_)
    
    228
    +        new_chatlist = self.get_chatlist(params.workspace_id)
    
    229
    +        new_chatlist.add_chat(params.account, params.jid, type_)
    
    228 230
             self.store_open_chats(current_chatlist.workspace_id)
    
    229
    -        self.store_open_chats(new_workspace_id)
    
    231
    +        self.store_open_chats(params.workspace_id)
    
    230 232
     
    
    231 233
         def _mark_as_read(self,
    
    232 234
                           _action: Gio.SimpleAction,
    

  • gajim/gtk/menus.py
    ... ... @@ -15,7 +15,7 @@
    15 15
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    16 16
     
    
    17 17
     from __future__ import annotations
    
    18
    -from typing import Tuple
    
    18
    +
    
    19 19
     from typing import List
    
    20 20
     from typing import Union
    
    21 21
     from typing import Any
    
    ... ... @@ -40,13 +40,21 @@
    40 40
     from gajim.common.const import URIType
    
    41 41
     from gajim.common.const import URIAction
    
    42 42
     from gajim.common.structs import URI
    
    43
    -from gajim.gtk.structs import AddChatActionParams
    
    43
    +from gajim.common.structs import VariantMixin
    
    44 44
     
    
    45
    +from gajim.gui.structs import AddChatActionParams
    
    45 46
     from gajim.gui.structs import ForgetGroupchatActionParams
    
    47
    +from gajim.gui.structs import MoveChatToWorkspaceAP
    
    46 48
     from gajim.gui.structs import RemoveHistoryActionParams
    
    49
    +from gajim.gui.util import make_menu_item
    
    50
    +from gajim.gui.util import make_menu
    
    47 51
     from gajim.gui.const import ControlType
    
    48 52
     
    
    49 53
     
    
    54
    +MenuValueT = Union[None, str, GLib.Variant, VariantMixin]
    
    55
    +MenuItemListT = list[tuple[str, str, MenuValueT]]
    
    56
    +
    
    57
    +
    
    50 58
     def get_singlechat_menu(control_id: str,
    
    51 59
                             account: str,
    
    52 60
                             jid: JID,
    
    ... ... @@ -477,55 +485,37 @@ def get_roster_menu(account: str, jid: str, gateway: bool = False) -> Gio.Menu:
    477 485
     
    
    478 486
     
    
    479 487
     def get_subscription_menu(account: str, jid: JID) -> Gio.Menu:
    
    480
    -    menu = Gio.Menu()
    
    481
    -
    
    482
    -    add_chat = Gio.MenuItem.new(_('Start Chat'))
    
    483 488
         params = AddChatActionParams(account=account,
    
    484 489
                                      jid=jid,
    
    485 490
                                      type='contact',
    
    486 491
                                      select=True)
    
    487
    -
    
    488
    -    add_chat.set_action_and_target_value('win.add-chat', params.to_variant())
    
    489
    -    menu.append_item(add_chat)
    
    490
    -
    
    491
    -    menu_items = [
    
    492
    -        ('contact-info', _('Information')),
    
    493
    -        ('subscription-block', _('Block')),
    
    494
    -        ('subscription-report', _('Report')),
    
    495
    -        ('subscription-deny', _('Deny')),
    
    492
    +    value = f's("{jid}")'
    
    493
    +    menuitems: MenuItemListT = [
    
    494
    +        (_('Start Chat'), 'win.add-chat', params),
    
    495
    +        (_('Information'), f'win.contact-info-{account}', value),
    
    496
    +        (_('Block'), f'win.subscription-block-{account}', value),
    
    497
    +        (_('Report'), f'win.subscription-report-{account}', value),
    
    498
    +        (_('Deny'), f'win.subscription-deny-{account}', value),
    
    496 499
         ]
    
    497
    -    for item in menu_items:
    
    498
    -        action, label = item
    
    499
    -        action = f'win.{action}-{account}'
    
    500
    -        menuitem = Gio.MenuItem.new(label, action)
    
    501
    -        variant = GLib.Variant('s', str(jid))
    
    502
    -        menuitem.set_action_and_target_value(action, variant)
    
    503
    -        menu.append_item(menuitem)
    
    504 500
     
    
    505
    -    return menu
    
    501
    +    return make_menu(menuitems)
    
    506 502
     
    
    507 503
     
    
    508 504
     def get_start_chat_row_menu(account: str, jid: JID) -> Gio.Menu:
    
    509
    -    menu_items: List[Tuple[str, str]] = [
    
    510
    -        ('forget-groupchat', _('Forget this Group Chat')),
    
    505
    +    params = ForgetGroupchatActionParams(account=account, jid=jid)
    
    506
    +    menuitems: MenuItemListT = [
    
    507
    +        (_('Forget this Group Chat'), 'app.forget-groupchat', params),
    
    511 508
         ]
    
    512
    -    menu = Gio.Menu()
    
    513
    -    for item in menu_items:
    
    514
    -        action, label = item
    
    515
    -        action = f'app.{action}'
    
    516
    -        menuitem = Gio.MenuItem.new(label, action)
    
    517
    -        params = ForgetGroupchatActionParams(account=account, jid=jid)
    
    518
    -        menuitem.set_action_and_target_value(action, params.to_variant())
    
    519
    -        menu.append_item(menuitem)
    
    520
    -    return menu
    
    509
    +
    
    510
    +    return make_menu(menuitems)
    
    521 511
     
    
    522 512
     
    
    523 513
     def get_chat_list_row_menu(workspace_id: str,
    
    524 514
                                account: str,
    
    525
    -                           jid: Union[JID, str],
    
    515
    +                           jid: JID,
    
    526 516
                                pinned: bool
    
    527 517
                                ) -> Gio.Menu:
    
    528
    -    jid = str(jid)
    
    518
    +
    
    529 519
         client = app.get_client(account)
    
    530 520
         contact = client.get_module('Contacts').get_contact(jid)
    
    531 521
     
    
    ... ... @@ -560,7 +550,7 @@ def get_chat_list_row_menu(workspace_id: str,
    560 550
                 action = f'win.{action}'
    
    561 551
                 menuitem = Gio.MenuItem.new(label, action)
    
    562 552
                 variant_list = GLib.Variant(
    
    563
    -                'as', [workspace_id, account, jid])
    
    553
    +                'as', [workspace_id, account, str(jid)])
    
    564 554
                 menuitem.set_action_and_target_value(action, variant_list)
    
    565 555
                 menu.append_item(menuitem)
    
    566 556
             else:
    
    ... ... @@ -575,18 +565,19 @@ def get_chat_list_row_menu(workspace_id: str,
    575 565
     
    
    576 566
     def build_workspaces_submenu(current_workspace_id: str,
    
    577 567
                                  account: str,
    
    578
    -                             jid: str
    
    568
    +                             jid: JID
    
    579 569
                                  ) -> Gio.Menu:
    
    580 570
         submenu = Gio.Menu()
    
    581 571
         for workspace_id in app.settings.get_workspaces():
    
    582 572
             if workspace_id == current_workspace_id:
    
    583 573
                 continue
    
    584 574
             name = app.settings.get_workspace_setting(workspace_id, 'name')
    
    585
    -        action = 'win.move-chat-to-workspace'
    
    586
    -        menuitem = Gio.MenuItem.new(name, action)
    
    587
    -        variant_list = GLib.Variant('as', [workspace_id, account, jid])
    
    588
    -        menuitem.set_action_and_target_value(action, variant_list)
    
    589
    -        submenu.append_item(menuitem)
    
    575
    +        params = MoveChatToWorkspaceAP(workspace_id=workspace_id,
    
    576
    +                                       account=account,
    
    577
    +                                       jid=jid)
    
    578
    +
    
    579
    +        item = make_menu_item(name, 'win.move-chat-to-workspace', params)
    
    580
    +        submenu.append_item(item)
    
    590 581
         return submenu
    
    591 582
     
    
    592 583
     
    

  • gajim/gtk/structs.py
    ... ... @@ -14,9 +14,15 @@
    14 14
     
    
    15 15
     from __future__ import annotations
    
    16 16
     
    
    17
    +from typing import Any
    
    18
    +from typing import Callable
    
    17 19
     from typing import Optional
    
    18 20
     
    
    21
    +import sys
    
    22
    +import inspect
    
    23
    +import functools
    
    19 24
     from dataclasses import dataclass
    
    25
    +from gi.repository import GLib, Gio
    
    20 26
     
    
    21 27
     from nbxmpp.protocol import JID
    
    22 28
     
    
    ... ... @@ -49,3 +55,41 @@ class AddChatActionParams(VariantMixin):
    49 55
         jid: JID
    
    50 56
         type: str
    
    51 57
         select: bool
    
    58
    +
    
    59
    +
    
    60
    +@dataclass
    
    61
    +class MoveChatToWorkspaceAP(VariantMixin):
    
    62
    +    workspace_id: str
    
    63
    +    account: str
    
    64
    +    jid: JID
    
    65
    +
    
    66
    +
    
    67
    +def get_params_class(func: Callable[..., Any]) -> Any:
    
    68
    +    module = sys.modules[__name__]
    
    69
    +    params = inspect.signature(func).parameters
    
    70
    +    cls_string = params['params'].annotation
    
    71
    +    cls_string = cls_string.rsplit('.', maxsplit=1)[-1]
    
    72
    +    return getattr(module, cls_string)
    
    73
    +
    
    74
    +
    
    75
    +def actionmethod(func: Callable[[Any, Gio.SimpleAction, Any], None]
    
    76
    +                 ) -> Callable[[Any, Gio.SimpleAction, GLib.Variant], None]:
    
    77
    +    @functools.wraps(func)
    
    78
    +    def method_wrapper(obj: Any,
    
    79
    +                       action: Gio.SimpleAction,
    
    80
    +                       param: GLib.Variant) -> None:
    
    81
    +        params_cls = get_params_class(func)
    
    82
    +        params = params_cls.from_variant(param)
    
    83
    +        return func(obj, action, params)
    
    84
    +    return method_wrapper
    
    85
    +
    
    86
    +
    
    87
    +def actionfunction(func: Callable[[Gio.SimpleAction, Any], None]
    
    88
    +                   ) -> Callable[[Gio.SimpleAction, GLib.Variant], None]:
    
    89
    +    @functools.wraps(func)
    
    90
    +    def func_wrapper(action: Gio.SimpleAction,
    
    91
    +                     param: GLib.Variant) -> None:
    
    92
    +        params_cls = get_params_class(func)
    
    93
    +        params = params_cls.from_variant(param)
    
    94
    +        return func(action, params)
    
    95
    +    return func_wrapper

  • gajim/gtk/util.py
    ... ... @@ -15,6 +15,8 @@
    15 15
     # You should have received a copy of the GNU General Public License
    
    16 16
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    17 17
     
    
    18
    +from __future__ import annotations
    
    19
    +
    
    18 20
     from typing import Any
    
    19 21
     from typing import List
    
    20 22
     from typing import Tuple
    
    ... ... @@ -36,6 +38,7 @@
    36 38
         pass
    
    37 39
     
    
    38 40
     from gi.repository import Gdk
    
    41
    +from gi.repository import Gio
    
    39 42
     from gi.repository import Gtk
    
    40 43
     from gi.repository import GLib
    
    41 44
     from gi.repository import Pango
    
    ... ... @@ -54,6 +57,7 @@
    54 57
     from gajim.common.const import StyleAttr
    
    55 58
     from gajim.common.ged import EventHelper as CommonEventHelper
    
    56 59
     from gajim.common.styling import PlainBlock
    
    60
    +from gajim.common.structs import VariantMixin
    
    57 61
     
    
    58 62
     from .const import GajimIconSet
    
    59 63
     from .const import WINDOW_MODULES
    
    ... ... @@ -62,6 +66,9 @@
    62 66
     log = logging.getLogger('gajim.gui.util')
    
    63 67
     
    
    64 68
     
    
    69
    +MenuValueT = Union[None, str, GLib.Variant, VariantMixin]
    
    70
    +
    
    71
    +
    
    65 72
     class NickCompletionGenerator:
    
    66 73
         def __init__(self, self_nick: str) -> None:
    
    67 74
             self.nick = self_nick
    
    ... ... @@ -901,3 +908,28 @@ def get_key_theme() -> Optional[str]:
    901 908
         if settings is None:
    
    902 909
             return None
    
    903 910
         return settings.get_property('gtk-key-theme-name')
    
    911
    +
    
    912
    +
    
    913
    +def make_menu_item(label: str,
    
    914
    +                   action: str,
    
    915
    +                   value: MenuValueT = None) -> Gio.MenuItem:
    
    916
    +
    
    917
    +    if value is None:
    
    918
    +        return Gio.MenuItem.new(label, action)
    
    919
    +
    
    920
    +    item = Gio.MenuItem.new(label)
    
    921
    +    if isinstance(value, str):
    
    922
    +        item.set_detailed_action(f'{action}::value')
    
    923
    +    elif isinstance(value, VariantMixin):
    
    924
    +        item.set_action_and_target_value(action, value.to_variant())
    
    925
    +    else:
    
    926
    +        item.set_action_and_target_value(action, value)
    
    927
    +    return item
    
    928
    +
    
    929
    +
    
    930
    +def make_menu(menuitems: list[tuple[str, str, MenuValueT]]) -> Gio.Menu:
    
    931
    +    menu = Gio.Menu()
    
    932
    +    for item in menuitems:
    
    933
    +        menuitem = make_menu_item(*item)
    
    934
    +        menu.append_item(menuitem)
    
    935
    +    return menu

  • gajim/gtk/workspace_side_bar.py
    ... ... @@ -25,6 +25,7 @@
    25 25
     from gi.repository import Gio
    
    26 26
     from gi.repository import GLib
    
    27 27
     from gi.repository import Gtk
    
    28
    +from nbxmpp.protocol import JID
    
    28 29
     
    
    29 30
     from gajim.common import app
    
    30 31
     from gajim.common.const import AvatarSize
    
    ... ... @@ -32,6 +33,7 @@
    32 33
     
    
    33 34
     from .chat_list_stack import ChatListStack
    
    34 35
     from .chat_page import ChatPage
    
    36
    +from .structs import MoveChatToWorkspaceAP
    
    35 37
     from .util import open_window
    
    36 38
     
    
    37 39
     log = logging.getLogger('gajim.gui.workspace_sidebar')
    
    ... ... @@ -148,9 +150,11 @@ def _process_chat_list_drop(self, identifier: str, y_coord: int) -> None:
    148 150
             if workspace_row.workspace_id == 'add':
    
    149 151
                 return
    
    150 152
     
    
    151
    -        app.window.activate_action(
    
    152
    -            'move-chat-to-workspace',
    
    153
    -            GLib.Variant('as', [workspace_row.workspace_id, account, jid]))
    
    153
    +        params = MoveChatToWorkspaceAP(workspace_id=workspace_row.workspace_id,
    
    154
    +                                       account=account,
    
    155
    +                                       jid=JID.from_string(jid))
    
    156
    +        app.window.activate_action('move-chat-to-workspace',
    
    157
    +                                   params.to_variant())
    
    154 158
     
    
    155 159
         def _get_row_before(self, row):
    
    156 160
             return self.get_row_at_index(row.get_index() - 1)
    

  • pyrightconfig.json
    ... ... @@ -38,7 +38,8 @@
    38 38
             "gajim/gtk/conversation/scrolled.py",
    
    39 39
             "gajim/gtk/main_stack.py",
    
    40 40
             "gajim/gtk/notification.py",
    
    41
    -        "gajim/gtk/side_bar_switcher.py",
    
    41
    +        "gajim/gtk/structs.py",
    
    42
    +        "gajim/gtk/sidebar_switcher.py",
    
    42 43
             "gajim/gtk/status_icon.py",
    
    43 44
             "gajim/gtk/status_message_selector.py",
    
    44 45
             "gajim/gtk/status_selector.py",
    

  • scripts/ci/link-gtk.py
    ... ... @@ -21,6 +21,8 @@ def cleanup_dir(target_dir: Path) -> None:
    21 21
         for path in target_dir.iterdir():
    
    22 22
             if path.name in IGNORED_FILES:
    
    23 23
                 continue
    
    24
    +        if path.name in IGNORED_DIRS:
    
    25
    +            continue
    
    24 26
             path.unlink()
    
    25 27
     
    
    26 28