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

Commits:

11 changed files:

Changes:

  • gajim/common/modules/contacts.py
    ... ... @@ -27,6 +27,8 @@
    27 27
     from nbxmpp.const import Affiliation
    
    28 28
     from nbxmpp.const import Role
    
    29 29
     from nbxmpp.protocol import JID
    
    30
    +from nbxmpp.structs import DiscoInfo
    
    31
    +from nbxmpp.structs import MucSubject
    
    30 32
     
    
    31 33
     from gajim.common import app
    
    32 34
     from gajim.common import types
    
    ... ... @@ -551,6 +553,13 @@ def occupant_jid(self):
    551 553
                 return None
    
    552 554
             return muc_data.occupant_jid
    
    553 555
     
    
    556
    +    @property
    
    557
    +    def subject(self) -> Optional[MucSubject]:
    
    558
    +        muc_data = self._module('MUC').get_muc_data(self._jid)
    
    559
    +        if muc_data is None:
    
    560
    +            return None
    
    561
    +        return muc_data.subject
    
    562
    +
    
    554 563
         @property
    
    555 564
         def is_joined(self) -> bool:
    
    556 565
             muc_data = self._module('MUC').get_muc_data(self._jid)
    
    ... ... @@ -576,11 +585,11 @@ def set_not_joined(self) -> None:
    576 585
             for contact in self._resources.values():
    
    577 586
                 contact.update_presence(UNKNOWN_MUC_PRESENCE, notify=False)
    
    578 587
     
    
    579
    -    def get_user_nicknames(self):
    
    588
    +    def get_user_nicknames(self) -> list[str]:
    
    580 589
             client = app.get_client(self._account)
    
    581 590
             return client.get_module('MUC').get_joined_users(self._jid)
    
    582 591
     
    
    583
    -    def get_disco(self, max_age=0):
    
    592
    +    def get_disco(self, max_age: int = 0) -> Optional[DiscoInfo]:
    
    584 593
             return app.storage.cache.get_last_disco_info(self.jid, max_age=max_age)
    
    585 594
     
    
    586 595
         def can_notify(self) -> bool:
    

  • gajim/common/modules/muc.py
    ... ... @@ -17,6 +17,7 @@
    17 17
     
    
    18 18
     import logging
    
    19 19
     from collections import defaultdict
    
    20
    +import time
    
    20 21
     
    
    21 22
     import nbxmpp
    
    22 23
     from nbxmpp.namespaces import Namespace
    
    ... ... @@ -655,9 +656,13 @@ def _on_subject_change(self, _con, _stanza, properties):
    655 656
                 self._log.warning('No MUCData found for %s', room_jid)
    
    656 657
                 return
    
    657 658
     
    
    658
    -        muc_data.subject = properties.subject
    
    659
    +        muc_subject = properties.muc_subject
    
    660
    +        if muc_subject is not None and muc_subject.timestamp is None:
    
    661
    +            muc_subject = muc_subject._replace(timestamp=time.time())
    
    662
    +
    
    663
    +        muc_data.subject = muc_subject
    
    659 664
             room = self._get_contact(room_jid)
    
    660
    -        room.notify('room-subject', properties)
    
    665
    +        room.notify('room-subject', muc_subject)
    
    661 666
     
    
    662 667
             if muc_data.state == MUCJoinedState.JOINING:
    
    663 668
                 self._room_join_complete(muc_data)
    

  • gajim/data/gui/groupchat_control.ui
    ... ... @@ -1334,96 +1334,7 @@
    1334 1334
                   </packing>
    
    1335 1335
                 </child>
    
    1336 1336
                 <child>
    
    1337
    -              <object class="GtkBox">
    
    1338
    -                <property name="visible">True</property>
    
    1339
    -                <property name="can-focus">False</property>
    
    1340
    -                <property name="orientation">vertical</property>
    
    1341
    -                <child>
    
    1342
    -                  <!-- n-columns=1 n-rows=3 -->
    
    1343
    -                  <object class="GtkGrid" id="info_grid">
    
    1344
    -                    <property name="visible">True</property>
    
    1345
    -                    <property name="can-focus">False</property>
    
    1346
    -                    <property name="hexpand">True</property>
    
    1347
    -                    <property name="vexpand">True</property>
    
    1348
    -                    <property name="orientation">vertical</property>
    
    1349
    -                    <property name="row-spacing">12</property>
    
    1350
    -                    <child>
    
    1351
    -                      <object class="GtkBox">
    
    1352
    -                        <property name="visible">True</property>
    
    1353
    -                        <property name="can-focus">False</property>
    
    1354
    -                        <property name="homogeneous">True</property>
    
    1355
    -                        <child>
    
    1356
    -                          <object class="GtkButton" id="info_close_button">
    
    1357
    -                            <property name="label" translatable="yes">_Close</property>
    
    1358
    -                            <property name="visible">True</property>
    
    1359
    -                            <property name="can-focus">True</property>
    
    1360
    -                            <property name="can-default">True</property>
    
    1361
    -                            <property name="receives-default">True</property>
    
    1362
    -                            <property name="halign">center</property>
    
    1363
    -                            <property name="valign">start</property>
    
    1364
    -                            <property name="use-underline">True</property>
    
    1365
    -                            <signal name="clicked" handler="_on_page_cancel_clicked" swapped="no"/>
    
    1366
    -                          </object>
    
    1367
    -                          <packing>
    
    1368
    -                            <property name="expand">False</property>
    
    1369
    -                            <property name="fill">True</property>
    
    1370
    -                            <property name="position">0</property>
    
    1371
    -                          </packing>
    
    1372
    -                        </child>
    
    1373
    -                      </object>
    
    1374
    -                      <packing>
    
    1375
    -                        <property name="left-attach">0</property>
    
    1376
    -                        <property name="top-attach">2</property>
    
    1377
    -                      </packing>
    
    1378
    -                    </child>
    
    1379
    -                    <child>
    
    1380
    -                      <object class="GtkLabel">
    
    1381
    -                        <property name="visible">True</property>
    
    1382
    -                        <property name="can-focus">False</property>
    
    1383
    -                        <property name="label" translatable="yes">Information</property>
    
    1384
    -                        <style>
    
    1385
    -                          <class name="bold16"/>
    
    1386
    -                        </style>
    
    1387
    -                      </object>
    
    1388
    -                      <packing>
    
    1389
    -                        <property name="left-attach">0</property>
    
    1390
    -                        <property name="top-attach">0</property>
    
    1391
    -                      </packing>
    
    1392
    -                    </child>
    
    1393
    -                    <child>
    
    1394
    -                      <object class="GtkBox" id="info_box">
    
    1395
    -                        <property name="visible">True</property>
    
    1396
    -                        <property name="can-focus">False</property>
    
    1397
    -                        <property name="hexpand">True</property>
    
    1398
    -                        <property name="vexpand">True</property>
    
    1399
    -                        <property name="orientation">vertical</property>
    
    1400
    -                        <child>
    
    1401
    -                          <placeholder/>
    
    1402
    -                        </child>
    
    1403
    -                        <style>
    
    1404
    -                          <class name="margin-18"/>
    
    1405
    -                        </style>
    
    1406
    -                      </object>
    
    1407
    -                      <packing>
    
    1408
    -                        <property name="left-attach">0</property>
    
    1409
    -                        <property name="top-attach">1</property>
    
    1410
    -                      </packing>
    
    1411
    -                    </child>
    
    1412
    -                    <style>
    
    1413
    -                      <class name="margin-18"/>
    
    1414
    -                    </style>
    
    1415
    -                  </object>
    
    1416
    -                  <packing>
    
    1417
    -                    <property name="expand">False</property>
    
    1418
    -                    <property name="fill">True</property>
    
    1419
    -                    <property name="position">0</property>
    
    1420
    -                  </packing>
    
    1421
    -                </child>
    
    1422
    -              </object>
    
    1423
    -              <packing>
    
    1424
    -                <property name="name">muc-info</property>
    
    1425
    -                <property name="position">7</property>
    
    1426
    -              </packing>
    
    1337
    +              <placeholder/>
    
    1427 1338
                 </child>
    
    1428 1339
                 <child>
    
    1429 1340
                   <object class="GtkBox">
    

  • gajim/gtk/const.py
    ... ... @@ -145,6 +145,7 @@ def __str__(self):
    145 145
         'CreateGroupchatWindow': 'gajim.gui.groupchat_creation',
    
    146 146
         'Features': 'gajim.gui.features',
    
    147 147
         'GroupchatConfig': 'gajim.gui.groupchat_config',
    
    148
    +    'GroupchatDetails': 'gajim.gui.groupchat_details',
    
    148 149
         'GroupChatInvitation': 'gajim.gui.groupchat_invitation',
    
    149 150
         'GroupchatJoin': 'gajim.gui.groupchat_join',
    
    150 151
         'HistoryExport': 'gajim.gui.history_export',
    

  • gajim/gtk/controls/groupchat.py
    ... ... @@ -27,7 +27,6 @@
    27 27
     from typing import Any
    
    28 28
     from typing import Optional
    
    29 29
     
    
    30
    -import time
    
    31 30
     import logging
    
    32 31
     
    
    33 32
     from nbxmpp import JID
    
    ... ... @@ -41,6 +40,7 @@
    41 40
     from nbxmpp.modules.vcard_temp import VCard
    
    42 41
     from nbxmpp.structs import PresenceProperties
    
    43 42
     from nbxmpp.structs import MessageProperties
    
    43
    +from nbxmpp.structs import MucSubject
    
    44 44
     from nbxmpp.task import Task
    
    45 45
     
    
    46 46
     from gi.repository import Gtk
    
    ... ... @@ -77,7 +77,6 @@
    77 77
     from gajim.gui.groupchat_config import GroupchatConfig
    
    78 78
     from gajim.gui.avatar_selector import AvatarSelector
    
    79 79
     from gajim.gui.dataform import DataFormWidget
    
    80
    -from gajim.gui.groupchat_info import GroupChatInfoScrolled
    
    81 80
     from gajim.gui.groupchat_inviter import GroupChatInviter
    
    82 81
     from gajim.gui.groupchat_settings import GroupChatSettings
    
    83 82
     from gajim.gui.groupchat_roster import GroupchatRoster
    
    ... ... @@ -171,10 +170,7 @@ def __init__(self, account: str, jid: JID) -> None:
    171 170
             # Holds CaptchaRequest widget
    
    172 171
             self._captcha_request: Optional[DataFormWidget] = None
    
    173 172
     
    
    174
    -        # MUC Info
    
    175
    -        self._subject_data = None
    
    176
    -        self._muc_info_box = GroupChatInfoScrolled(self.account)
    
    177
    -        self.xml.info_box.add(self._muc_info_box)
    
    173
    +        self._subject_text = ''
    
    178 174
     
    
    179 175
             # Groupchat settings
    
    180 176
             self._groupchat_settings_box: Optional[GroupChatSettings] = None
    
    ... ... @@ -286,12 +282,6 @@ def _nick_completion(self) -> NickCompletionGenerator:
    286 282
                     self.contact.nickname)
    
    287 283
             return self.__nick_completion
    
    288 284
     
    
    289
    -    @property
    
    290
    -    def subject(self) -> str:
    
    291
    -        if self._subject_data is None:
    
    292
    -            return ''
    
    293
    -        return self._subject_data.subject
    
    294
    -
    
    295 285
         @property
    
    296 286
         def disco_info(self):
    
    297 287
             return app.storage.cache.get_last_disco_info(self.contact.jid)
    
    ... ... @@ -306,7 +296,7 @@ def add_actions(self) -> None:
    306 296
                 ('destroy-', None, self._on_destroy_room),
    
    307 297
                 ('configure-', None, self._on_configure_room),
    
    308 298
                 ('request-voice-', None, self._on_request_voice),
    
    309
    -            ('information-', None, self._on_information),
    
    299
    +            ('groupchat-details-', None, self._on_details),
    
    310 300
                 ('invite-', None, self._on_invite),
    
    311 301
                 ('contact-information-', 's', self._on_contact_information),
    
    312 302
                 ('execute-command-', 's', self._on_execute_command),
    
    ... ... @@ -406,7 +396,7 @@ def remove_actions(self) -> None:
    406 396
                 'destroy-',
    
    407 397
                 'configure-',
    
    408 398
                 'request-voice-',
    
    409
    -            'information-',
    
    399
    +            'groupchat-details-',
    
    410 400
                 'invite-',
    
    411 401
                 'contact-information-',
    
    412 402
                 'execute-command-',
    
    ... ... @@ -441,11 +431,6 @@ def _show_page(self, name: str) -> None:
    441 431
             if name == 'groupchat':
    
    442 432
                 transition = Gtk.StackTransitionType.SLIDE_UP
    
    443 433
                 self.msg_textview.grab_focus()
    
    444
    -        if name == 'muc-info':
    
    445
    -            # Set focus on the close button, otherwise one of
    
    446
    -            # the selectable labels of the GroupchatInfo box gets focus,
    
    447
    -            # which means it is fully selected
    
    448
    -            self.xml.info_close_button.grab_focus()
    
    449 434
             self.xml.stack.set_visible_child_full(name, transition)
    
    450 435
     
    
    451 436
         def _get_current_page(self) -> str:
    
    ... ... @@ -456,16 +441,11 @@ def _on_muc_disco_update(self, _event: events.MucDiscoUpdate) -> None:
    456 441
             self.draw_banner_text()
    
    457 442
     
    
    458 443
         # Actions
    
    459
    -    def _on_information(self,
    
    460
    -                        _action: Gio.SimpleAction,
    
    461
    -                        _param: Optional[GLib.Variant]
    
    462
    -                        ) -> None:
    
    463
    -        self._muc_info_box.set_from_disco_info(self.disco_info)
    
    464
    -        if self._subject_data is not None:
    
    465
    -            self._muc_info_box.set_subject(self._subject_data.subject)
    
    466
    -            self._muc_info_box.set_author(self._subject_data.muc_nickname,
    
    467
    -                                          self._subject_data.user_timestamp)
    
    468
    -        self._show_page('muc-info')
    
    444
    +    def _on_details(self,
    
    445
    +                    _action: Gio.SimpleAction,
    
    446
    +                    _param: Optional[GLib.Variant]
    
    447
    +                    ) -> None:
    
    448
    +        open_window('GroupchatDetails', contact=self.contact)
    
    469 449
     
    
    470 450
         def _on_groupchat_settings(self,
    
    471 451
                                    _action: Gio.SimpleAction,
    
    ... ... @@ -872,23 +852,21 @@ def add_message(self,
    872 852
         def _on_room_subject(self,
    
    873 853
                              _contact: GroupchatContact,
    
    874 854
                              _signal_name: str,
    
    875
    -                         properties: MessageProperties
    
    855
    +                         subject: Optional[MucSubject]
    
    876 856
                              ) -> None:
    
    877
    -        if self.subject == properties.subject:
    
    878
    -            # Probably a rejoin, we already showed that subject
    
    857
    +
    
    858
    +        if subject is None:
    
    879 859
                 return
    
    880 860
     
    
    881
    -        self._subject_data = properties
    
    861
    +        if self._subject_text == subject.text:
    
    862
    +            # Probably a rejoin, we already showed that subject
    
    863
    +            return
    
    882 864
     
    
    883
    -        date = ''
    
    884
    -        if properties.user_timestamp:
    
    885
    -            date = time.strftime('%c',
    
    886
    -                                 time.localtime(properties.user_timestamp))
    
    865
    +        self._subject_text = subject.text
    
    887 866
     
    
    888 867
             if (app.settings.get('show_subject_on_join') or
    
    889 868
                     not self.contact.is_joining):
    
    890
    -            self.conversation_view.add_muc_subject(
    
    891
    -                properties.subject, properties.muc_nickname, date)
    
    869
    +            self.conversation_view.add_muc_subject(subject)
    
    892 870
     
    
    893 871
         def _on_room_config_changed(self,
    
    894 872
                                     _contact: GroupchatContact,
    
    ... ... @@ -1594,8 +1572,6 @@ def delegate_action(self, action: str) -> int:
    1594 1572
                     self._on_password_cancel_clicked()
    
    1595 1573
                 elif self._get_current_page() == 'captcha':
    
    1596 1574
                     self._on_captcha_cancel_clicked()
    
    1597
    -            elif self._get_current_page() == 'muc-info':
    
    1598
    -                self._on_page_cancel_clicked()
    
    1599 1575
                 elif self._get_current_page() in ('error', 'captcha-error'):
    
    1600 1576
                     self._on_page_close_clicked()
    
    1601 1577
                 else:
    
    ... ... @@ -1609,7 +1585,7 @@ def delegate_action(self, action: str) -> int:
    1609 1585
     
    
    1610 1586
             if action == 'show-contact-info':
    
    1611 1587
                 app.window.lookup_action(
    
    1612
    -                f'information-{self.control_id}').activate()
    
    1588
    +                f'groupchat-details-{self.control_id}').activate()
    
    1613 1589
                 return Gdk.EVENT_STOP
    
    1614 1590
     
    
    1615 1591
             return Gdk.EVENT_PROPAGATE
    
    ... ... @@ -1650,8 +1626,6 @@ def _on_page_change(self, stack: Gtk.Stack, _param: Any) -> None:
    1650 1626
             page_name = stack.get_visible_child_name()
    
    1651 1627
             if page_name == 'groupchat':
    
    1652 1628
                 pass
    
    1653
    -        elif page_name == 'muc-info':
    
    1654
    -            self.xml.info_close_button.grab_default()
    
    1655 1629
             elif page_name == 'password':
    
    1656 1630
                 self.xml.password_entry.set_text('')
    
    1657 1631
                 self.xml.password_entry.grab_focus()
    
    ... ... @@ -1730,7 +1704,7 @@ def _on_manage_save_clicked(self, _button: Gtk.Button) -> None:
    1730 1704
         def _on_change_subject(self, _button: Gtk.Button) -> None:
    
    1731 1705
             if self._get_current_page() not in ('groupchat', 'muc-manage'):
    
    1732 1706
                 return
    
    1733
    -        self.xml.subject_textview.get_buffer().set_text(self.subject)
    
    1707
    +        self.xml.subject_textview.get_buffer().set_text(self._subject_text)
    
    1734 1708
             self.xml.subject_textview.grab_focus()
    
    1735 1709
             self._show_page('subject')
    
    1736 1710
     
    

  • gajim/gtk/conversation/rows/muc_subject.py
    ... ... @@ -16,6 +16,7 @@
    16 16
     from datetime import datetime
    
    17 17
     
    
    18 18
     from gi.repository import Gtk
    
    19
    +from nbxmpp.structs import MucSubject
    
    19 20
     
    
    20 21
     from gajim.common.const import AvatarSize
    
    21 22
     from gajim.common.i18n import _
    
    ... ... @@ -28,7 +29,7 @@ class MUCSubject(BaseRow):
    28 29
     
    
    29 30
         type = 'muc-subject'
    
    30 31
     
    
    31
    -    def __init__(self, account: str, text: str, nick: str, date: str) -> None:
    
    32
    +    def __init__(self, account: str, subject: MucSubject) -> None:
    
    32 33
             BaseRow.__init__(self, account)
    
    33 34
     
    
    34 35
             timestamp = time.time()
    
    ... ... @@ -48,16 +49,21 @@ def __init__(self, account: str, text: str, nick: str, date: str) -> None:
    48 49
             title.get_style_context().add_class('bold')
    
    49 50
             subject_box.add(title)
    
    50 51
     
    
    51
    -        meta_str = _('Changed by %s') % nick
    
    52
    -        if date is not None:
    
    53
    -            meta_str = f'{meta_str} ({date})'
    
    52
    +        author = _('Changed by %s') % (subject.author or _('Unknown'))
    
    53
    +
    
    54
    +        date = ''
    
    55
    +        if subject.timestamp is not None:
    
    56
    +            time_str = time.strftime("%c", time.localtime(subject.timestamp))
    
    57
    +            date = f' ({time_str})'
    
    58
    +
    
    59
    +        meta_str = f'{author}{date}'
    
    54 60
             meta = Gtk.Label(label=meta_str)
    
    55 61
             meta.set_halign(Gtk.Align.START)
    
    56 62
             meta.get_style_context().add_class('small-label')
    
    57 63
             subject_box.add(meta)
    
    58 64
     
    
    59 65
             message_widget = MessageWidget(account)
    
    60
    -        message_widget.add_with_styling(text)
    
    66
    +        message_widget.add_with_styling(subject.text)
    
    61 67
             subject_box.add(message_widget)
    
    62 68
             self.grid.attach(subject_box, 1, 0, 1, 1)
    
    63 69
     
    

  • gajim/gtk/conversation/view.py
    ... ... @@ -32,6 +32,7 @@
    32 32
     
    
    33 33
     from nbxmpp.errors import StanzaError
    
    34 34
     from nbxmpp.modules.security_labels import Displaymarking
    
    35
    +from nbxmpp.structs import MucSubject
    
    35 36
     
    
    36 37
     from gajim.common import app
    
    37 38
     from gajim.common.client import Client
    
    ... ... @@ -155,7 +156,6 @@ def clear(self) -> None:
    155 156
             for row in self.get_children()[2:]:
    
    156 157
                 if isinstance(row, ReadMarkerRow):
    
    157 158
                     continue
    
    158
    -            self.remove(row)
    
    159 159
                 row.destroy()
    
    160 160
     
    
    161 161
             self._reset_conversation_view()
    
    ... ... @@ -199,9 +199,9 @@ def _filter_func(self, row: BaseRow) -> bool:
    199 199
     
    
    200 200
             return True
    
    201 201
     
    
    202
    -    def add_muc_subject(self, text: str, nick: str, date: str) -> None:
    
    203
    -        subject = MUCSubject(self._account, text, nick, date)
    
    204
    -        self._insert_message(subject)
    
    202
    +    def add_muc_subject(self, subject: MucSubject) -> None:
    
    203
    +        muc_subject = MUCSubject(self._account, subject)
    
    204
    +        self._insert_message(muc_subject)
    
    205 205
     
    
    206 206
         def add_muc_user_left(self,
    
    207 207
                               nick: str,
    
    ... ... @@ -418,25 +418,25 @@ def _reduce_messages_before(self) -> bool:
    418 418
             if row1.type == row2.type == 'date':
    
    419 419
                 # First two rows are date rows,
    
    420 420
                 # it’s safe to remove the fist row
    
    421
    -            self.remove(row1)
    
    421
    +            row1.destroy()
    
    422 422
                 success = True
    
    423 423
     
    
    424 424
             if row1.type == 'date' and row2.type != 'date':
    
    425 425
                 # First one is a date row, keep it and
    
    426 426
                 # remove the second row instead
    
    427
    -            self.remove(row2)
    
    427
    +            row2.destroy()
    
    428 428
                 success = True
    
    429 429
     
    
    430 430
             if row1.type != 'date':
    
    431 431
                 # Not a date row, safe to remove
    
    432
    -            self.remove(row1)
    
    432
    +            row1.destroy()
    
    433 433
                 success = True
    
    434 434
     
    
    435 435
             return success
    
    436 436
     
    
    437 437
         def _reduce_messages_after(self) -> None:
    
    438 438
             row = self.get_row_at_index(len(self.get_children()) - 1)
    
    439
    -        self.remove(row)
    
    439
    +        row.destroy()
    
    440 440
     
    
    441 441
         def scroll_to_message_and_highlight(self, log_line_id: str) -> None:
    
    442 442
             highlight_row = None
    

  • gajim/gtk/groupchat_details.py
    1
    +# This file is part of Gajim.
    
    2
    +#
    
    3
    +# Gajim is free software; you can redistribute it and/or modify
    
    4
    +# it under the terms of the GNU General Public License as published
    
    5
    +# by the Free Software Foundation; version 3 only.
    
    6
    +#
    
    7
    +# Gajim is distributed in the hope that it will be useful,
    
    8
    +# but WITHOUT ANY WARRANTY; without even the implied warranty of
    
    9
    +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    
    10
    +# GNU General Public License for more details.
    
    11
    +#
    
    12
    +# You should have received a copy of the GNU General Public License
    
    13
    +# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    14
    +
    
    15
    +from __future__ import annotations
    
    16
    +
    
    17
    +from gi.repository import Gdk
    
    18
    +from gi.repository import Gtk
    
    19
    +
    
    20
    +from gajim.common import app
    
    21
    +from gajim.common.i18n import _
    
    22
    +from gajim.common.modules.contacts import GroupchatContact
    
    23
    +
    
    24
    +from .groupchat_info import GroupChatInfoScrolled
    
    25
    +from .sidebar_switcher import SideBarSwitcher
    
    26
    +
    
    27
    +
    
    28
    +class GroupchatDetails(Gtk.ApplicationWindow):
    
    29
    +    def __init__(self, contact: GroupchatContact) -> None:
    
    30
    +        Gtk.ApplicationWindow.__init__(self)
    
    31
    +        self.set_application(app.app)
    
    32
    +        self.set_position(Gtk.WindowPosition.CENTER)
    
    33
    +        self.set_show_menubar(False)
    
    34
    +        self.set_type_hint(Gdk.WindowTypeHint.DIALOG)
    
    35
    +        self.set_resizable(True)
    
    36
    +        self.set_default_size(-1, 600)
    
    37
    +        self.set_title(_('Groupchat Details'))
    
    38
    +
    
    39
    +        self.account = contact.account
    
    40
    +        self._contact = contact
    
    41
    +
    
    42
    +        main_box = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL)
    
    43
    +        self._stack = Gtk.Stack()
    
    44
    +        self._side_bar_switcher = SideBarSwitcher()
    
    45
    +
    
    46
    +        main_box.add(self._side_bar_switcher)
    
    47
    +        main_box.add(self._stack)
    
    48
    +
    
    49
    +        self._add_groupchat_info()
    
    50
    +
    
    51
    +        self._side_bar_switcher.set_stack(self._stack)
    
    52
    +
    
    53
    +        self.add(main_box)
    
    54
    +
    
    55
    +        self.connect('key-press-event', self._on_key_press)
    
    56
    +        self.connect('destroy', self._on_destroy)
    
    57
    +
    
    58
    +        self.show_all()
    
    59
    +
    
    60
    +    def _add_groupchat_info(self) -> None:
    
    61
    +        groupchat_info = GroupChatInfoScrolled(self._contact.account, width=600)
    
    62
    +        groupchat_info.set_halign(Gtk.Align.FILL)
    
    63
    +        disco_info = self._contact.get_disco()
    
    64
    +        assert disco_info is not None
    
    65
    +        groupchat_info.set_from_disco_info(disco_info)
    
    66
    +        groupchat_info.set_subject(self._contact.subject)
    
    67
    +
    
    68
    +        self._stack.add_titled(groupchat_info, 'info', _('Information'))
    
    69
    +
    
    70
    +    def _on_key_press(self,
    
    71
    +                      _widget: GroupchatDetails,
    
    72
    +                      event: Gdk.EventKey) -> None:
    
    73
    +        if event.keyval == Gdk.KEY_Escape:
    
    74
    +            self.destroy()
    
    75
    +
    
    76
    +    def _on_destroy(self, _widget: GroupchatDetails) -> None:
    
    77
    +        app.check_finalize(self)

  • gajim/gtk/groupchat_info.py
    ... ... @@ -23,6 +23,7 @@
    23 23
     from nbxmpp import JID
    
    24 24
     from nbxmpp.namespaces import Namespace
    
    25 25
     from nbxmpp.structs import DiscoInfo
    
    26
    +from nbxmpp.structs import MucSubject
    
    26 27
     
    
    27 28
     from gajim.common import app
    
    28 29
     from gajim.common.i18n import _
    
    ... ... @@ -139,22 +140,22 @@ def set_account(self, account: str) -> None:
    139 140
         def get_jid(self) -> Optional[JID]:
    
    140 141
             return self._info.jid
    
    141 142
     
    
    142
    -    def set_author(self,
    
    143
    -                   author: Optional[str],
    
    144
    -                   epoch_timestamp: Optional[float] = None
    
    145
    -                   ) -> None:
    
    143
    +    def set_subject(self, muc_subject: Optional[MucSubject]) -> None:
    
    144
    +        if muc_subject is None:
    
    145
    +            return
    
    146
    +
    
    147
    +        author = muc_subject.author
    
    146 148
             has_author = bool(author)
    
    147
    -        if has_author and epoch_timestamp is not None:
    
    148
    -            time_ = time.strftime('%c', time.localtime(epoch_timestamp))
    
    149
    -            author = f'{author} - {time_}'
    
    149
    +        if has_author and muc_subject.timestamp is not None:
    
    150
    +            time_ = time.strftime('%c', time.localtime(muc_subject.timestamp))
    
    151
    +            author = f'{muc_subject.author} - {time_}'
    
    150 152
     
    
    151 153
             self._ui.author.set_text(author or '')
    
    152 154
             self._ui.author.set_visible(has_author)
    
    153 155
             self._ui.author_label.set_visible(has_author)
    
    154 156
     
    
    155
    -    def set_subject(self, subject: str) -> None:
    
    156
    -        has_subject = bool(subject)
    
    157
    -        subject = GLib.markup_escape_text(subject or '')
    
    157
    +        has_subject = bool(muc_subject.text)
    
    158
    +        subject = GLib.markup_escape_text(muc_subject.text)
    
    158 159
             self._ui.subject.set_markup(make_href_markup(subject))
    
    159 160
             self._ui.subject.set_visible(has_subject)
    
    160 161
             self._ui.subject_label.set_visible(has_subject)
    

  • gajim/gtk/menus.py
    ... ... @@ -150,7 +150,7 @@ def get_groupchat_menu(control_id: str, account: str, jid: JID) -> Gio.Menu:
    150 150
         params = RemoveHistoryActionParams(account=account, jid=jid)
    
    151 151
     
    
    152 152
         menulist: MenuItemListT = [
    
    153
    -        (_('Information'), f'win.information-{control_id}', None),
    
    153
    +        (_('Details'), f'win.groupchat-details-{control_id}', None),
    
    154 154
             (_('Settings…'), f'win.groupchat-settings-{control_id}', None),
    
    155 155
             (_('Manage…'), f'win.groupchat-manage-{control_id}', None),
    
    156 156
             (_('Rename Chat…'), f'win.rename-groupchat-{control_id}', None),
    

  • pyrightconfig.json
    ... ... @@ -54,6 +54,7 @@
    54 54
             "gajim/gtk/conversation/view.py",
    
    55 55
             "gajim/gtk/features.py",
    
    56 56
             "gajim/gtk/file_transfer_send.py",
    
    57
    +        "gajim/gtk/groupchat_details.py",
    
    57 58
             "gajim/gtk/groupchat_invitation.py",
    
    58 59
             "gajim/gtk/groupchat_inviter.py",
    
    59 60
             "gajim/gtk/groupchat_nick.py",