Daniel Brötzmann pushed to branch master at gajim / gajim

Commits:

8 changed files:

Changes:

  • gajim/common/storage/archive.py
    ... ... @@ -21,6 +21,10 @@
    21 21
     # You should have received a copy of the GNU General Public License
    
    22 22
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    23 23
     
    
    24
    +from typing import Any
    
    25
    +from typing import List
    
    26
    +from typing import Optional
    
    27
    +
    
    24 28
     import time
    
    25 29
     import datetime
    
    26 30
     import calendar
    
    ... ... @@ -125,7 +129,7 @@ def _namedtuple_factory(self, cursor, row):
    125 129
                     named_row = named_row._replace(account=jid)
    
    126 130
             return named_row
    
    127 131
     
    
    128
    -    def _migrate(self):
    
    132
    +    def _migrate(self) -> None:
    
    129 133
             user_version = self.user_version
    
    130 134
             if user_version == 0:
    
    131 135
                 # All migrations from 0.16.9 until 1.0.0
    
    ... ... @@ -183,7 +187,7 @@ def dispatch(event, error):
    183 187
             app.ged.raise_event(event, None, str(error))
    
    184 188
     
    
    185 189
         @staticmethod
    
    186
    -    def _get_timeout():
    
    190
    +    def _get_timeout() -> int:
    
    187 191
             """
    
    188 192
             returns the timeout in epoch
    
    189 193
             """
    
    ... ... @@ -195,11 +199,11 @@ def _get_timeout():
    195 199
             return timeout
    
    196 200
     
    
    197 201
         @staticmethod
    
    198
    -    def _like(search_str):
    
    199
    -        return '%{}%'.format(search_str)
    
    202
    +    def _like(search_str: str) -> str:
    
    203
    +        return f'%{search_str}%'
    
    200 204
     
    
    201 205
         @timeit
    
    202
    -    def _get_jid_ids_from_db(self):
    
    206
    +    def _get_jid_ids_from_db(self) -> None:
    
    203 207
             """
    
    204 208
             Load all jid/jid_id tuples into a dict for faster access
    
    205 209
             """
    
    ... ... @@ -215,7 +219,7 @@ def get_jid_from_id(self, jid_id):
    215 219
         def get_jids_in_db(self):
    
    216 220
             return self._jid_ids.keys()
    
    217 221
     
    
    218
    -    def jid_is_from_pm(self, jid):
    
    222
    +    def jid_is_from_pm(self, jid: str) -> bool:
    
    219 223
             """
    
    220 224
             If jid is gajim@conf/nkour it's likely a pm one, how we know gajim@conf
    
    221 225
             is not a normal guy and nkour is not his resource?  we ask if gajim@conf
    
    ... ... @@ -230,7 +234,7 @@ def jid_is_from_pm(self, jid):
    230 234
             # it's not a full jid, so it's not a pm one
    
    231 235
             return False
    
    232 236
     
    
    233
    -    def jid_is_room_jid(self, jid):
    
    237
    +    def jid_is_room_jid(self, jid: str) -> bool:
    
    234 238
             """
    
    235 239
             Return True if it's a room jid, False if it's not, None if we don't know
    
    236 240
             """
    
    ... ... @@ -239,18 +243,25 @@ def jid_is_room_jid(self, jid):
    239 243
                 return None
    
    240 244
             return jid_.type == JIDConstant.ROOM_TYPE
    
    241 245
     
    
    242
    -    def get_account_id(self, account, type_=JIDConstant.NORMAL_TYPE):
    
    246
    +    def get_account_id(self,
    
    247
    +                       account: str,
    
    248
    +                       type_: JIDConstant = JIDConstant.NORMAL_TYPE
    
    249
    +                       ) -> int:
    
    243 250
             jid = app.get_jid_from_account(account)
    
    244 251
             return self.get_jid_id(jid, type_=type_)
    
    245 252
     
    
    246
    -    def get_active_account_ids(self):
    
    253
    +    def get_active_account_ids(self) -> List[int]:
    
    247 254
             account_ids = []
    
    248 255
             for account in app.settings.get_active_accounts():
    
    249 256
                 account_ids.append(self.get_account_id(account))
    
    250 257
             return account_ids
    
    251 258
     
    
    252 259
         @timeit
    
    253
    -    def get_jid_id(self, jid, kind=None, type_=None):
    
    260
    +    def get_jid_id(self,
    
    261
    +                   jid: JID,
    
    262
    +                   kind: Optional[KindConstant] = None,
    
    263
    +                   type_: Optional[JIDConstant] = None
    
    264
    +                   ) -> int:
    
    254 265
             """
    
    255 266
             Get the jid id from a jid.
    
    256 267
             In case the jid id is not found create a new one.
    
    ... ... @@ -291,7 +302,8 @@ def get_jid_id(self, jid, kind=None, type_=None):
    291 302
             return lastrowid
    
    292 303
     
    
    293 304
         @staticmethod
    
    294
    -    def convert_show_values_to_db_api_values(show):
    
    305
    +    def convert_show_values_to_db_api_values(show: Optional[str]
    
    306
    +                                             ) -> Optional[ShowConstant]:
    
    295 307
             """
    
    296 308
             Convert from string style to constant ints for db
    
    297 309
             """
    
    ... ... @@ -315,8 +327,13 @@ def convert_show_values_to_db_api_values(show):
    315 327
             return None
    
    316 328
     
    
    317 329
         @timeit
    
    318
    -    def get_conversation_before_after(self, account, jid, before, timestamp,
    
    319
    -                                      n_lines):
    
    330
    +    def get_conversation_before_after(self,
    
    331
    +                                      account: str,
    
    332
    +                                      jid: JID,
    
    333
    +                                      before: bool,
    
    334
    +                                      timestamp: float,
    
    335
    +                                      n_lines: int
    
    336
    +                                      ) -> List[namedtuple]:
    
    320 337
             """
    
    321 338
             Load n_lines lines of conversation with jid before or after timestamp
    
    322 339
     
    
    ... ... @@ -359,8 +376,13 @@ def get_conversation_before_after(self, account, jid, before, timestamp,
    359 376
                 tuple(jids) + (timestamp, n_lines)).fetchall()
    
    360 377
     
    
    361 378
         @timeit
    
    362
    -    def get_conversation_muc_before_after(self, account, jid, before,
    
    363
    -                                          timestamp, n_lines):
    
    379
    +    def get_conversation_muc_before_after(self,
    
    380
    +                                          _account: str,
    
    381
    +                                          jid: JID,
    
    382
    +                                          before: bool,
    
    383
    +                                          timestamp: float,
    
    384
    +                                          n_lines: int
    
    385
    +                                          ) -> List[namedtuple]:
    
    364 386
             """
    
    365 387
             Load n_lines lines of conversation with jid before or after timestamp
    
    366 388
     
    
    ... ... @@ -401,7 +423,10 @@ def get_conversation_muc_before_after(self, account, jid, before,
    401 423
                 tuple(jids) + (timestamp, n_lines)).fetchall()
    
    402 424
     
    
    403 425
         @timeit
    
    404
    -    def get_last_conversation_line(self, account, jid):
    
    426
    +    def get_last_conversation_line(self,
    
    427
    +                                   account: str,
    
    428
    +                                   jid: JID
    
    429
    +                                   ) -> List[namedtuple]:
    
    405 430
             """
    
    406 431
             Load the last line of a conversation with jid for account.
    
    407 432
             Loads messages, but no status messages or error messages.
    
    ... ... @@ -433,7 +458,11 @@ def get_last_conversation_line(self, account, jid):
    433 458
             return self._con.execute(sql, tuple(jids)).fetchone()
    
    434 459
     
    
    435 460
         @timeit
    
    436
    -    def get_conversation_around(self, account, jid, timestamp):
    
    461
    +    def get_conversation_around(self,
    
    462
    +                                account: str,
    
    463
    +                                jid: JID,
    
    464
    +                                timestamp: float
    
    465
    +                                ) -> List[namedtuple]:
    
    437 466
             """
    
    438 467
             Load all lines of conversation with jid around a specific timestamp
    
    439 468
     
    
    ... ... @@ -561,8 +590,14 @@ def get_messages_for_date(self, account, jid, date):
    561 590
                 tuple(jids) + (date_ts, delta_ts)).fetchall()
    
    562 591
     
    
    563 592
         @timeit
    
    564
    -    def search_log(self, account, jid, query, from_users=None, before=None,
    
    565
    -                   after=None):
    
    593
    +    def search_log(self,
    
    594
    +                   _account: str,
    
    595
    +                   jid: JID,
    
    596
    +                   query: str,
    
    597
    +                   from_users: Optional[List[str]] = None,
    
    598
    +                   before: Optional[datetime.datetime] = None,
    
    599
    +                   after: Optional[datetime.datetime] = None
    
    600
    +                   ) -> List[namedtuple]:
    
    566 601
             """
    
    567 602
             Search the conversation log for messages containing the `query` string.
    
    568 603
     
    
    ... ... @@ -626,7 +661,12 @@ def search_log(self, account, jid, query, from_users=None, before=None,
    626 661
                 query, users, after_ts, before_ts)).fetchall()
    
    627 662
     
    
    628 663
         @timeit
    
    629
    -    def search_all_logs(self, query, from_users=None, before=None, after=None):
    
    664
    +    def search_all_logs(self,
    
    665
    +                        query: str,
    
    666
    +                        from_users: Optional[List[str]] = None,
    
    667
    +                        before: Optional[datetime.datetime] = None,
    
    668
    +                        after: Optional[datetime.datetime] = None
    
    669
    +                        ) -> List[namedtuple]:
    
    630 670
             """
    
    631 671
             Search all conversation logs for messages containing the `query`
    
    632 672
             string.
    
    ... ... @@ -682,7 +722,7 @@ def search_all_logs(self, query, from_users=None, before=None, after=None):
    682 722
                 sql, (query, users, after_ts, before_ts)).fetchall()
    
    683 723
     
    
    684 724
         @timeit
    
    685
    -    def get_days_with_logs(self, account, jid, year, month):
    
    725
    +    def get_days_with_logs(self, _account, jid, year, month):
    
    686 726
             """
    
    687 727
             Request the days in a month where we received messages
    
    688 728
             for a given `jid`.
    
    ... ... @@ -723,7 +763,7 @@ def get_days_with_logs(self, account, jid, year, month):
    723 763
                                           (date + delta).timestamp())).fetchall()
    
    724 764
     
    
    725 765
         @timeit
    
    726
    -    def get_last_date_that_has_logs(self, account, jid):
    
    766
    +    def get_last_date_that_has_logs(self, _account, jid):
    
    727 767
             """
    
    728 768
             Get the timestamp of the last message we received for the jid.
    
    729 769
     
    
    ... ... @@ -750,7 +790,7 @@ def get_last_date_that_has_logs(self, account, jid):
    750 790
             return self._con.execute(sql, tuple(jids)).fetchone().time
    
    751 791
     
    
    752 792
         @timeit
    
    753
    -    def get_first_date_that_has_logs(self, account, jid):
    
    793
    +    def get_first_date_that_has_logs(self, _account, jid):
    
    754 794
             """
    
    755 795
             Get the timestamp of the first message we received for the jid.
    
    756 796
     
    
    ... ... @@ -777,7 +817,7 @@ def get_first_date_that_has_logs(self, account, jid):
    777 817
             return self._con.execute(sql, tuple(jids)).fetchone().time
    
    778 818
     
    
    779 819
         @timeit
    
    780
    -    def get_date_has_logs(self, account, jid, date):
    
    820
    +    def get_date_has_logs(self, _account, jid, date):
    
    781 821
             """
    
    782 822
             Get single timestamp of a message we received for the jid
    
    783 823
             in the time range of one day.
    
    ... ... @@ -809,8 +849,13 @@ def get_date_has_logs(self, account, jid, date):
    809 849
                 sql, tuple(jids) + (start, end)).fetchone()
    
    810 850
     
    
    811 851
         @timeit
    
    812
    -    def deduplicate_muc_message(self, account, jid, resource,
    
    813
    -                                timestamp, message_id):
    
    852
    +    def deduplicate_muc_message(self,
    
    853
    +                                account: str,
    
    854
    +                                jid: str,
    
    855
    +                                resource: str,
    
    856
    +                                timestamp: float,
    
    857
    +                                message_id: str
    
    858
    +                                ) -> bool:
    
    814 859
             """
    
    815 860
             Check if a message is already in the `logs` table
    
    816 861
     
    
    ... ... @@ -857,8 +902,13 @@ def deduplicate_muc_message(self, account, jid, resource,
    857 902
             return False
    
    858 903
     
    
    859 904
         @timeit
    
    860
    -    def find_stanza_id(self, account, archive_jid, stanza_id, origin_id=None,
    
    861
    -                       groupchat=False):
    
    905
    +    def find_stanza_id(self,
    
    906
    +                       account: str,
    
    907
    +                       archive_jid: str,
    
    908
    +                       stanza_id: str,
    
    909
    +                       origin_id: Optional[str] = None,
    
    910
    +                       groupchat: bool = False
    
    911
    +                       ) -> bool:
    
    862 912
             """
    
    863 913
             Checks if a stanza-id is already in the `logs` table
    
    864 914
     
    
    ... ... @@ -916,7 +966,8 @@ def find_stanza_id(self, account, archive_jid, stanza_id, origin_id=None,
    916 966
     
    
    917 967
             if result is not None:
    
    918 968
                 log.info('Found duplicated message, stanza-id: %s, origin-id: %s, '
    
    919
    -                     'archive-jid: %s, account: %s', stanza_id, origin_id, archive_jid, account_id)
    
    969
    +                     'archive-jid: %s, account: %s', stanza_id, origin_id,
    
    970
    +                     archive_jid, account_id)
    
    920 971
                 return True
    
    921 972
             return False
    
    922 973
     
    
    ... ... @@ -1043,7 +1094,11 @@ def update_additional_data(self,
    1043 1094
                     sql, (serialized_dict, stanza_id, account_id,
    
    1044 1095
                           KindConstant.GC_MSG))
    
    1045 1096
     
    
    1046
    -    def insert_jid(self, jid, kind=None, type_=JIDConstant.NORMAL_TYPE):
    
    1097
    +    def insert_jid(self,
    
    1098
    +                   jid: str,
    
    1099
    +                   kind: Optional[KindConstant] = None,
    
    1100
    +                   type_: JIDConstant = JIDConstant.NORMAL_TYPE
    
    1101
    +                   ) -> int:
    
    1047 1102
             """
    
    1048 1103
             Insert a new jid into the `jids` table.
    
    1049 1104
             This is an alias of get_jid_id() for better readablility.
    
    ... ... @@ -1057,7 +1112,13 @@ def insert_jid(self, jid, kind=None, type_=JIDConstant.NORMAL_TYPE):
    1057 1112
             return self.get_jid_id(jid, kind, type_)
    
    1058 1113
     
    
    1059 1114
         @timeit
    
    1060
    -    def insert_into_logs(self, account, jid, time_, kind, **kwargs):
    
    1115
    +    def insert_into_logs(self,
    
    1116
    +                         account: str,
    
    1117
    +                         jid: str,
    
    1118
    +                         time_: float,
    
    1119
    +                         kind: KindConstant,
    
    1120
    +                         **kwargs: Any
    
    1121
    +                         ) -> int:
    
    1061 1122
             """
    
    1062 1123
             Insert a new message into the `logs` table
    
    1063 1124
     
    
    ... ... @@ -1100,7 +1161,12 @@ def insert_into_logs(self, account, jid, time_, kind, **kwargs):
    1100 1161
             return lastrowid
    
    1101 1162
     
    
    1102 1163
         @timeit
    
    1103
    -    def set_message_error(self, account_jid, jid, message_id, error):
    
    1164
    +    def set_message_error(self,
    
    1165
    +                          account_jid: str,
    
    1166
    +                          jid: JID,
    
    1167
    +                          message_id: str,
    
    1168
    +                          error: str
    
    1169
    +                          ) -> None:
    
    1104 1170
             """
    
    1105 1171
             Update the corresponding message with the error
    
    1106 1172
     
    
    ... ... @@ -1129,7 +1195,12 @@ def set_message_error(self, account_jid, jid, message_id, error):
    1129 1195
             self._delayed_commit()
    
    1130 1196
     
    
    1131 1197
         @timeit
    
    1132
    -    def set_marker(self, account_jid, jid, message_id, state):
    
    1198
    +    def set_marker(self,
    
    1199
    +                   account_jid: str,
    
    1200
    +                   jid: str,
    
    1201
    +                   message_id: str,
    
    1202
    +                   state: str
    
    1203
    +                   ) -> None:
    
    1133 1204
             """
    
    1134 1205
             Update the marker state of the corresponding message
    
    1135 1206
     
    
    ... ... @@ -1234,8 +1305,11 @@ def reset_archive_infos(self, jid):
    1234 1305
             log.info('Reset message archive info: %s', jid)
    
    1235 1306
             self._delayed_commit()
    
    1236 1307
     
    
    1237
    -    def remove_chat_history(self, account: str, jid: str,
    
    1238
    -                            groupchat: bool = False) -> None:
    
    1308
    +    def remove_chat_history(self,
    
    1309
    +                            account: str,
    
    1310
    +                            jid: str,
    
    1311
    +                            groupchat: bool = False
    
    1312
    +                            ) -> None:
    
    1239 1313
             """
    
    1240 1314
             Remove chat history for a specific chat.
    
    1241 1315
             If it's a group chat, remove last MAM ID as well.
    
    ... ... @@ -1255,7 +1329,7 @@ def remove_chat_history(self, account: str, jid: str,
    1255 1329
             self._delayed_commit()
    
    1256 1330
             log.info('Removed chat history for: %s', jid)
    
    1257 1331
     
    
    1258
    -    def _cleanup_chat_history(self):
    
    1332
    +    def _cleanup_chat_history(self) -> None:
    
    1259 1333
             """
    
    1260 1334
             Remove messages from account where messages are older than max_age
    
    1261 1335
             """
    

  • gajim/gtk/chat_filter.py
    ... ... @@ -26,7 +26,7 @@ class ChatFilter(Gtk.Box):
    26 26
                                (str, )),
    
    27 27
         }
    
    28 28
     
    
    29
    -    def __init__(self, icons=False):
    
    29
    +    def __init__(self, icons: bool = False) -> None:
    
    30 30
             Gtk.Box.__init__(self)
    
    31 31
             self.set_halign(Gtk.Align.CENTER)
    
    32 32
     
    
    ... ... @@ -69,10 +69,10 @@ def __init__(self, icons=False):
    69 69
             self.add(toolbar)
    
    70 70
             self.show_all()
    
    71 71
     
    
    72
    -    def _on_button_clicked(self, button):
    
    72
    +    def _on_button_clicked(self, button: Gtk.Button) -> None:
    
    73 73
             if button.get_active():
    
    74 74
                 self.emit('filter-changed', button.get_name())
    
    75 75
     
    
    76
    -    def reset(self):
    
    76
    +    def reset(self) -> None:
    
    77 77
             self._all_button.set_active(True)
    
    78 78
             self.emit('filter-changed', 'all')

  • gajim/gtk/dialogs.py
    ... ... @@ -149,7 +149,11 @@ class WarningDialog(HigDialog):
    149 149
         HIG compliant warning dialog
    
    150 150
         """
    
    151 151
     
    
    152
    -    def __init__(self, pritext, sectext='', transient_for=None):
    
    152
    +    def __init__(self,
    
    153
    +                 pritext: str,
    
    154
    +                 sectext: str = '',
    
    155
    +                 transient_for: Optional[Gtk.Window] = None
    
    156
    +                 ) -> None:
    
    153 157
             if transient_for is None:
    
    154 158
                 transient_for = app.app.get_active_window()
    
    155 159
             HigDialog.__init__(self,
    
    ... ... @@ -167,7 +171,11 @@ class InformationDialog(HigDialog):
    167 171
         HIG compliant info dialog
    
    168 172
         """
    
    169 173
     
    
    170
    -    def __init__(self, pritext, sectext='', transient_for=None):
    
    174
    +    def __init__(self,
    
    175
    +                 pritext: str,
    
    176
    +                 sectext: str = '',
    
    177
    +                 transient_for: Optional[Gtk.Window] = None
    
    178
    +                 ) -> None:
    
    171 179
             if transient_for is None:
    
    172 180
                 transient_for = app.app.get_active_window()
    
    173 181
             HigDialog.__init__(self,
    

  • gajim/gtk/features.py
    ... ... @@ -19,9 +19,11 @@
    19 19
     # You should have received a copy of the GNU General Public License
    
    20 20
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    21 21
     
    
    22
    +from typing import NamedTuple
    
    23
    +from typing import List
    
    24
    +
    
    22 25
     import os
    
    23 26
     import sys
    
    24
    -from collections import namedtuple
    
    25 27
     
    
    26 28
     from gi.repository import Gtk
    
    27 29
     from gi.repository import Gdk
    
    ... ... @@ -30,8 +32,17 @@
    30 32
     from gajim.common.i18n import _
    
    31 33
     
    
    32 34
     
    
    35
    +class Feature(NamedTuple):
    
    36
    +    name: str
    
    37
    +    available: bool
    
    38
    +    tooltip: str
    
    39
    +    dependency_u: str
    
    40
    +    dependency_w: str
    
    41
    +    enabled: bool
    
    42
    +
    
    43
    +
    
    33 44
     class Features(Gtk.ApplicationWindow):
    
    34
    -    def __init__(self):
    
    45
    +    def __init__(self) -> None:
    
    35 46
             Gtk.ApplicationWindow.__init__(self)
    
    36 47
             self.set_application(app.app)
    
    37 48
             self.set_position(Gtk.WindowPosition.CENTER)
    
    ... ... @@ -64,24 +75,21 @@ def __init__(self):
    64 75
     
    
    65 76
             self.show_all()
    
    66 77
     
    
    67
    -    def _on_key_press(self, _widget, event):
    
    78
    +    def _on_key_press(self,
    
    79
    +                      _widget: Gtk.Widget,
    
    80
    +                      event: Gdk.EventButton) -> None:
    
    68 81
             if event.keyval == Gdk.KEY_Escape:
    
    69 82
                 self.destroy()
    
    70 83
     
    
    71
    -    def _add_feature(self, feature):
    
    84
    +    def _add_feature(self, feature: Feature) -> None:
    
    72 85
             item = FeatureItem(feature)
    
    73 86
             self.feature_listbox.add(item)
    
    74
    -        item.get_parent().set_tooltip_text(item.tooltip)
    
    75 87
     
    
    76
    -    def _get_features(self):
    
    77
    -        Feature = namedtuple('Feature',
    
    78
    -                             ['name', 'available', 'tooltip',
    
    79
    -                              'dependency_u', 'dependency_w', 'enabled'])
    
    80
    -
    
    81
    -        notification_sounds_available = (
    
    88
    +    def _get_features(self) -> List[Feature]:
    
    89
    +        notification_sounds_available: bool = (
    
    82 90
                 app.is_installed('GSOUND') or sys.platform in ('win32', 'darwin'))
    
    83
    -        notification_sounds_enabled = app.settings.get('sounds_on')
    
    84
    -        spell_check_enabled = app.settings.get('use_speller')
    
    91
    +        notification_sounds_enabled: bool = app.settings.get('sounds_on')
    
    92
    +        spell_check_enabled: bool = app.settings.get('use_speller')
    
    85 93
     
    
    86 94
             auto_status = [app.settings.get('autoaway'), app.settings.get('autoxa')]
    
    87 95
             auto_status_enabled = bool(any(auto_status))
    
    ... ... @@ -156,77 +164,67 @@ def _get_features(self):
    156 164
             ]
    
    157 165
     
    
    158 166
         @staticmethod
    
    159
    -    def _some_keyring_available():
    
    167
    +    def _some_keyring_available() -> bool:
    
    160 168
             from gajim.common import passwords
    
    161 169
             return passwords.KEYRING_AVAILABLE
    
    162 170
     
    
    163 171
         @staticmethod
    
    164
    -    def _idle_available():
    
    172
    +    def _idle_available() -> bool:
    
    165 173
             from gajim.common import idle
    
    166 174
             return idle.Monitor.is_available()
    
    167 175
     
    
    168 176
     
    
    169 177
     class FeatureItem(Gtk.Grid):
    
    170
    -    def __init__(self, feature):
    
    171
    -        super().__init__()
    
    178
    +    def __init__(self, feature: Feature) -> None:
    
    179
    +        Gtk.Grid.__init__(self)
    
    172 180
             self.set_column_spacing(12)
    
    173 181
     
    
    174
    -        self.tooltip = feature.tooltip
    
    175
    -        self.feature_dependency_u_text = feature.dependency_u
    
    176
    -        self.feature_dependency_w_text = feature.dependency_w
    
    182
    +        feature_label = Gtk.Label(label=feature.name)
    
    183
    +        feature_label.set_halign(Gtk.Align.START)
    
    184
    +        self._box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
    
    185
    +        self._box.pack_start(feature_label, True, True, 0)
    
    186
    +        self._box.set_tooltip_text(feature.tooltip)
    
    177 187
     
    
    178
    -        self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
    
    179
    -        self.feature_label = Gtk.Label(label=feature.name)
    
    180
    -        self.feature_label.set_halign(Gtk.Align.START)
    
    181
    -        self.box.pack_start(self.feature_label, True, True, 0)
    
    188
    +        feature_dependency = Gtk.Label(label=feature.dependency_u)
    
    189
    +        feature_dependency.get_style_context().add_class('dim-label')
    
    182 190
     
    
    183
    -        self.feature_dependency_u = Gtk.Label(label=feature.dependency_u)
    
    184
    -        self.feature_dependency_u.get_style_context().add_class('dim-label')
    
    185
    -        self.feature_dependency_w = Gtk.Label(label=feature.dependency_w)
    
    186
    -        self.feature_dependency_w.get_style_context().add_class('dim-label')
    
    191
    +        if os.name == 'nt':
    
    192
    +            feature_dependency.set_label(feature.dependency_w)
    
    193
    +        else:
    
    194
    +            feature_dependency.set_label(feature.dependency_u)
    
    187 195
     
    
    188 196
             if not feature.available:
    
    189
    -            self.feature_dependency_u.set_halign(Gtk.Align.START)
    
    190
    -            self.feature_dependency_u.set_xalign(0.0)
    
    191
    -            self.feature_dependency_u.set_yalign(0.0)
    
    192
    -            self.feature_dependency_u.set_line_wrap(True)
    
    193
    -            self.feature_dependency_u.set_max_width_chars(50)
    
    194
    -            self.feature_dependency_u.set_selectable(True)
    
    195
    -            self.feature_dependency_w.set_halign(Gtk.Align.START)
    
    196
    -            self.feature_dependency_w.set_xalign(0.0)
    
    197
    -            self.feature_dependency_w.set_yalign(0.0)
    
    198
    -            self.feature_dependency_w.set_line_wrap(True)
    
    199
    -            self.feature_dependency_w.set_max_width_chars(50)
    
    200
    -            self.feature_dependency_w.set_selectable(True)
    
    201
    -
    
    202
    -            if os.name == 'nt':
    
    203
    -                self.box.pack_start(self.feature_dependency_w, True, True, 0)
    
    204
    -            else:
    
    205
    -                self.box.pack_start(self.feature_dependency_u, True, True, 0)
    
    206
    -
    
    207
    -        self.icon = Gtk.Image()
    
    208
    -        self.label_disabled = Gtk.Label(label=_('Disabled in Preferences'))
    
    209
    -        self.label_disabled.get_style_context().add_class('dim-label')
    
    210
    -        self.set_feature(feature.available, feature.enabled)
    
    211
    -
    
    212
    -        self.add(self.icon)
    
    213
    -        self.add(self.box)
    
    214
    -
    
    215
    -    def set_feature(self, available, enabled):
    
    216
    -        self.icon.get_style_context().remove_class('error-color')
    
    217
    -        self.icon.get_style_context().remove_class('warning-color')
    
    218
    -        self.icon.get_style_context().remove_class('success-color')
    
    197
    +            feature_dependency.set_halign(Gtk.Align.START)
    
    198
    +            feature_dependency.set_xalign(0.0)
    
    199
    +            feature_dependency.set_yalign(0.0)
    
    200
    +            feature_dependency.set_line_wrap(True)
    
    201
    +            feature_dependency.set_max_width_chars(50)
    
    202
    +            feature_dependency.set_selectable(True)
    
    203
    +            self._box.pack_start(feature_dependency, True, True, 0)
    
    204
    +
    
    205
    +        self._icon = Gtk.Image()
    
    206
    +        self._label_disabled = Gtk.Label(label=_('Disabled in Preferences'))
    
    207
    +        self._label_disabled.get_style_context().add_class('dim-label')
    
    208
    +        self._set_feature(feature.available, feature.enabled)
    
    209
    +
    
    210
    +        self.add(self._icon)
    
    211
    +        self.add(self._box)
    
    212
    +
    
    213
    +    def _set_feature(self, available: bool, enabled: bool) -> None:
    
    214
    +        self._icon.get_style_context().remove_class('error-color')
    
    215
    +        self._icon.get_style_context().remove_class('warning-color')
    
    216
    +        self._icon.get_style_context().remove_class('success-color')
    
    219 217
     
    
    220 218
             if not available:
    
    221
    -            self.icon.set_from_icon_name('window-close-symbolic',
    
    222
    -                                         Gtk.IconSize.MENU)
    
    223
    -            self.icon.get_style_context().add_class('error-color')
    
    219
    +            self._icon.set_from_icon_name(
    
    220
    +                'window-close-symbolic', Gtk.IconSize.MENU)
    
    221
    +            self._icon.get_style_context().add_class('error-color')
    
    224 222
             elif enabled is False:
    
    225
    -            self.icon.set_from_icon_name('dialog-warning-symbolic',
    
    226
    -                                         Gtk.IconSize.MENU)
    
    227
    -            self.box.pack_start(self.label_disabled, True, True, 0)
    
    228
    -            self.icon.get_style_context().add_class('warning-color')
    
    223
    +            self._icon.set_from_icon_name(
    
    224
    +                'dialog-warning-symbolic', Gtk.IconSize.MENU)
    
    225
    +            self._box.pack_start(self._label_disabled, True, True, 0)
    
    226
    +            self._icon.get_style_context().add_class('warning-color')
    
    229 227
             else:
    
    230
    -            self.icon.set_from_icon_name('emblem-ok-symbolic',
    
    231
    -                                         Gtk.IconSize.MENU)
    
    232
    -            self.icon.get_style_context().add_class('success-color')
    228
    +            self._icon.set_from_icon_name(
    
    229
    +                'emblem-ok-symbolic', Gtk.IconSize.MENU)
    
    230
    +            self._icon.get_style_context().add_class('success-color')

  • gajim/gtk/groupchat_info.py
    ... ... @@ -12,13 +12,20 @@
    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 typing import Any
    
    16
    +from typing import Dict
    
    17
    +from typing import List
    
    18
    +from typing import Optional
    
    19
    +
    
    15 20
     import time
    
    16 21
     
    
    17 22
     from gi.repository import Gdk
    
    18 23
     from gi.repository import GLib
    
    19 24
     from gi.repository import Gtk
    
    20 25
     
    
    26
    +from nbxmpp import JID
    
    21 27
     from nbxmpp.namespaces import Namespace
    
    28
    +from nbxmpp.structs import DiscoInfo
    
    22 29
     
    
    23 30
     from gajim.common import app
    
    24 31
     from gajim.common.i18n import _
    
    ... ... @@ -97,7 +104,10 @@
    97 104
     
    
    98 105
     
    
    99 106
     class GroupChatInfoScrolled(Gtk.ScrolledWindow):
    
    100
    -    def __init__(self, account=None, options=None):
    
    107
    +    def __init__(self,
    
    108
    +                 account: Optional[str] = None,
    
    109
    +                 options: Optional[Dict[str, Any]] = None
    
    110
    +                 ) -> None:
    
    101 111
             Gtk.ScrolledWindow.__init__(self)
    
    102 112
             if options is None:
    
    103 113
                 options = {}
    
    ... ... @@ -116,23 +126,26 @@ def __init__(self, account=None, options=None):
    116 126
                                 Gtk.PolicyType.AUTOMATIC)
    
    117 127
     
    
    118 128
             self._account = account
    
    119
    -        self._info = None
    
    129
    +        self._info: Optional[DiscoInfo] = None
    
    120 130
     
    
    121 131
             self._ui = get_builder('groupchat_info_scrolled.ui')
    
    122 132
             self.add(self._ui.info_grid)
    
    123 133
             self._ui.connect_signals(self)
    
    124 134
             self.show_all()
    
    125 135
     
    
    126
    -    def get_account(self):
    
    136
    +    def get_account(self) -> str:
    
    127 137
             return self._account
    
    128 138
     
    
    129
    -    def set_account(self, account):
    
    139
    +    def set_account(self, account: str) -> None:
    
    130 140
             self._account = account
    
    131 141
     
    
    132
    -    def get_jid(self):
    
    142
    +    def get_jid(self) -> Optional[JID]:
    
    133 143
             return self._info.jid
    
    134 144
     
    
    135
    -    def set_author(self, author, epoch_timestamp=None):
    
    145
    +    def set_author(self,
    
    146
    +                   author: Optional[str],
    
    147
    +                   epoch_timestamp: Optional[float] = None
    
    148
    +                   ) -> None:
    
    136 149
             has_author = bool(author)
    
    137 150
             if has_author and epoch_timestamp is not None:
    
    138 151
                 time_ = time.strftime('%c', time.localtime(epoch_timestamp))
    
    ... ... @@ -142,14 +155,14 @@ def set_author(self, author, epoch_timestamp=None):
    142 155
             self._ui.author.set_visible(has_author)
    
    143 156
             self._ui.author_label.set_visible(has_author)
    
    144 157
     
    
    145
    -    def set_subject(self, subject):
    
    158
    +    def set_subject(self, subject: str) -> None:
    
    146 159
             has_subject = bool(subject)
    
    147 160
             subject = GLib.markup_escape_text(subject or '')
    
    148 161
             self._ui.subject.set_markup(make_href_markup(subject))
    
    149 162
             self._ui.subject.set_visible(has_subject)
    
    150 163
             self._ui.subject_label.set_visible(has_subject)
    
    151 164
     
    
    152
    -    def set_from_disco_info(self, info):
    
    165
    +    def set_from_disco_info(self, info: DiscoInfo) -> None:
    
    153 166
             self._info = info
    
    154 167
             # Set name
    
    155 168
             if self._account is None:
    
    ... ... @@ -219,7 +232,7 @@ def set_from_disco_info(self, info):
    219 232
     
    
    220 233
             self._add_features(info.features)
    
    221 234
     
    
    222
    -    def _add_features(self, features):
    
    235
    +    def _add_features(self, features: List[str]) -> None:
    
    223 236
             grid = self._ui.info_grid
    
    224 237
             for row in range(30, 9, -1):
    
    225 238
                 # Remove everything from row 30 to 10
    
    ... ... @@ -244,7 +257,7 @@ def _add_features(self, features):
    244 257
                     row += 1
    
    245 258
             grid.show_all()
    
    246 259
     
    
    247
    -    def _on_copy_address(self, _button):
    
    260
    +    def _on_copy_address(self, _button: Gtk.Button) -> None:
    
    248 261
             clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD)
    
    249 262
             clipboard.set_text(f'xmpp:{self._info.jid}?join', -1)
    
    250 263
     
    
    ... ... @@ -265,7 +278,7 @@ def _on_activate_subject_link(_label, uri):
    265 278
             return Gdk.EVENT_STOP
    
    266 279
     
    
    267 280
         @staticmethod
    
    268
    -    def _get_feature_icon(icon, tooltip):
    
    281
    +    def _get_feature_icon(icon, tooltip: str) -> Gtk.Image:
    
    269 282
             image = Gtk.Image.new_from_icon_name(icon, Gtk.IconSize.MENU)
    
    270 283
             image.set_valign(Gtk.Align.CENTER)
    
    271 284
             image.set_halign(Gtk.Align.END)
    
    ... ... @@ -273,13 +286,13 @@ def _get_feature_icon(icon, tooltip):
    273 286
             return image
    
    274 287
     
    
    275 288
         @staticmethod
    
    276
    -    def _get_feature_label(text):
    
    289
    +    def _get_feature_label(text: str) -> Gtk.Label:
    
    277 290
             label = Gtk.Label(label=text, use_markup=True)
    
    278 291
             label.set_halign(Gtk.Align.START)
    
    279 292
             label.set_valign(Gtk.Align.START)
    
    280 293
             return label
    
    281 294
     
    
    282
    -    def _get_contact_button(self, contact):
    
    295
    +    def _get_contact_button(self, contact: str) -> Gtk.Button:
    
    283 296
             button = Gtk.LinkButton.new(contact)
    
    284 297
             button.set_halign(Gtk.Align.START)
    
    285 298
             button.get_style_context().add_class('link-button')
    

  • gajim/gtk/groupchat_nick.py
    ... ... @@ -21,7 +21,7 @@
    21 21
     
    
    22 22
     
    
    23 23
     class NickChooser(Gtk.MenuButton):
    
    24
    -    def __init__(self):
    
    24
    +    def __init__(self) -> None:
    
    25 25
             Gtk.MenuButton.__init__(self)
    
    26 26
             self._ui = get_builder('groupchat_nick_chooser.ui')
    
    27 27
             self.add(self._ui.button_content)
    
    ... ... @@ -34,24 +34,24 @@ def __init__(self):
    34 34
             self._ui.entry.connect('changed', self._on_nickname_changed)
    
    35 35
             self._ui.apply_button.connect('clicked', self._on_apply_nickname)
    
    36 36
     
    
    37
    -    def get_text(self):
    
    37
    +    def get_text(self) -> str:
    
    38 38
             return self._ui.entry.get_text()
    
    39 39
     
    
    40
    -    def set_text(self, text):
    
    40
    +    def set_text(self, text: str) -> None:
    
    41 41
             self._ui.entry.set_text(text)
    
    42 42
             self._ui.label.set_text(text)
    
    43 43
     
    
    44
    -    def _on_nickname_button_toggled(self, _widget):
    
    44
    +    def _on_nickname_button_toggled(self, _widget: Gtk.MenuButton) -> None:
    
    45 45
             self._ui.entry.grab_focus()
    
    46 46
     
    
    47
    -    def _on_nickname_changed(self, entry):
    
    47
    +    def _on_nickname_changed(self, entry: Gtk.Entry) -> None:
    
    48 48
             try:
    
    49 49
                 validate_resourcepart(entry.get_text())
    
    50 50
                 self._ui.apply_button.set_sensitive(True)
    
    51 51
             except InvalidJid:
    
    52 52
                 self._ui.apply_button.set_sensitive(False)
    
    53 53
     
    
    54
    -    def _on_apply_nickname(self, _button):
    
    54
    +    def _on_apply_nickname(self, _button: Gtk.Button) -> None:
    
    55 55
             nickname = self._ui.entry.get_text()
    
    56 56
             self._ui.popover.popdown()
    
    57 57
             self._ui.label.set_text(nickname)

  • gajim/gtk/notification.py
    ... ... @@ -24,13 +24,19 @@
    24 24
     # You should have received a copy of the GNU General Public License
    
    25 25
     # along with Gajim. If not, see <http://www.gnu.org/licenses/>.
    
    26 26
     
    
    27
    +from typing import Dict
    
    28
    +from typing import Optional
    
    29
    +from typing import Tuple
    
    30
    +
    
    27 31
     import sys
    
    28 32
     import logging
    
    29 33
     
    
    30 34
     from gi.repository import GLib
    
    31 35
     from gi.repository import Gio
    
    32 36
     from gi.repository import Gdk
    
    37
    +from gi.repository import GdkPixbuf
    
    33 38
     from gi.repository import Gtk
    
    39
    +from gi.repository import GObject
    
    34 40
     
    
    35 41
     from gajim.common import app
    
    36 42
     from gajim.common import ged
    
    ... ... @@ -49,7 +55,7 @@
    49 55
     
    
    50 56
     log = logging.getLogger('gajim.gui.notification')
    
    51 57
     
    
    52
    -NOTIFICATION_ICONS = {
    
    58
    +NOTIFICATION_ICONS: Dict[str, str] = {
    
    53 59
         'incoming-message': 'gajim-chat_msg_recv',
    
    54 60
         'group-chat-invitation': 'gajim-gc_invitation',
    
    55 61
         'incoming-call': 'call-start-symbolic',
    
    ... ... @@ -64,9 +70,9 @@ class Notification(EventHelper):
    64 70
         """
    
    65 71
         Handle notifications
    
    66 72
         """
    
    67
    -    def __init__(self):
    
    73
    +    def __init__(self) -> None:
    
    68 74
             EventHelper.__init__(self)
    
    69
    -        self._dbus_available = False
    
    75
    +        self._dbus_available: bool = False
    
    70 76
             self._daemon_capabilities = ['actions']
    
    71 77
             self._win32_active_popup = None
    
    72 78
     
    
    ... ... @@ -79,7 +85,7 @@ def __init__(self):
    79 85
                 ('connection-lost', ged.GUI2, self._on_connection_lost)
    
    80 86
             ])
    
    81 87
     
    
    82
    -    def _detect_dbus_caps(self):
    
    88
    +    def _detect_dbus_caps(self) -> None:
    
    83 89
             if sys.platform in ('win32', 'darwin'):
    
    84 90
                 return
    
    85 91
     
    
    ... ... @@ -87,7 +93,10 @@ def _detect_dbus_caps(self):
    87 93
                 self._dbus_available = True
    
    88 94
                 return
    
    89 95
     
    
    90
    -        def on_proxy_ready(_source, res, _data=None):
    
    96
    +        def on_proxy_ready(_source: GObject.Object,
    
    97
    +                           res: Gio.AsyncResult,
    
    98
    +                           _data: Optional[object] = None
    
    99
    +                           ) -> None:
    
    91 100
                 try:
    
    92 101
                     proxy = Gio.DBusProxy.new_finish(res)
    
    93 102
                     self._daemon_capabilities = proxy.GetCapabilities()
    
    ... ... @@ -177,14 +186,15 @@ def _on_connection_lost(self, event):
    177 186
                 icon_name='gajim-connection_lost')
    
    178 187
     
    
    179 188
         def _issue_notification(self,
    
    180
    -                            notif_type,
    
    181
    -                            account,
    
    182
    -                            jid,
    
    183
    -                            notif_detail='',
    
    184
    -                            title='',
    
    185
    -                            text='',
    
    186
    -                            icon_name=None,
    
    187
    -                            timeout=-1):
    
    189
    +                            notif_type: str,
    
    190
    +                            account: str,
    
    191
    +                            jid: Optional[str],
    
    192
    +                            notif_detail: str = '',
    
    193
    +                            title: str = '',
    
    194
    +                            text: str = '',
    
    195
    +                            icon_name: Optional[str] = None,
    
    196
    +                            timeout: int = -1
    
    197
    +                            ) -> None:
    
    188 198
             """
    
    189 199
             Notify a user of an event using GNotification and GApplication under
    
    190 200
             Linux, Use PopupNotificationWindow under Windows
    
    ... ... @@ -263,7 +273,9 @@ def _issue_notification(self,
    263 273
             app.app.send_notification(notif_id, notification)
    
    264 274
     
    
    265 275
         @staticmethod
    
    266
    -    def _get_avatar_for_notification(account, jid):
    
    276
    +    def _get_avatar_for_notification(account: str,
    
    277
    +                                     jid: str
    
    278
    +                                     ) -> GdkPixbuf.Pixbuf:
    
    267 279
             scale = get_monitor_scale_factor()
    
    268 280
             client = app.get_client(account)
    
    269 281
             contact = client.get_module('Contacts').get_contact(jid)
    
    ... ... @@ -286,14 +298,15 @@ def _make_id(*args):
    286 298
     
    
    287 299
     class PopupNotification(Gtk.Window):
    
    288 300
         def __init__(self,
    
    289
    -                 notif_type,
    
    290
    -                 account,
    
    291
    -                 jid,
    
    292
    -                 notif_detail,
    
    293
    -                 title,
    
    294
    -                 text,
    
    295
    -                 icon_name,
    
    296
    -                 timeout):
    
    301
    +                 notif_type: str,
    
    302
    +                 account: str,
    
    303
    +                 jid: Optional[str],
    
    304
    +                 notif_detail: str,
    
    305
    +                 title: str,
    
    306
    +                 text: str,
    
    307
    +                 icon_name: str,
    
    308
    +                 timeout: int
    
    309
    +                 ) -> None:
    
    297 310
             Gtk.Window.__init__(self)
    
    298 311
             self.set_type_hint(Gdk.WindowTypeHint.NOTIFICATION)
    
    299 312
             self.set_focus_on_map(False)
    
    ... ... @@ -301,7 +314,7 @@ def __init__(self,
    301 314
             self.set_skip_taskbar_hint(True)
    
    302 315
             self.set_decorated(False)
    
    303 316
     
    
    304
    -        self._timeout_id = None
    
    317
    +        self._timeout_id: Optional[int] = None
    
    305 318
             self._account = account
    
    306 319
             self._jid = jid
    
    307 320
             self._notif_type = notif_type
    
    ... ... @@ -334,11 +347,9 @@ def __init__(self,
    334 347
             add_css_to_widget(self._ui.color_bar, bar_class)
    
    335 348
             self._ui.color_bar.get_style_context().add_class('popup-bar')
    
    336 349
     
    
    337
    -        if title is None:
    
    338
    -            title = ''
    
    339 350
             self._ui.event_type_label.set_markup(title)
    
    340 351
     
    
    341
    -        if text is None:
    
    352
    +        if not text:
    
    342 353
                 client = app.get_client(account)
    
    343 354
                 contact = client.get_module('Contacts').get_contact(jid)
    
    344 355
                 text = contact.name
    
    ... ... @@ -357,7 +368,7 @@ def __init__(self,
    357 368
                 self._timeout_id = GLib.timeout_add_seconds(timeout, self.destroy)
    
    358 369
     
    
    359 370
         @staticmethod
    
    360
    -    def _get_window_pos():
    
    371
    +    def _get_window_pos() -> Tuple[int, int]:
    
    361 372
             pos_x = app.settings.get('notification_position_x')
    
    362 373
             screen_w, screen_h = get_total_screen_geometry()
    
    363 374
             if pos_x < 0:
    
    ... ... @@ -367,10 +378,13 @@ def _get_window_pos():
    367 378
                 pos_y = screen_h - 95 - 80 + pos_y + 1
    
    368 379
             return pos_x, pos_y
    
    369 380
     
    
    370
    -    def _on_close_button_clicked(self, _widget):
    
    381
    +    def _on_close_button_clicked(self, _button: Gtk.Button) -> None:
    
    371 382
             self.destroy()
    
    372 383
     
    
    373
    -    def _on_button_press(self, _widget, event):
    
    384
    +    def _on_button_press(self,
    
    385
    +                         _widget: Gtk.Widget,
    
    386
    +                         event: Gdk.EventButton
    
    387
    +                         ) -> None:
    
    374 388
             if event.button == 1:
    
    375 389
                 app.interface.handle_event(
    
    376 390
                     self._account, self._jid, self._notif_type)
    

  • gajim/gtk/search_view.py
    ... ... @@ -11,13 +11,21 @@
    11 11
     #
    
    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
    +
    
    15
    +from typing import Dict
    
    16
    +from typing import List
    
    17
    +from typing import Optional
    
    18
    +from typing import Tuple
    
    19
    +
    
    14 20
     import datetime
    
    15 21
     import logging
    
    16 22
     import time
    
    17 23
     import re
    
    24
    +from collections import namedtuple
    
    18 25
     
    
    19 26
     from gi.repository import GObject
    
    20 27
     from gi.repository import Gtk
    
    28
    +import cairo
    
    21 29
     
    
    22 30
     from nbxmpp import JID
    
    23 31
     
    
    ... ... @@ -43,14 +51,14 @@ class SearchView(Gtk.Box):
    43 51
                 ()),
    
    44 52
         }
    
    45 53
     
    
    46
    -    def __init__(self):
    
    54
    +    def __init__(self) -> None:
    
    47 55
             Gtk.Box.__init__(self)
    
    48 56
             self.set_size_request(300, -1)
    
    49 57
     
    
    50
    -        self._account = None
    
    51
    -        self._jid = None
    
    52
    -        self._results = []
    
    53
    -        self._scope = None
    
    58
    +        self._account: Optional[str] = None
    
    59
    +        self._jid: Optional[JID] = None
    
    60
    +        self._results: List[str] = []
    
    61
    +        self._scope: Optional[str] = None
    
    54 62
     
    
    55 63
             self._ui = get_builder('search_view.ui')
    
    56 64
             self._ui.results_listbox.set_header_func(self._header_func)
    
    ... ... @@ -86,19 +94,19 @@ def _header_func(row, before):
    86 94
                 else:
    
    87 95
                     row.set_header(None)
    
    88 96
     
    
    89
    -    def _on_hide_clicked(self, _button):
    
    97
    +    def _on_hide_clicked(self, _button: Gtk.Button) -> None:
    
    90 98
             self.emit('hide-search')
    
    91 99
     
    
    92
    -    def clear(self):
    
    100
    +    def clear(self) -> None:
    
    93 101
             self._ui.search_entry.set_text('')
    
    94 102
             self._clear_results()
    
    95 103
     
    
    96
    -    def _clear_results(self):
    
    104
    +    def _clear_results(self) -> None:
    
    97 105
             for row in self._ui.results_listbox.get_children():
    
    98 106
                 self._ui.results_listbox.remove(row)
    
    99 107
                 row.destroy()
    
    100 108
     
    
    101
    -    def _on_search(self, entry):
    
    109
    +    def _on_search(self, entry: Gtk.Entry) -> None:
    
    102 110
             self._clear_results()
    
    103 111
             self._ui.date_hint.hide()
    
    104 112
             text = entry.get_text()
    
    ... ... @@ -162,15 +170,20 @@ def _on_search(self, entry):
    162 170
             if has_filters is not None:
    
    163 171
                 filetypes = []
    
    164 172
                 for filetype in has_filters:
    
    165
    -                filetypes.append(FILE_CATEGORIES.get(filetype, filetype))
    
    166
    -
    
    167
    -            filetypes = self._flatten(filetypes)
    
    173
    +                types = FILE_CATEGORIES.get(filetype)
    
    174
    +                if types is None:
    
    175
    +                    filetypes.append(filetype)
    
    176
    +                else:
    
    177
    +                    for type_ in types:
    
    178
    +                        filetypes.append(type_)
    
    168 179
                 self._filter_results_for_files(filetypes)
    
    169 180
     
    
    170 181
             self._add_counter()
    
    171 182
             self._add_results()
    
    172 183
     
    
    173
    -    def _filter_results_for_files(self, filetypes):
    
    184
    +    def _filter_results_for_files(self,
    
    185
    +                                  filetypes: List[str]
    
    186
    +                                  ) -> None:
    
    174 187
             if 'file' in filetypes:
    
    175 188
                 results = []
    
    176 189
                 for result in self._results:
    
    ... ... @@ -189,7 +202,9 @@ def _filter_results_for_files(self, filetypes):
    189 202
                 self._results = results
    
    190 203
     
    
    191 204
         @staticmethod
    
    192
    -    def _strip_filters(text, filter_name):
    
    205
    +    def _strip_filters(text: str,
    
    206
    +                       filter_name: str
    
    207
    +                       ) -> Tuple[str, Optional[List[str]]]:
    
    193 208
             filters = []
    
    194 209
             start = 0
    
    195 210
             new_text = ''
    
    ... ... @@ -201,23 +216,12 @@ def _strip_filters(text, filter_name):
    201 216
             new_text += text[start:]
    
    202 217
             return new_text, filters or None
    
    203 218
     
    
    204
    -    @staticmethod
    
    205
    -    def _flatten(to_flatten):
    
    206
    -        nlist = []
    
    207
    -        for element in to_flatten:
    
    208
    -            if isinstance(element, list):
    
    209
    -                for sub_element in element:
    
    210
    -                    nlist.append(sub_element)
    
    211
    -            else:
    
    212
    -                nlist.append(element)
    
    213
    -        return nlist
    
    214
    -
    
    215
    -    def _add_counter(self):
    
    219
    +    def _add_counter(self) -> None:
    
    216 220
             results_count = len(self._results)
    
    217 221
             if results_count:
    
    218 222
                 self._ui.results_listbox.add(CounterRow(results_count))
    
    219 223
     
    
    220
    -    def _add_results(self):
    
    224
    +    def _add_results(self) -> None:
    
    221 225
             accounts = self._get_accounts()
    
    222 226
             for msg in self._results[:25]:
    
    223 227
                 if self._scope == 'everywhere':
    
    ... ... @@ -231,14 +235,17 @@ def _add_results(self):
    231 235
                 self._ui.results_listbox.add(result_row)
    
    232 236
             self._results = self._results[25:]
    
    233 237
     
    
    234
    -    def _on_edge_reached(self, _scrolledwin, pos):
    
    238
    +    def _on_edge_reached(self,
    
    239
    +                         _scrolledwin: Gtk.ScrolledWindow,
    
    240
    +                         pos: Gtk.PositionType
    
    241
    +                         ) -> None:
    
    235 242
             if pos != Gtk.PositionType.BOTTOM:
    
    236 243
                 return
    
    237 244
     
    
    238 245
             self._add_results()
    
    239 246
     
    
    240 247
         @staticmethod
    
    241
    -    def _get_accounts():
    
    248
    +    def _get_accounts() -> Dict[str, str]:
    
    242 249
             accounts = {}
    
    243 250
             for account in app.settings.get_accounts():
    
    244 251
                 account_id = app.storage.archive.get_account_id(account)
    
    ... ... @@ -246,7 +253,7 @@ def _get_accounts():
    246 253
             return accounts
    
    247 254
     
    
    248 255
         @staticmethod
    
    249
    -    def _on_row_activated(_listbox, row):
    
    256
    +    def _on_row_activated(_listbox: Gtk.ListBox, row: Gtk.ListBoxRow) -> None:
    
    250 257
             if row.type == 'counter':
    
    251 258
                 return
    
    252 259
     
    
    ... ... @@ -264,17 +271,17 @@ def _on_row_activated(_listbox, row):
    264 271
             if control is not None:
    
    265 272
                 control.scroll_to_message(row.log_line_id, row.timestamp)
    
    266 273
     
    
    267
    -    def set_focus(self):
    
    274
    +    def set_focus(self) -> None:
    
    268 275
             self._ui.search_entry.grab_focus()
    
    269 276
     
    
    270
    -    def set_context(self, account, jid):
    
    277
    +    def set_context(self, account: str, jid: JID) -> None:
    
    271 278
             self._account = account
    
    272 279
             self._jid = jid
    
    273 280
             self._ui.search_checkbutton.set_active(jid is None)
    
    274 281
     
    
    275 282
     
    
    276 283
     class RowHeader(Gtk.Box):
    
    277
    -    def __init__(self, account, jid, timestamp):
    
    284
    +    def __init__(self, account: str, jid: JID, timestamp: float) -> None:
    
    278 285
             Gtk.Box.__init__(self)
    
    279 286
             self.set_hexpand(True)
    
    280 287
     
    
    ... ... @@ -293,11 +300,11 @@ def __init__(self, account, jid, timestamp):
    293 300
     
    
    294 301
     
    
    295 302
     class CounterRow(Gtk.ListBoxRow):
    
    296
    -    def __init__(self, count):
    
    303
    +    def __init__(self, count: int) -> None:
    
    297 304
             Gtk.ListBoxRow.__init__(self)
    
    298
    -        self.type = 'counter'
    
    299
    -        self.jid = ''
    
    300
    -        self.time = 0
    
    305
    +        self.type: str = 'counter'
    
    306
    +        self.jid = None
    
    307
    +        self.time: float = 0.0
    
    301 308
             self.get_style_context().add_class('search-view-counter')
    
    302 309
     
    
    303 310
             if count == 1:
    
    ... ... @@ -310,7 +317,7 @@ def __init__(self, count):
    310 317
     
    
    311 318
     
    
    312 319
     class ResultRow(Gtk.ListBoxRow):
    
    313
    -    def __init__(self, msg, account, jid):
    
    320
    +    def __init__(self, msg: namedtuple, account: str, jid: JID) -> None:
    
    314 321
             Gtk.ListBoxRow.__init__(self)
    
    315 322
             self.account = account
    
    316 323
             self.jid = jid
    
    ... ... @@ -359,7 +366,10 @@ def __init__(self, msg, account, jid):
    359 366
     
    
    360 367
             self.show_all()
    
    361 368
     
    
    362
    -    def _get_avatar(self, kind, name):
    
    369
    +    def _get_avatar(self,
    
    370
    +                    kind: str,
    
    371
    +                    name: str
    
    372
    +                    ) -> Optional[cairo.ImageSurface]:
    
    363 373
             scale = self.get_scale_factor()
    
    364 374
             if self.contact.is_groupchat:
    
    365 375
                 contact = self.contact.get_resource(name)