Philipp Hörist pushed to branch sort-chat-list at gajim / gajim

Commits:

9 changed files:

Changes:

  • gajim/common/modules/mam.py
    ... ... @@ -464,12 +464,16 @@ def request_archive_on_muc_join(self, jid: JID):
    464 464
             if threshold == SyncThreshold.NO_SYNC:
    
    465 465
                 return
    
    466 466
     
    
    467
    +        contact = self._get_contact(jid, groupchat=True)
    
    468
    +        contact.notify('mam-sync-started')
    
    469
    +
    
    467 470
             mam_id, start_date = self._get_muc_query_params(jid, threshold)
    
    468 471
     
    
    469 472
             result = yield self._execute_query(jid, mam_id, start_date)
    
    470 473
             if is_error(result):
    
    471 474
                 if result.condition != 'item-not-found':
    
    472 475
                     self._log.warning(result)
    
    476
    +                contact.notify('mam-sync-error', result.get_text())
    
    473 477
                     return
    
    474 478
     
    
    475 479
                 app.storage.archive.reset_archive_infos(result.jid)
    
    ... ... @@ -477,6 +481,7 @@ def request_archive_on_muc_join(self, jid: JID):
    477 481
                 result = yield self._execute_query(result.jid, None, start_date)
    
    478 482
                 if is_error(result):
    
    479 483
                     self._log.warning(result)
    
    484
    +                contact.notify('mam-sync-error', result.get_text())
    
    480 485
                     return
    
    481 486
     
    
    482 487
             if result.rsm.last is not None:
    
    ... ... @@ -488,6 +493,8 @@ def request_archive_on_muc_join(self, jid: JID):
    488 493
                     last_mam_id=result.rsm.last,
    
    489 494
                     last_muc_timestamp=time.time())
    
    490 495
     
    
    496
    +        contact.notify('mam-sync-finished')
    
    497
    +
    
    491 498
         @as_task
    
    492 499
         def _execute_query(self,
    
    493 500
                            jid: JID,
    

  • gajim/data/gui/advanced_configuration.ui
    ... ... @@ -96,7 +96,7 @@
    96 96
               <object class="GtkLabel" id="description">
    
    97 97
                 <property name="height_request">40</property>
    
    98 98
                 <property name="visible">True</property>
    
    99
    -            <property name="can_focus">False</property>
    
    99
    +            <property name="selectable">True</property>
    
    100 100
                 <property name="wrap">True</property>
    
    101 101
                 <property name="max_width_chars">60</property>
    
    102 102
                 <property name="xalign">0</property>
    

  • gajim/data/gui/groupchat_details.ui
    ... ... @@ -55,9 +55,10 @@
    55 55
                     <child>
    
    56 56
                       <object class="GtkToggleButton" id="edit_name_button">
    
    57 57
                         <property name="visible">True</property>
    
    58
    +                    <property name="sensitive">False</property>
    
    58 59
                         <property name="can-focus">True</property>
    
    59 60
                         <property name="receives-default">True</property>
    
    60
    -                    <property name="tooltip-text" translatable="yes">Edit Name…</property>
    
    61
    +                    <property name="tooltip-text" translatable="yes">Not connected</property>
    
    61 62
                         <property name="valign">center</property>
    
    62 63
                         <signal name="toggled" handler="_on_edit_name_toggled" swapped="no"/>
    
    63 64
                         <child>
    

  • gajim/gtk/advanced_config.py
    ... ... @@ -201,7 +201,10 @@ def _on_config_edited(self,
    201 201
     
    
    202 202
             value = text
    
    203 203
             if modelrow[Column.TYPE] == SETTING_TYPES[int]:
    
    204
    -            value = int(text)
    
    204
    +            try:
    
    205
    +                value = int(text)
    
    206
    +            except ValueError:
    
    207
    +                return
    
    205 208
     
    
    206 209
             app.settings.set(setting, value)
    
    207 210
             modelrow[Column.VALUE] = text
    

  • gajim/gtk/chat_list.py
    ... ... @@ -71,7 +71,9 @@ def __init__(self, workspace_id: str) -> None:
    71 71
             self.set_sort_func(self._sort_func)
    
    72 72
             self._set_placeholder()
    
    73 73
     
    
    74
    -        self._mouseover: bool = False
    
    74
    +        self._rows_need_sort = False
    
    75
    +        self._context_menu_visible = False
    
    76
    +        self._mouseover = False
    
    75 77
             self._pinned_order_change = False
    
    76 78
             self.connect('enter-notify-event', self._on_mouse_focus_changed)
    
    77 79
             self.connect('leave-notify-event', self._on_mouse_focus_changed)
    
    ... ... @@ -206,6 +208,8 @@ def add_chat(self,
    206 208
     
    
    207 209
             row.connect('drag-begin', self._on_row_drag_begin)
    
    208 210
             row.connect('unread-changed', self._on_row_unread_changed)
    
    211
    +        row.connect('context-menu-state-changed',
    
    212
    +                    self._on_context_menu_state_changed)
    
    209 213
     
    
    210 214
             self.add(row)
    
    211 215
     
    
    ... ... @@ -371,6 +375,14 @@ def _on_row_drag_begin(self,
    371 375
         def _on_row_unread_changed(self, row: ChatListRow) -> None:
    
    372 376
             self._emit_unread_changed()
    
    373 377
     
    
    378
    +    def _on_context_menu_state_changed(self,
    
    379
    +                                       row: ChatListRow,
    
    380
    +                                       menu_is_visible: bool
    
    381
    +                                       ) -> None:
    
    382
    +
    
    383
    +        self._context_menu_visible = menu_is_visible
    
    384
    +        self._schedule_check_sort_inhibit()
    
    385
    +
    
    374 386
         def _on_drag_data_received(self,
    
    375 387
                                    _widget: Gtk.Widget,
    
    376 388
                                    _drag_context: Gdk.DragContext,
    
    ... ... @@ -478,8 +490,9 @@ def _header_func(row: ChatListRow, before: ChatListRow | None) -> None:
    478 490
                         row.set_header_type(None)
    
    479 491
     
    
    480 492
         def _sort_func(self, row1: ChatListRow, row2: ChatListRow) -> int:
    
    481
    -        if self._mouseover and not self._pinned_order_change:
    
    482
    -            log.debug('Mouseover active, don’t sort rows')
    
    493
    +        if self._is_sort_inhibited():
    
    494
    +            self._rows_need_sort = True
    
    495
    +            log.debug('Sort inhibited')
    
    483 496
                 return 0
    
    484 497
     
    
    485 498
             # Sort pinned rows according to stored order
    
    ... ... @@ -497,6 +510,33 @@ def _sort_func(self, row1: ChatListRow, row2: ChatListRow) -> int:
    497 510
             # Sort by timestamp
    
    498 511
             return -1 if row1.timestamp > row2.timestamp else 1
    
    499 512
     
    
    513
    +    def invalidate_sort(self) -> None:
    
    514
    +        if self._is_sort_inhibited():
    
    515
    +            return
    
    516
    +
    
    517
    +        self._rows_need_sort = False
    
    518
    +        log.debug('Sort Chatlist')
    
    519
    +        Gtk.ListBox.invalidate_sort(self)
    
    520
    +
    
    521
    +    def _is_sort_inhibited(self) -> bool:
    
    522
    +        if self._pinned_order_change:
    
    523
    +            return False
    
    524
    +        return self._mouseover or self._context_menu_visible
    
    525
    +
    
    526
    +    def _schedule_check_sort_inhibit(self) -> None:
    
    527
    +        if self._is_sort_inhibited():
    
    528
    +            return
    
    529
    +        GLib.timeout_add(100, self._check_sort_inhibit)
    
    530
    +
    
    531
    +    def _check_sort_inhibit(self) -> None:
    
    532
    +        if self._is_sort_inhibited():
    
    533
    +            return
    
    534
    +
    
    535
    +        if not self._rows_need_sort:
    
    536
    +            return
    
    537
    +
    
    538
    +        self.invalidate_sort()
    
    539
    +
    
    500 540
         def _on_mouse_focus_changed(self,
    
    501 541
                                     _widget: Gtk.ListBox,
    
    502 542
                                     event: Gdk.EventCrossing
    
    ... ... @@ -510,6 +550,8 @@ def _on_mouse_focus_changed(self,
    510 550
                     # Not hovering a Gtk.ListBoxRow (row is INFERIOR)
    
    511 551
                     self._mouseover = False
    
    512 552
     
    
    553
    +        self._schedule_check_sort_inhibit()
    
    554
    +
    
    513 555
         @staticmethod
    
    514 556
         def _on_start_chat_clicked(_button: Gtk.Button) -> None:
    
    515 557
             app.app.activate_action('start-chat', GLib.Variant('as', ['', '']))
    

  • gajim/gtk/chat_list_row.py
    ... ... @@ -63,6 +63,10 @@ class ChatListRow(Gtk.ListBoxRow):
    63 63
                 GObject.SignalFlags.RUN_LAST,
    
    64 64
                 None,
    
    65 65
                 ()),
    
    66
    +        'context-menu-state-changed': (
    
    67
    +            GObject.SignalFlags.RUN_LAST,
    
    68
    +            None,
    
    69
    +            (bool,)),
    
    66 70
         }
    
    67 71
     
    
    68 72
         def __init__(self,
    
    ... ... @@ -437,14 +441,14 @@ def _on_row_button_press_event(self,
    437 441
                                        ) -> None:
    
    438 442
     
    
    439 443
             if event.button == Gdk.BUTTON_SECONDARY:
    
    440
    -            self._popup_menu(event)
    
    444
    +            self._raise_context_popover(event)
    
    441 445
     
    
    442 446
             elif event.button == Gdk.BUTTON_MIDDLE:
    
    443 447
                 app.window.activate_action(
    
    444 448
                     'remove-chat',
    
    445 449
                     GLib.Variant('as', [self.account, str(self.jid)]))
    
    446 450
     
    
    447
    -    def _popup_menu(self, event: Gdk.EventButton):
    
    451
    +    def _raise_context_popover(self, event: Gdk.EventButton):
    
    448 452
             menu = get_chat_list_row_menu(
    
    449 453
                 self.workspace_id, self.account, self.jid, self._pinned)
    
    450 454
     
    
    ... ... @@ -460,8 +464,13 @@ def _popup_menu(self, event: Gdk.EventButton):
    460 464
     
    
    461 465
             popover = GajimPopover(menu, relative_to=self)
    
    462 466
             popover.set_pointing_to_coord(x=x, y=event.y)
    
    467
    +        popover.connect('closed', self._on_context_popover_closed)
    
    468
    +        self.emit('context-menu-state-changed', True)
    
    463 469
             popover.popup()
    
    464 470
     
    
    471
    +    def _on_context_popover_closed(self, _popover: Gtk.Popover) -> None:
    
    472
    +        self.emit('context-menu-state-changed', False)
    
    473
    +
    
    465 474
         def _on_drag_begin(self,
    
    466 475
                            row: ChatListRow,
    
    467 476
                            drag_context: Gdk.DragContext
    

  • gajim/gtk/chat_stack.py
    ... ... @@ -507,7 +507,6 @@ def _update_base_actions(self, contact: ChatContactT) -> None:
    507 507
                 jingle.get_enabled() or
    
    508 508
                 httpupload.get_enabled())
    
    509 509
     
    
    510
    -        app.window.get_action('show-contact-info').set_enabled(online)
    
    511 510
             app.window.get_action('correct-message').set_enabled(online)
    
    512 511
     
    
    513 512
         def _update_chat_actions(self, contact: BareContact) -> None:
    

  • gajim/gtk/const.py
    ... ... @@ -232,7 +232,7 @@ def __str__(self):
    232 232
         ('add-to-roster', None, True),
    
    233 233
         ('start-voice-call', None, False),
    
    234 234
         ('start-video-call', None, False),
    
    235
    -    ('show-contact-info', None, False),
    
    235
    +    ('show-contact-info', None, True),
    
    236 236
         ('send-message', None, False),
    
    237 237
         ('muc-change-nickname', None, False),
    
    238 238
         ('muc-invite', None, False),
    

  • gajim/gtk/groupchat_details.py
    ... ... @@ -22,7 +22,9 @@
    22 22
     
    
    23 23
     from gajim.common import app
    
    24 24
     from gajim.common import ged
    
    25
    +from gajim.common import types
    
    25 26
     from gajim.common.const import AvatarSize
    
    27
    +from gajim.common.const import SimpleClientState
    
    26 28
     from gajim.common.events import MucDiscoUpdate
    
    27 29
     from gajim.common.i18n import _
    
    28 30
     from gajim.common.modules.contacts import GroupchatContact
    
    ... ... @@ -55,6 +57,9 @@ def __init__(self,
    55 57
     
    
    56 58
             self.account = contact.account
    
    57 59
             self._client = app.get_client(contact.account)
    
    60
    +        self._client.connect_signal(
    
    61
    +            'state-changed', self._on_client_state_changed)
    
    62
    +
    
    58 63
             self._contact = contact
    
    59 64
             self._contact.connect('avatar-update', self._on_avatar_update)
    
    60 65
     
    
    ... ... @@ -62,7 +67,7 @@ def __init__(self,
    62 67
             self._ui.connect_signals(self)
    
    63 68
     
    
    64 69
             self._switcher = SideBarSwitcher(width=250)
    
    65
    -        self._switcher.set_stack(self._ui.main_stack)
    
    70
    +        self._switcher.set_stack(self._ui.main_stack, rows_visible=False)
    
    66 71
             self._ui.main_grid.attach(self._switcher, 0, 0, 1, 1)
    
    67 72
             self._ui.main_stack.connect('notify::visible-child-name',
    
    68 73
                                         self._on_stack_child_changed)
    
    ... ... @@ -73,10 +78,14 @@ def __init__(self,
    73 78
             self._add_groupchat_info()
    
    74 79
             self._add_groupchat_settings()
    
    75 80
             self._add_groupchat_encryption()
    
    76
    -        self._add_groupchat_manage()
    
    77
    -        self._add_affiliations()
    
    78
    -        self._add_outcasts()
    
    79
    -        self._add_configuration()
    
    81
    +
    
    82
    +        if self._client.state.is_available:
    
    83
    +            self._ui.edit_name_button.set_sensitive(True)
    
    84
    +            self._ui.edit_name_button.set_tooltip_text(_('Edit Name…'))
    
    85
    +            self._add_groupchat_manage()
    
    86
    +            self._add_affiliations()
    
    87
    +            self._add_outcasts()
    
    88
    +            self._add_configuration()
    
    80 89
     
    
    81 90
             self._load_avatar()
    
    82 91
             self._ui.name_entry.set_text(contact.name)
    
    ... ... @@ -92,6 +101,16 @@ def __init__(self,
    92 101
     
    
    93 102
             self.show_all()
    
    94 103
     
    
    104
    +    def _on_client_state_changed(self,
    
    105
    +                                 _client: types.Client,
    
    106
    +                                 _signal_name: str,
    
    107
    +                                 state: SimpleClientState
    
    108
    +                                 ) -> None:
    
    109
    +
    
    110
    +        self._ui.edit_name_button.set_sensitive(state.is_connected)
    
    111
    +        self._ui.edit_name_button.set_tooltip_text(
    
    112
    +            _('Not connected') if not state.is_connected else _('Edit Name…'))
    
    113
    +
    
    95 114
         def _on_muc_disco_update(self, event: MucDiscoUpdate) -> None:
    
    96 115
             if event.jid != self._contact.jid:
    
    97 116
                 return
    
    ... ... @@ -138,6 +157,7 @@ def _add_groupchat_manage(self) -> None:
    138 157
             self._groupchat_manage = GroupchatManage(self.account,
    
    139 158
                                                      self._contact)
    
    140 159
             self._ui.manage_box.add(self._groupchat_manage)
    
    160
    +        self._switcher.set_row_visible('manage', True)
    
    141 161
     
    
    142 162
         def _add_groupchat_info(self) -> None:
    
    143 163
             self._groupchat_info = GroupChatInfoScrolled(
    
    ... ... @@ -148,6 +168,7 @@ def _add_groupchat_info(self) -> None:
    148 168
             self._groupchat_info.set_from_disco_info(disco_info)
    
    149 169
             self._groupchat_info.set_subject(self._contact.subject)
    
    150 170
             self._ui.info_box.add(self._groupchat_info)
    
    171
    +        self._switcher.set_row_visible('information', True)
    
    151 172
     
    
    152 173
         def _add_groupchat_settings(self) -> None:
    
    153 174
             main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=24)
    
    ... ... @@ -174,6 +195,7 @@ def _add_groupchat_settings(self) -> None:
    174 195
             scrolled_window.add(main_box)
    
    175 196
     
    
    176 197
             self._ui.settings_box.add(scrolled_window)
    
    198
    +        self._switcher.set_row_visible('settings', True)
    
    177 199
     
    
    178 200
         def _add_groupchat_encryption(self) -> None:
    
    179 201
             if (self._contact.is_groupchat and
    
    ... ... @@ -184,18 +206,22 @@ def _add_groupchat_encryption(self) -> None:
    184 206
     
    
    185 207
             self._ui.encryption_box.add(
    
    186 208
                 OMEMOTrustManager(self._contact.account, self._contact))
    
    209
    +        self._switcher.set_row_visible('encryption-omemo', True)
    
    187 210
     
    
    188 211
         def _add_affiliations(self) -> None:
    
    189 212
             affiliations = GroupchatAffiliation(self._client, self._contact)
    
    190 213
             self._ui.affiliation_box.add(affiliations)
    
    214
    +        self._switcher.set_row_visible('affiliations', True)
    
    191 215
     
    
    192 216
         def _add_outcasts(self) -> None:
    
    193 217
             affiliations = GroupchatOutcasts(self._client, self._contact)
    
    194 218
             self._ui.outcasts_box.add(affiliations)
    
    219
    +        self._switcher.set_row_visible('outcasts', True)
    
    195 220
     
    
    196 221
         def _add_configuration(self) -> None:
    
    197 222
             config = GroupchatConfig(self._client, self._contact)
    
    198 223
             self._ui.configuration_box.add(config)
    
    224
    +        self._switcher.set_row_visible('config', True)
    
    199 225
     
    
    200 226
         def _on_key_press(self,
    
    201 227
                           _widget: GroupchatDetails,