Daniel Brötzmann pushed to branch mainwindow at gajim / gajim
Commits:
-
97a5b223
by wurstsalat at 2021-11-25T21:00:17+01:00
-
6282556e
by wurstsalat at 2021-11-25T23:27:48+01:00
-
cf5bf121
by wurstsalat at 2021-11-25T23:28:01+01:00
-
d7d25700
by wurstsalat at 2021-11-25T23:28:19+01:00
-
0615dbff
by wurstsalat at 2021-11-25T23:28:45+01:00
7 changed files:
- gajim/common/const.py
- gajim/gtk/chat_list.py
- gajim/gtk/controls/base.py
- gajim/gtk/controls/chat.py
- gajim/gtk/controls/groupchat.py
- gajim/gtk/controls/private.py
- gajim/gtk/main.py
Changes:
| ... | ... | @@ -186,6 +186,11 @@ class Trust(IntEnum): |
| 186 | 186 |
VERIFIED = 3
|
| 187 | 187 |
|
| 188 | 188 |
|
| 189 |
+class Direction(IntEnum):
|
|
| 190 |
+ NEXT = 0
|
|
| 191 |
+ PREV = 1
|
|
| 192 |
+ |
|
| 193 |
+ |
|
| 189 | 194 |
class Display(Enum):
|
| 190 | 195 |
X11 = 'X11Display'
|
| 191 | 196 |
WAYLAND = 'GdkWaylandDisplay'
|
| ... | ... | @@ -30,6 +30,7 @@ |
| 30 | 30 |
from gajim.common import app
|
| 31 | 31 |
from gajim.common import ged
|
| 32 | 32 |
from gajim.common.const import AvatarSize
|
| 33 |
+from gajim.common.const import Direction
|
|
| 33 | 34 |
from gajim.common.const import KindConstant
|
| 34 | 35 |
from gajim.common.const import RowHeaderType
|
| 35 | 36 |
from gajim.common.i18n import _
|
| ... | ... | @@ -224,10 +225,9 @@ def select_chat(self, account: str, jid: JID) -> None: |
| 224 | 225 |
row = self._chats[(account, jid)]
|
| 225 | 226 |
self.select_row(row)
|
| 226 | 227 |
|
| 227 |
- def select_next_chat(self, forwards: bool,
|
|
| 228 |
+ def select_next_chat(self, direction: Direction,
|
|
| 228 | 229 |
unread_first: bool = False) -> None:
|
| 229 | 230 |
# Selects the next chat, but prioritizes chats with unread messages.
|
| 230 |
- # Direction is forwards (True) or backwards (False)
|
|
| 231 | 231 |
row = self.get_selected_chat()
|
| 232 | 232 |
if row is None:
|
| 233 | 233 |
row = self.get_row_at_index(0)
|
| ... | ... | @@ -243,7 +243,7 @@ def select_next_chat(self, forwards: bool, |
| 243 | 243 |
|
| 244 | 244 |
# Loop until finding a chat with unread count or completing a cycle
|
| 245 | 245 |
while True:
|
| 246 |
- if forwards:
|
|
| 246 |
+ if direction == Direction.NEXT:
|
|
| 247 | 247 |
index += 1
|
| 248 | 248 |
if index >= len(self.get_children()):
|
| 249 | 249 |
index = 0
|
| ... | ... | @@ -266,12 +266,12 @@ def select_next_chat(self, forwards: bool, |
| 266 | 266 |
return
|
| 267 | 267 |
|
| 268 | 268 |
index = row.get_index()
|
| 269 |
- if forwards:
|
|
| 269 |
+ if direction == Direction.NEXT:
|
|
| 270 | 270 |
next_row = self.get_row_at_index(index + 1)
|
| 271 | 271 |
else:
|
| 272 | 272 |
next_row = self.get_row_at_index(index - 1)
|
| 273 | 273 |
if next_row is None:
|
| 274 |
- if forwards:
|
|
| 274 |
+ if direction == Direction.NEXT:
|
|
| 275 | 275 |
next_row = self.get_row_at_index(0)
|
| 276 | 276 |
else:
|
| 277 | 277 |
last = len(self.get_children()) - 1
|
| ... | ... | @@ -23,6 +23,9 @@ |
| 23 | 23 |
# You should have received a copy of the GNU General Public License
|
| 24 | 24 |
# along with Gajim. If not, see <http://www.gnu.org/licenses/>.
|
| 25 | 25 |
|
| 26 |
+from typing import Any
|
|
| 27 |
+from typing import Dict
|
|
| 28 |
+from typing import List
|
|
| 26 | 29 |
from typing import Optional
|
| 27 | 30 |
|
| 28 | 31 |
import os
|
| ... | ... | @@ -31,13 +34,16 @@ |
| 31 | 34 |
import uuid
|
| 32 | 35 |
import tempfile
|
| 33 | 36 |
|
| 34 |
-from nbxmpp.const import Chatstate
|
|
| 35 |
- |
|
| 36 | 37 |
from gi.repository import Gtk
|
| 37 | 38 |
from gi.repository import Gdk
|
| 39 |
+from gi.repository import GdkPixbuf
|
|
| 38 | 40 |
from gi.repository import GLib
|
| 39 | 41 |
from gi.repository import Gio
|
| 40 | 42 |
|
| 43 |
+from nbxmpp import JID
|
|
| 44 |
+from nbxmpp.const import Chatstate
|
|
| 45 |
+from nbxmpp.modules.security_labels import Displaymarking
|
|
| 46 |
+ |
|
| 41 | 47 |
from gajim.common import app
|
| 42 | 48 |
from gajim.common import helpers
|
| 43 | 49 |
from gajim.common import ged
|
| ... | ... | @@ -48,6 +54,7 @@ |
| 48 | 54 |
from gajim.common.helpers import AdditionalDataDict
|
| 49 | 55 |
from gajim.common.helpers import get_retraction_text
|
| 50 | 56 |
from gajim.common.const import KindConstant
|
| 57 |
+from gajim.common.modules.httpupload import HTTPFileTransfer
|
|
| 51 | 58 |
from gajim.common.preview_helpers import filename_from_uri
|
| 52 | 59 |
from gajim.common.preview_helpers import guess_simple_file_type
|
| 53 | 60 |
from gajim.common.structs import OutgoingMessage
|
| ... | ... | @@ -103,13 +110,13 @@ class BaseControl(ChatCommandProcessor, CommandTools, EventHelper): |
| 103 | 110 |
|
| 104 | 111 |
_type = None # type: ControlType
|
| 105 | 112 |
|
| 106 |
- def __init__(self, widget_name, account, jid):
|
|
| 113 |
+ def __init__(self, widget_name: str, account: str, jid: JID) -> None:
|
|
| 107 | 114 |
EventHelper.__init__(self)
|
| 108 | 115 |
# Undo needs this variable to know if space has been pressed.
|
| 109 | 116 |
# Initialize it to True so empty textview is saved in undo list
|
| 110 |
- self.space_pressed = True
|
|
| 117 |
+ self.space_pressed: bool = True
|
|
| 111 | 118 |
|
| 112 |
- self.handlers = {}
|
|
| 119 |
+ self.handlers: Dict[str, Any] = {}
|
|
| 113 | 120 |
|
| 114 | 121 |
self.account = account
|
| 115 | 122 |
|
| ... | ... | @@ -122,7 +129,7 @@ def __init__(self, widget_name, account, jid): |
| 122 | 129 |
|
| 123 | 130 |
# control_id is a unique id for the control,
|
| 124 | 131 |
# its used as action name for actions that belong to a control
|
| 125 |
- self.control_id = str(uuid.uuid4())
|
|
| 132 |
+ self.control_id: str = str(uuid.uuid4())
|
|
| 126 | 133 |
self.session = None
|
| 127 | 134 |
|
| 128 | 135 |
self.xml = get_builder(f'{widget_name}.ui')
|
| ... | ... | @@ -131,8 +138,8 @@ def __init__(self, widget_name, account, jid): |
| 131 | 138 |
|
| 132 | 139 |
self._account_badge = AccountBadge(self.account)
|
| 133 | 140 |
self.xml.account_badge_box.add(self._account_badge)
|
| 134 |
- show = len(app.settings.get_active_accounts()) > 1
|
|
| 135 |
- self.xml.account_badge_box.set_visible(show)
|
|
| 141 |
+ show_account_badge = len(app.settings.get_active_accounts()) > 1
|
|
| 142 |
+ self.xml.account_badge_box.set_visible(show_account_badge)
|
|
| 136 | 143 |
|
| 137 | 144 |
# Drag and drop
|
| 138 | 145 |
self.xml.overlay.add_overlay(self.xml.drop_area)
|
| ... | ... | @@ -214,30 +221,32 @@ def __init__(self, widget_name, account, jid): |
| 214 | 221 |
self.xml.hbox.pack_start(self.msg_scrolledwindow, True, True, 0)
|
| 215 | 222 |
|
| 216 | 223 |
# the following vars are used to keep history of user's messages
|
| 217 |
- self.sent_history = []
|
|
| 218 |
- self.sent_history_pos = 0
|
|
| 219 |
- self.received_history = []
|
|
| 220 |
- self.received_history_pos = 0
|
|
| 221 |
- self.orig_msg = None
|
|
| 224 |
+ self.sent_history: List[str] = []
|
|
| 225 |
+ self.sent_history_pos: int = 0
|
|
| 226 |
+ self.received_history: List[str] = []
|
|
| 227 |
+ self.received_history_pos: int = 0
|
|
| 228 |
+ self.orig_msg: Optional[str] = None
|
|
| 222 | 229 |
|
| 223 |
- # For XEP-0333
|
|
| 224 |
- self.last_msg_id = None
|
|
| 230 |
+ # XEP-0333 Chat Markers
|
|
| 231 |
+ self.last_msg_id: Optional[str] = None
|
|
| 225 | 232 |
|
| 226 |
- self.correcting = False
|
|
| 227 |
- self.last_sent_msg = None
|
|
| 233 |
+ # XEP-0308 Message Correction
|
|
| 234 |
+ self.correcting: bool = False
|
|
| 235 |
+ self.last_sent_msg: Optional[str] = None
|
|
| 228 | 236 |
|
| 229 | 237 |
self.set_emoticon_popover()
|
| 230 | 238 |
|
| 231 | 239 |
# Attach speller
|
| 232 | 240 |
self.set_speller()
|
| 233 | 241 |
|
| 234 |
- # For XEP-0172
|
|
| 242 |
+ # XEP-0172 User Nickname
|
|
| 243 |
+ # TODO:
|
|
| 235 | 244 |
self.user_nick = None
|
| 236 | 245 |
|
| 237 |
- self.command_hits = []
|
|
| 238 |
- self.last_key_tabs = False
|
|
| 246 |
+ self.command_hits: List[str] = []
|
|
| 247 |
+ self.last_key_tabs: bool = False
|
|
| 239 | 248 |
|
| 240 |
- self.sendmessage = True
|
|
| 249 |
+ self.sendmessage: bool = True
|
|
| 241 | 250 |
|
| 242 | 251 |
self._client.get_module('Chatstate').set_active(self.contact)
|
| 243 | 252 |
|
| ... | ... | @@ -263,11 +272,17 @@ def __init__(self, widget_name, account, jid): |
| 263 | 272 |
def _connect_contact_signals(self):
|
| 264 | 273 |
raise NotImplementedError
|
| 265 | 274 |
|
| 266 |
- def _process_jingle_av_event(self):
|
|
| 275 |
+ def _process_jingle_av_event(self, *args):
|
|
| 267 | 276 |
raise NotImplementedError
|
| 268 | 277 |
|
| 269 |
- def _get_action(self, name):
|
|
| 270 |
- return app.window.lookup_action(name + self.control_id)
|
|
| 278 |
+ def get_our_nick(self):
|
|
| 279 |
+ raise NotImplementedError
|
|
| 280 |
+ |
|
| 281 |
+ def room_name(self):
|
|
| 282 |
+ raise NotImplementedError
|
|
| 283 |
+ |
|
| 284 |
+ def _get_action(self, name: str) -> Gio.Action:
|
|
| 285 |
+ return app.window.lookup_action(f'{name}{self.control_id}')
|
|
| 271 | 286 |
|
| 272 | 287 |
def process_event(self, event):
|
| 273 | 288 |
if event.account != self.account:
|
| ... | ... | @@ -341,22 +356,22 @@ def _on_conversation_view_key_press(self, _listbox, event): |
| 341 | 356 |
return Gdk.EVENT_STOP
|
| 342 | 357 |
|
| 343 | 358 |
@property
|
| 344 |
- def type(self):
|
|
| 359 |
+ def type(self) -> ControlType:
|
|
| 345 | 360 |
return self._type
|
| 346 | 361 |
|
| 347 | 362 |
@property
|
| 348 |
- def is_chat(self):
|
|
| 363 |
+ def is_chat(self) -> bool:
|
|
| 349 | 364 |
return self._type.is_chat
|
| 350 | 365 |
|
| 351 | 366 |
@property
|
| 352 |
- def is_privatechat(self):
|
|
| 367 |
+ def is_privatechat(self) -> bool:
|
|
| 353 | 368 |
return self._type.is_privatechat
|
| 354 | 369 |
|
| 355 | 370 |
@property
|
| 356 |
- def is_groupchat(self):
|
|
| 371 |
+ def is_groupchat(self) -> bool:
|
|
| 357 | 372 |
return self._type.is_groupchat
|
| 358 | 373 |
|
| 359 |
- def safe_shutdown(self):
|
|
| 374 |
+ def safe_shutdown(self) -> bool:
|
|
| 360 | 375 |
"""
|
| 361 | 376 |
Called to check if control can be closed without losing data.
|
| 362 | 377 |
returns True if control can be closed safely else False
|
| ... | ... | @@ -378,7 +393,7 @@ def allow_shutdown(self, method, on_response_yes, on_response_no): |
| 378 | 393 |
def focus(self):
|
| 379 | 394 |
raise NotImplementedError
|
| 380 | 395 |
|
| 381 |
- def draw_banner(self):
|
|
| 396 |
+ def draw_banner(self) -> None:
|
|
| 382 | 397 |
"""
|
| 383 | 398 |
Draw the fat line at the top of the window
|
| 384 | 399 |
that houses the icon, jid, etc
|
| ... | ... | @@ -387,7 +402,7 @@ def draw_banner(self): |
| 387 | 402 |
"""
|
| 388 | 403 |
self.draw_banner_text()
|
| 389 | 404 |
|
| 390 |
- def update_toolbar(self):
|
|
| 405 |
+ def update_toolbar(self) -> None:
|
|
| 391 | 406 |
"""
|
| 392 | 407 |
update state of buttons in toolbar
|
| 393 | 408 |
"""
|
| ... | ... | @@ -395,18 +410,18 @@ def update_toolbar(self): |
| 395 | 410 |
app.plugin_manager.gui_extension_point(
|
| 396 | 411 |
'chat_control_base_update_toolbar', self)
|
| 397 | 412 |
|
| 398 |
- def draw_banner_text(self):
|
|
| 413 |
+ def draw_banner_text(self) -> None:
|
|
| 399 | 414 |
"""
|
| 400 | 415 |
Derived types SHOULD implement this
|
| 401 | 416 |
"""
|
| 402 | 417 |
|
| 403 |
- def update_ui(self):
|
|
| 418 |
+ def update_ui(self) -> None:
|
|
| 404 | 419 |
"""
|
| 405 | 420 |
Derived types SHOULD implement this
|
| 406 | 421 |
"""
|
| 407 | 422 |
self.draw_banner()
|
| 408 | 423 |
|
| 409 |
- def repaint_themed_widgets(self):
|
|
| 424 |
+ def repaint_themed_widgets(self) -> None:
|
|
| 410 | 425 |
"""
|
| 411 | 426 |
Derived types MAY implement this
|
| 412 | 427 |
"""
|
| ... | ... | @@ -453,7 +468,7 @@ def remove_session(self, session): |
| 453 | 468 |
def _nec_ping(self, obj):
|
| 454 | 469 |
raise NotImplementedError
|
| 455 | 470 |
|
| 456 |
- def setup_seclabel(self):
|
|
| 471 |
+ def setup_seclabel(self) -> None:
|
|
| 457 | 472 |
self.xml.label_selector.hide()
|
| 458 | 473 |
self.xml.label_selector.set_no_show_all(True)
|
| 459 | 474 |
lb = Gtk.ListStore(str)
|
| ... | ... | @@ -502,7 +517,7 @@ def delegate_action(self, action): |
| 502 | 517 |
return Gdk.EVENT_STOP
|
| 503 | 518 |
|
| 504 | 519 |
if action == 'delete-line':
|
| 505 |
- self.clear(self.msg_textview)
|
|
| 520 |
+ self.msg_textview.clear()
|
|
| 506 | 521 |
return Gdk.EVENT_STOP
|
| 507 | 522 |
|
| 508 | 523 |
if action == 'show-emoji-chooser':
|
| ... | ... | @@ -514,7 +529,7 @@ def delegate_action(self, action): |
| 514 | 529 |
|
| 515 | 530 |
return Gdk.EVENT_PROPAGATE
|
| 516 | 531 |
|
| 517 |
- def add_actions(self):
|
|
| 532 |
+ def add_actions(self) -> None:
|
|
| 518 | 533 |
action = Gio.SimpleAction.new_stateful(
|
| 519 | 534 |
f'set-encryption-{self.control_id}',
|
| 520 | 535 |
GLib.VariantType.new('s'),
|
| ... | ... | @@ -535,7 +550,7 @@ def add_actions(self): |
| 535 | 550 |
action.set_enabled(False)
|
| 536 | 551 |
app.window.add_action(action)
|
| 537 | 552 |
|
| 538 |
- def remove_actions(self):
|
|
| 553 |
+ def remove_actions(self) -> None:
|
|
| 539 | 554 |
actions = [
|
| 540 | 555 |
'send-message-',
|
| 541 | 556 |
'set-encryption-',
|
| ... | ... | @@ -547,7 +562,7 @@ def remove_actions(self): |
| 547 | 562 |
for action in actions:
|
| 548 | 563 |
app.window.remove_action(f'{action}{self.control_id}')
|
| 549 | 564 |
|
| 550 |
- def mark_as_read(self, send_marker=True):
|
|
| 565 |
+ def mark_as_read(self, send_marker: bool = True) -> None:
|
|
| 551 | 566 |
self._jump_to_end_button.reset_unread_count()
|
| 552 | 567 |
|
| 553 | 568 |
if send_marker:
|
| ... | ... | @@ -576,7 +591,7 @@ def change_encryption(self, action, param): |
| 576 | 591 |
self.set_encryption_menu_icon()
|
| 577 | 592 |
self.set_lock_image()
|
| 578 | 593 |
|
| 579 |
- def set_lock_image(self):
|
|
| 594 |
+ def set_lock_image(self) -> None:
|
|
| 580 | 595 |
encryption_state = {'visible': self.encryption is not None,
|
| 581 | 596 |
'enc_type': self.encryption,
|
| 582 | 597 |
'authenticated': False}
|
| ... | ... | @@ -621,7 +636,7 @@ def get_encryption_state(self): |
| 621 | 636 |
return None
|
| 622 | 637 |
return state
|
| 623 | 638 |
|
| 624 |
- def set_encryption_menu_icon(self):
|
|
| 639 |
+ def set_encryption_menu_icon(self) -> None:
|
|
| 625 | 640 |
image = self.xml.encryption_menu.get_image()
|
| 626 | 641 |
if image is None:
|
| 627 | 642 |
image = Gtk.Image()
|
| ... | ... | @@ -633,7 +648,7 @@ def set_encryption_menu_icon(self): |
| 633 | 648 |
image.set_from_icon_name('channel-secure-symbolic',
|
| 634 | 649 |
Gtk.IconSize.MENU)
|
| 635 | 650 |
|
| 636 |
- def set_speller(self):
|
|
| 651 |
+ def set_speller(self) -> None:
|
|
| 637 | 652 |
if (not app.is_installed('GSPELL') or
|
| 638 | 653 |
not app.settings.get('use_speller')):
|
| 639 | 654 |
return
|
| ... | ... | @@ -649,7 +664,7 @@ def set_speller(self): |
| 649 | 664 |
|
| 650 | 665 |
spell_checker.connect('notify::language', self.on_language_changed)
|
| 651 | 666 |
|
| 652 |
- def get_speller_language(self):
|
|
| 667 |
+ def get_speller_language(self) -> Optional[Gspell.Language]:
|
|
| 653 | 668 |
lang = self.contact.settings.get('speller_language')
|
| 654 | 669 |
if not lang:
|
| 655 | 670 |
# use the default one
|
| ... | ... | @@ -665,7 +680,7 @@ def on_language_changed(self, checker, _param): |
| 665 | 680 |
gspell_lang = checker.get_language()
|
| 666 | 681 |
self.contact.settings.set('speller_language', gspell_lang.get_code())
|
| 667 | 682 |
|
| 668 |
- def shutdown(self):
|
|
| 683 |
+ def shutdown(self) -> None:
|
|
| 669 | 684 |
# remove_gui_extension_point() is called on shutdown, but also when
|
| 670 | 685 |
# a plugin is getting disabled. Plugins don’t know the difference.
|
| 671 | 686 |
# Plugins might want to remove their widgets on
|
| ... | ... | @@ -763,17 +778,24 @@ def _on_message_textview_paste_event(self, _texview): |
| 763 | 778 |
callback=self._paste_event_confirmed,
|
| 764 | 779 |
args=[image])]).show()
|
| 765 | 780 |
|
| 766 |
- def _paste_event_confirmed(self, is_checked, image):
|
|
| 781 |
+ def _paste_event_confirmed(self,
|
|
| 782 |
+ is_checked: bool,
|
|
| 783 |
+ image: Optional[GdkPixbuf.Pixbuf]
|
|
| 784 |
+ ) -> None:
|
|
| 767 | 785 |
if is_checked:
|
| 768 | 786 |
app.settings.set('confirm_paste_image', False)
|
| 769 | 787 |
|
| 770 | 788 |
dir_ = tempfile.gettempdir()
|
| 771 | 789 |
path = os.path.join(dir_, f'{uuid.uuid4()}.png')
|
| 790 |
+ if image is None:
|
|
| 791 |
+ self.add_info_message(_('Error: Could not process image'))
|
|
| 792 |
+ return
|
|
| 793 |
+ |
|
| 772 | 794 |
image.savev(path, 'png', [], [])
|
| 773 | 795 |
|
| 774 | 796 |
self._start_filetransfer(path)
|
| 775 | 797 |
|
| 776 |
- def _get_pref_ft_method(self):
|
|
| 798 |
+ def _get_pref_ft_method(self) -> Optional[str]:
|
|
| 777 | 799 |
ft_pref = app.settings.get_account_setting(self.account,
|
| 778 | 800 |
'filetransfer_preference')
|
| 779 | 801 |
httpupload = app.window.lookup_action(
|
| ... | ... | @@ -1006,12 +1028,13 @@ def _on_send_message(self, *args): |
| 1006 | 1028 |
self.send_message(message, xhtml=xhtml)
|
| 1007 | 1029 |
|
| 1008 | 1030 |
def send_message(self,
|
| 1009 |
- message,
|
|
| 1010 |
- type_='chat',
|
|
| 1011 |
- resource=None,
|
|
| 1012 |
- xhtml=None,
|
|
| 1013 |
- process_commands=True,
|
|
| 1014 |
- attention=False):
|
|
| 1031 |
+ message: str,
|
|
| 1032 |
+ type_: str = 'chat',
|
|
| 1033 |
+ resource: Optional[str] = None,
|
|
| 1034 |
+ xhtml: Optional[str] = None,
|
|
| 1035 |
+ process_commands: bool = True,
|
|
| 1036 |
+ attention: bool = False
|
|
| 1037 |
+ ) -> None:
|
|
| 1015 | 1038 |
"""
|
| 1016 | 1039 |
Send the given message to the active tab. Doesn't return None if error
|
| 1017 | 1040 |
"""
|
| ... | ... | @@ -1023,6 +1046,7 @@ def send_message(self, |
| 1023 | 1046 |
|
| 1024 | 1047 |
label = self.get_seclabel()
|
| 1025 | 1048 |
|
| 1049 |
+ correct_id: Optional[str] = None
|
|
| 1026 | 1050 |
if self.correcting and self.last_sent_msg:
|
| 1027 | 1051 |
correct_id = self.last_sent_msg
|
| 1028 | 1052 |
else:
|
| ... | ... | @@ -1073,7 +1097,7 @@ def _on_message_tv_buffer_changed(self, textbuffer): |
| 1073 | 1097 |
self._client.get_module('Chatstate').set_chatstate(
|
| 1074 | 1098 |
self.contact, Chatstate.COMPOSING)
|
| 1075 | 1099 |
|
| 1076 |
- def save_message(self, message, msg_type):
|
|
| 1100 |
+ def save_message(self, message: str, msg_type: str) -> None:
|
|
| 1077 | 1101 |
# save the message, so user can scroll though the list with key up/down
|
| 1078 | 1102 |
if msg_type == 'sent':
|
| 1079 | 1103 |
history = self.sent_history
|
| ... | ... | @@ -1099,10 +1123,10 @@ def save_message(self, message, msg_type): |
| 1099 | 1123 |
else:
|
| 1100 | 1124 |
self.received_history_pos = pos
|
| 1101 | 1125 |
|
| 1102 |
- def add_info_message(self, text):
|
|
| 1126 |
+ def add_info_message(self, text: str) -> None:
|
|
| 1103 | 1127 |
self.conversation_view.add_info_message(text)
|
| 1104 | 1128 |
|
| 1105 |
- def add_file_transfer(self, transfer):
|
|
| 1129 |
+ def add_file_transfer(self, transfer: HTTPFileTransfer) -> None:
|
|
| 1106 | 1130 |
self.conversation_view.add_file_transfer(transfer)
|
| 1107 | 1131 |
|
| 1108 | 1132 |
def add_jingle_file_transfer(self, event):
|
| ... | ... | @@ -1118,16 +1142,17 @@ def add_call_message(self, event): |
| 1118 | 1142 |
self.conversation_view.add_call_message(event=event)
|
| 1119 | 1143 |
|
| 1120 | 1144 |
def add_message(self,
|
| 1121 |
- text,
|
|
| 1122 |
- kind,
|
|
| 1123 |
- name,
|
|
| 1124 |
- tim,
|
|
| 1125 |
- notify,
|
|
| 1126 |
- displaymarking=None,
|
|
| 1127 |
- msg_log_id=None,
|
|
| 1128 |
- message_id=None,
|
|
| 1129 |
- stanza_id=None,
|
|
| 1130 |
- additional_data=None):
|
|
| 1145 |
+ text: str,
|
|
| 1146 |
+ kind: str,
|
|
| 1147 |
+ name: str,
|
|
| 1148 |
+ tim: float,
|
|
| 1149 |
+ notify: bool,
|
|
| 1150 |
+ displaymarking: Optional[Displaymarking] = None,
|
|
| 1151 |
+ msg_log_id: Optional[str] = None,
|
|
| 1152 |
+ message_id: Optional[str] = None,
|
|
| 1153 |
+ stanza_id: Optional[str] =None,
|
|
| 1154 |
+ additional_data: Optional[AdditionalDataDict] = None
|
|
| 1155 |
+ ) -> None:
|
|
| 1131 | 1156 |
|
| 1132 | 1157 |
if additional_data is None:
|
| 1133 | 1158 |
additional_data = AdditionalDataDict()
|
| ... | ... | @@ -1174,8 +1199,12 @@ def add_message(self, |
| 1174 | 1199 |
if chat_active and self._scrolled_view.get_autoscroll():
|
| 1175 | 1200 |
app.window.mark_as_read(self.account, self.contact.jid)
|
| 1176 | 1201 |
|
| 1177 |
- def _notify(self, name: str, text: str, tim: Optional[int],
|
|
| 1178 |
- additional_data: AdditionalDataDict) -> None:
|
|
| 1202 |
+ def _notify(self,
|
|
| 1203 |
+ name: str,
|
|
| 1204 |
+ text: str,
|
|
| 1205 |
+ tim: Optional[float],
|
|
| 1206 |
+ additional_data: AdditionalDataDict
|
|
| 1207 |
+ ) -> None:
|
|
| 1179 | 1208 |
if app.window.is_chat_active(self.account, self.contact.jid):
|
| 1180 | 1209 |
if self._scrolled_view.get_autoscroll():
|
| 1181 | 1210 |
return
|
| ... | ... | @@ -1192,6 +1221,7 @@ def _notify(self, name: str, text: str, tim: Optional[int], |
| 1192 | 1221 |
_icon, file_type = guess_simple_file_type(text)
|
| 1193 | 1222 |
text = f'{file_type} ({file_name})'
|
| 1194 | 1223 |
|
| 1224 |
+ sound: Optional[str] = None
|
|
| 1195 | 1225 |
if self.is_chat:
|
| 1196 | 1226 |
msg_type = 'chat-message'
|
| 1197 | 1227 |
sound = 'first_message_received'
|
| ... | ... | @@ -1205,6 +1235,7 @@ def _notify(self, name: str, text: str, tim: Optional[int], |
| 1205 | 1235 |
sound = 'muc_message_highlight'
|
| 1206 | 1236 |
else:
|
| 1207 | 1237 |
sound = 'muc_message_received'
|
| 1238 |
+ |
|
| 1208 | 1239 |
if not self.contact.can_notify():
|
| 1209 | 1240 |
sound = None
|
| 1210 | 1241 |
|
| ... | ... | @@ -1234,7 +1265,7 @@ def _notify(self, name: str, text: str, tim: Optional[int], |
| 1234 | 1265 |
text=text,
|
| 1235 | 1266 |
sound=sound))
|
| 1236 | 1267 |
|
| 1237 |
- def toggle_emoticons(self):
|
|
| 1268 |
+ def toggle_emoticons(self) -> None:
|
|
| 1238 | 1269 |
"""
|
| 1239 | 1270 |
Hide show emoticons_button
|
| 1240 | 1271 |
"""
|
| ... | ... | @@ -1245,7 +1276,7 @@ def toggle_emoticons(self): |
| 1245 | 1276 |
self.xml.emoticons_button.set_no_show_all(True)
|
| 1246 | 1277 |
self.xml.emoticons_button.hide()
|
| 1247 | 1278 |
|
| 1248 |
- def set_emoticon_popover(self):
|
|
| 1279 |
+ def set_emoticon_popover(self) -> None:
|
|
| 1249 | 1280 |
if not app.settings.get('emoticons_theme'):
|
| 1250 | 1281 |
return
|
| 1251 | 1282 |
|
| ... | ... | @@ -1295,7 +1326,7 @@ def clear(tv): |
| 1295 | 1326 |
start, end = buffer_.get_bounds()
|
| 1296 | 1327 |
buffer_.delete(start, end)
|
| 1297 | 1328 |
|
| 1298 |
- def set_control_active(self, state):
|
|
| 1329 |
+ def set_control_active(self, state: bool) -> None:
|
|
| 1299 | 1330 |
if state:
|
| 1300 | 1331 |
self.set_emoticon_popover()
|
| 1301 | 1332 |
|
| ... | ... | @@ -1309,19 +1340,19 @@ def set_control_active(self, state): |
| 1309 | 1340 |
self._client.get_module('Chatstate').set_chatstate(
|
| 1310 | 1341 |
self.contact, Chatstate.INACTIVE)
|
| 1311 | 1342 |
|
| 1312 |
- def reset_view(self):
|
|
| 1343 |
+ def reset_view(self) -> None:
|
|
| 1313 | 1344 |
self.conversation_view.clear()
|
| 1314 | 1345 |
|
| 1315 |
- def get_autoscroll(self):
|
|
| 1346 |
+ def get_autoscroll(self) -> bool:
|
|
| 1316 | 1347 |
return self._scrolled_view.get_autoscroll()
|
| 1317 | 1348 |
|
| 1318 |
- def scroll_to_end(self, force=False):
|
|
| 1349 |
+ def scroll_to_end(self, force: bool = False) -> None:
|
|
| 1319 | 1350 |
# Clear view and reload conversation
|
| 1320 | 1351 |
self.conversation_view.clear()
|
| 1321 | 1352 |
self._scrolled_view.reset()
|
| 1322 | 1353 |
self.conversation_view.scroll_to_end(force)
|
| 1323 | 1354 |
|
| 1324 |
- def scroll_to_message(self, log_line_id, timestamp):
|
|
| 1355 |
+ def scroll_to_message(self, log_line_id: str, timestamp: float) -> None:
|
|
| 1325 | 1356 |
row = self.conversation_view.get_row_by_log_line_id(log_line_id)
|
| 1326 | 1357 |
if row is None:
|
| 1327 | 1358 |
# Clear view and reload conversation around timestamp
|
| ... | ... | @@ -1338,7 +1369,11 @@ def scroll_to_message(self, log_line_id, timestamp): |
| 1338 | 1369 |
log_line_id)
|
| 1339 | 1370 |
GLib.idle_add(self.conversation_view.unlock)
|
| 1340 | 1371 |
|
| 1341 |
- def fetch_n_lines_history(self, _scrolled, before, n_lines):
|
|
| 1372 |
+ def fetch_n_lines_history(self,
|
|
| 1373 |
+ _scrolled: Gtk.ScrolledWindow,
|
|
| 1374 |
+ before: bool,
|
|
| 1375 |
+ n_lines: int
|
|
| 1376 |
+ ) -> None:
|
|
| 1342 | 1377 |
if self.conversation_view.locked:
|
| 1343 | 1378 |
return
|
| 1344 | 1379 |
|
| ... | ... | @@ -1436,13 +1471,17 @@ def add_messages(self, messages): |
| 1436 | 1471 |
marker=msg.marker,
|
| 1437 | 1472 |
error=msg.error)
|
| 1438 | 1473 |
|
| 1439 |
- def has_focus(self):
|
|
| 1474 |
+ def has_focus(self) -> bool:
|
|
| 1440 | 1475 |
if app.window.get_property('has-toplevel-focus'):
|
| 1441 | 1476 |
if self == app.window.get_active_control():
|
| 1442 | 1477 |
return True
|
| 1443 | 1478 |
return False
|
| 1444 | 1479 |
|
| 1445 |
- def scroll_messages(self, direction, msg_buf, msg_type):
|
|
| 1480 |
+ def scroll_messages(self,
|
|
| 1481 |
+ direction: str,
|
|
| 1482 |
+ msg_buf: Gtk.TextBuffer,
|
|
| 1483 |
+ msg_type: str,
|
|
| 1484 |
+ ) -> None:
|
|
| 1446 | 1485 |
if msg_type == 'sent':
|
| 1447 | 1486 |
history = self.sent_history
|
| 1448 | 1487 |
pos = self.sent_history_pos
|
| ... | ... | @@ -1490,7 +1529,7 @@ def scroll_messages(self, direction, msg_buf, msg_type): |
| 1490 | 1529 |
message = '> %s\n' % message.replace('\n', '\n> ')
|
| 1491 | 1530 |
msg_buf.set_text(message)
|
| 1492 | 1531 |
|
| 1493 |
- def update_account_badge(self):
|
|
| 1532 |
+ def update_account_badge(self) -> None:
|
|
| 1494 | 1533 |
show = len(app.settings.get_active_accounts()) > 1
|
| 1495 | 1534 |
self.xml.account_badge_box.set_visible(show)
|
| 1496 | 1535 |
|
| ... | ... | @@ -25,6 +25,7 @@ |
| 25 | 25 |
|
| 26 | 26 |
from typing import ClassVar # pylint: disable=unused-import
|
| 27 | 27 |
from typing import Type # pylint: disable=unused-import
|
| 28 |
+from typing import Optional
|
|
| 28 | 29 |
|
| 29 | 30 |
import time
|
| 30 | 31 |
import logging
|
| ... | ... | @@ -34,8 +35,10 @@ |
| 34 | 35 |
from gi.repository import GLib
|
| 35 | 36 |
from gi.repository import Gdk
|
| 36 | 37 |
|
| 37 |
-from nbxmpp.namespaces import Namespace
|
|
| 38 |
+from nbxmpp import JID
|
|
| 38 | 39 |
from nbxmpp.const import Chatstate
|
| 40 |
+from nbxmpp.modules.security_labels import Displaymarking
|
|
| 41 |
+from nbxmpp.namespaces import Namespace
|
|
| 39 | 42 |
|
| 40 | 43 |
from gajim.common import app
|
| 41 | 44 |
from gajim.common import helpers
|
| ... | ... | @@ -80,14 +83,17 @@ class ChatControl(BaseControl): |
| 80 | 83 |
# processed with this command host.
|
| 81 | 84 |
COMMAND_HOST = ChatCommands # type: ClassVar[Type[CommandHost]]
|
| 82 | 85 |
|
| 83 |
- def __init__(self, account, jid):
|
|
| 86 |
+ def __init__(self, account: str, jid: JID) -> None:
|
|
| 84 | 87 |
BaseControl.__init__(self,
|
| 85 | 88 |
'chat_control',
|
| 86 | 89 |
account,
|
| 87 | 90 |
jid)
|
| 88 | 91 |
|
| 89 |
- self.last_recv_message_id = None
|
|
| 90 |
- self.last_recv_message_marks = None
|
|
| 92 |
+ self.sendmessage: bool = True
|
|
| 93 |
+ |
|
| 94 |
+ # XEP-0308 Message Correction
|
|
| 95 |
+ self.correcting: bool = False
|
|
| 96 |
+ self.last_sent_msg: Optional[str] = None
|
|
| 91 | 97 |
|
| 92 | 98 |
self.toggle_emoticons()
|
| 93 | 99 |
|
| ... | ... | @@ -147,7 +153,7 @@ def __init__(self, account, jid): |
| 147 | 153 |
app.plugin_manager.gui_extension_point('chat_control', self)
|
| 148 | 154 |
self.update_actions()
|
| 149 | 155 |
|
| 150 |
- def _connect_contact_signals(self):
|
|
| 156 |
+ def _connect_contact_signals(self) -> None:
|
|
| 151 | 157 |
self.contact.multi_connect({
|
| 152 | 158 |
'presence-update': self._on_presence_update,
|
| 153 | 159 |
'chatstate-update': self._on_chatstate_update,
|
| ... | ... | @@ -157,10 +163,10 @@ def _connect_contact_signals(self): |
| 157 | 163 |
})
|
| 158 | 164 |
|
| 159 | 165 |
@property
|
| 160 |
- def jid(self):
|
|
| 166 |
+ def jid(self) -> JID:
|
|
| 161 | 167 |
return self.contact.jid
|
| 162 | 168 |
|
| 163 |
- def add_actions(self):
|
|
| 169 |
+ def add_actions(self) -> None:
|
|
| 164 | 170 |
super().add_actions()
|
| 165 | 171 |
actions = [
|
| 166 | 172 |
('invite-contacts-', self._on_invite_contacts),
|
| ... | ... | @@ -194,7 +200,7 @@ def add_actions(self): |
| 194 | 200 |
act.connect('change-state', self._on_send_marker)
|
| 195 | 201 |
app.window.add_action(act)
|
| 196 | 202 |
|
| 197 |
- def update_actions(self):
|
|
| 203 |
+ def update_actions(self) -> None:
|
|
| 198 | 204 |
online = app.account_is_connected(self.account)
|
| 199 | 205 |
|
| 200 | 206 |
if self.type.is_chat:
|
| ... | ... | @@ -254,7 +260,7 @@ def update_actions(self): |
| 254 | 260 |
# Information
|
| 255 | 261 |
self._get_action('information-').set_enabled(online)
|
| 256 | 262 |
|
| 257 |
- def remove_actions(self):
|
|
| 263 |
+ def remove_actions(self) -> None:
|
|
| 258 | 264 |
super().remove_actions()
|
| 259 | 265 |
actions = [
|
| 260 | 266 |
'invite-contacts-',
|
| ... | ... | @@ -268,7 +274,7 @@ def remove_actions(self): |
| 268 | 274 |
for action in actions:
|
| 269 | 275 |
app.window.remove_action(f'{action}{self.control_id}')
|
| 270 | 276 |
|
| 271 |
- def focus(self):
|
|
| 277 |
+ def focus(self) -> None:
|
|
| 272 | 278 |
self.msg_textview.grab_focus()
|
| 273 | 279 |
|
| 274 | 280 |
def delegate_action(self, action):
|
| ... | ... | @@ -307,7 +313,7 @@ def _on_send_marker(self, action, param): |
| 307 | 313 |
action.set_state(param)
|
| 308 | 314 |
self.contact.settings.set('send_marker', param.get_boolean())
|
| 309 | 315 |
|
| 310 |
- def _update_toolbar(self):
|
|
| 316 |
+ def _update_toolbar(self) -> None:
|
|
| 311 | 317 |
# Formatting
|
| 312 | 318 |
# TODO: find out what encryption allows for xhtml and which not
|
| 313 | 319 |
if self.contact.supports(Namespace.XHTML_IM):
|
| ... | ... | @@ -319,13 +325,13 @@ def _update_toolbar(self): |
| 319 | 325 |
self.xml.formattings_button.set_tooltip_text(
|
| 320 | 326 |
_('This contact does not support HTML'))
|
| 321 | 327 |
|
| 322 |
- def update_all_pep_types(self):
|
|
| 328 |
+ def update_all_pep_types(self) -> None:
|
|
| 323 | 329 |
self._update_pep(PEPEventType.LOCATION)
|
| 324 | 330 |
self._update_pep(PEPEventType.MOOD)
|
| 325 | 331 |
self._update_pep(PEPEventType.ACTIVITY)
|
| 326 | 332 |
self._update_pep(PEPEventType.TUNE)
|
| 327 | 333 |
|
| 328 |
- def _update_pep(self, type_):
|
|
| 334 |
+ def _update_pep(self, type_: PEPEventType) -> None:
|
|
| 329 | 335 |
return
|
| 330 | 336 |
# TODO
|
| 331 | 337 |
image = self._get_pep_widget(type_)
|
| ... | ... | @@ -351,7 +357,7 @@ def _update_pep(self, type_): |
| 351 | 357 |
image.set_tooltip_markup(formated_text)
|
| 352 | 358 |
image.show()
|
| 353 | 359 |
|
| 354 |
- def _get_pep_widget(self, type_):
|
|
| 360 |
+ def _get_pep_widget(self, type_: PEPEventType) -> Optional[Gtk.Image]:
|
|
| 355 | 361 |
if type_ == PEPEventType.MOOD:
|
| 356 | 362 |
return self.xml.mood_image
|
| 357 | 363 |
if type_ == PEPEventType.ACTIVITY:
|
| ... | ... | @@ -488,7 +494,7 @@ def _nec_ping(self, event): |
| 488 | 494 |
self.add_info_message(event.error)
|
| 489 | 495 |
|
| 490 | 496 |
# Jingle AV calls
|
| 491 |
- def _on_start_call(self):
|
|
| 497 |
+ def _on_start_call(self) -> None:
|
|
| 492 | 498 |
self._call_widget.start_call()
|
| 493 | 499 |
|
| 494 | 500 |
def _process_jingle_av_event(self, event):
|
| ... | ... | @@ -527,14 +533,14 @@ def on_location_eventbox_enter_notify_event(self, _widget, _event): |
| 527 | 533 |
cursor = get_cursor('pointer')
|
| 528 | 534 |
app.window.get_window().set_cursor(cursor)
|
| 529 | 535 |
|
| 530 |
- def update_ui(self):
|
|
| 536 |
+ def update_ui(self) -> None:
|
|
| 531 | 537 |
# The name banner is drawn here
|
| 532 | 538 |
BaseControl.update_ui(self)
|
| 533 | 539 |
self.update_toolbar()
|
| 534 | 540 |
self._update_avatar()
|
| 535 | 541 |
self.update_actions()
|
| 536 | 542 |
|
| 537 |
- def draw_banner_text(self):
|
|
| 543 |
+ def draw_banner_text(self) -> None:
|
|
| 538 | 544 |
"""
|
| 539 | 545 |
Draws the chat banner's text (e.g. name, chat state) in the top of the
|
| 540 | 546 |
chat window
|
| ... | ... | @@ -572,10 +578,11 @@ def draw_banner_text(self): |
| 572 | 578 |
self.xml.banner_name_label.set_tooltip_text(label_tooltip)
|
| 573 | 579 |
|
| 574 | 580 |
def send_message(self,
|
| 575 |
- message,
|
|
| 576 |
- xhtml=None,
|
|
| 577 |
- process_commands=True,
|
|
| 578 |
- attention=False):
|
|
| 581 |
+ message: str,
|
|
| 582 |
+ xhtml: Optional[str] = None,
|
|
| 583 |
+ process_commands: bool = True,
|
|
| 584 |
+ attention: bool = False
|
|
| 585 |
+ ) -> None:
|
|
| 579 | 586 |
"""
|
| 580 | 587 |
Send a message to contact
|
| 581 | 588 |
"""
|
| ... | ... | @@ -598,19 +605,20 @@ def send_message(self, |
| 598 | 605 |
process_commands=process_commands,
|
| 599 | 606 |
attention=attention)
|
| 600 | 607 |
|
| 601 |
- def get_our_nick(self):
|
|
| 608 |
+ def get_our_nick(self) -> str:
|
|
| 602 | 609 |
return app.nicks[self.account]
|
| 603 | 610 |
|
| 604 | 611 |
def add_message(self,
|
| 605 |
- text,
|
|
| 606 |
- kind,
|
|
| 607 |
- tim=None,
|
|
| 608 |
- displaymarking=None,
|
|
| 609 |
- msg_log_id=None,
|
|
| 610 |
- stanza_id=None,
|
|
| 611 |
- message_id=None,
|
|
| 612 |
- additional_data=None,
|
|
| 613 |
- notify=True):
|
|
| 612 |
+ text: str,
|
|
| 613 |
+ kind: str,
|
|
| 614 |
+ tim: Optional[float] = None,
|
|
| 615 |
+ displaymarking: Optional[Displaymarking] = None,
|
|
| 616 |
+ msg_log_id: Optional[str] = None,
|
|
| 617 |
+ stanza_id: Optional[str] = None,
|
|
| 618 |
+ message_id: Optional[str] = None,
|
|
| 619 |
+ additional_data: Optional[AdditionalDataDict] = None,
|
|
| 620 |
+ notify: bool = True
|
|
| 621 |
+ ) -> None:
|
|
| 614 | 622 |
|
| 615 | 623 |
if additional_data is None:
|
| 616 | 624 |
additional_data = AdditionalDataDict()
|
| ... | ... | @@ -632,7 +640,7 @@ def add_message(self, |
| 632 | 640 |
stanza_id=stanza_id,
|
| 633 | 641 |
additional_data=additional_data)
|
| 634 | 642 |
|
| 635 |
- def shutdown(self):
|
|
| 643 |
+ def shutdown(self) -> None:
|
|
| 636 | 644 |
# PluginSystem: removing GUI extension points connected with ChatControl
|
| 637 | 645 |
# instance object
|
| 638 | 646 |
app.plugin_manager.remove_gui_extension_point('chat_control', self)
|
| ... | ... | @@ -682,7 +690,7 @@ def allow_shutdown(self, _method, on_yes, on_no): |
| 682 | 690 |
def _on_avatar_update(self, _contact, _signal_name):
|
| 683 | 691 |
self._update_avatar()
|
| 684 | 692 |
|
| 685 |
- def _update_avatar(self):
|
|
| 693 |
+ def _update_avatar(self) -> None:
|
|
| 686 | 694 |
scale = app.window.get_scale_factor()
|
| 687 | 695 |
surface = self.contact.get_avatar(AvatarSize.CHAT, scale)
|
| 688 | 696 |
self.xml.avatar_image.set_from_surface(surface)
|
| ... | ... | @@ -24,15 +24,21 @@ |
| 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 Any
|
|
| 28 |
+from typing import List
|
|
| 29 |
+from typing import Optional
|
|
| 30 |
+ |
|
| 27 | 31 |
import time
|
| 28 | 32 |
import logging
|
| 29 | 33 |
|
| 34 |
+from nbxmpp import JID
|
|
| 30 | 35 |
from nbxmpp.namespaces import Namespace
|
| 31 | 36 |
from nbxmpp.protocol import InvalidJid
|
| 32 | 37 |
from nbxmpp.protocol import validate_resourcepart
|
| 33 | 38 |
from nbxmpp.const import StatusCode
|
| 34 | 39 |
from nbxmpp.const import Affiliation
|
| 35 | 40 |
from nbxmpp.errors import StanzaError
|
| 41 |
+from nbxmpp.modules.security_labels import Displaymarking
|
|
| 36 | 42 |
from nbxmpp.modules.vcard_temp import VCard
|
| 37 | 43 |
|
| 38 | 44 |
from gi.repository import Gtk
|
| ... | ... | @@ -46,6 +52,7 @@ |
| 46 | 52 |
from gajim.common import app
|
| 47 | 53 |
from gajim.common import ged
|
| 48 | 54 |
from gajim.common import helpers
|
| 55 |
+from gajim.common.helpers import AdditionalDataDict
|
|
| 49 | 56 |
from gajim.common.helpers import event_filter
|
| 50 | 57 |
from gajim.common.helpers import to_user_string
|
| 51 | 58 |
from gajim.common.const import AvatarSize
|
| ... | ... | @@ -86,7 +93,7 @@ class GroupchatControl(BaseControl): |
| 86 | 93 |
# will be processed with this command host.
|
| 87 | 94 |
COMMAND_HOST = GroupChatCommands
|
| 88 | 95 |
|
| 89 |
- def __init__(self, account, jid):
|
|
| 96 |
+ def __init__(self, account: str, jid: JID) -> None:
|
|
| 90 | 97 |
BaseControl.__init__(self,
|
| 91 | 98 |
'groupchat_control',
|
| 92 | 99 |
account,
|
| ... | ... | @@ -95,23 +102,27 @@ def __init__(self, account, jid): |
| 95 | 102 |
self._client.connect_signal('state-changed',
|
| 96 | 103 |
self._on_client_state_changed)
|
| 97 | 104 |
|
| 98 |
- self.is_anonymous = True
|
|
| 105 |
+ self.is_anonymous: bool = True
|
|
| 99 | 106 |
|
| 100 | 107 |
self.toggle_emoticons()
|
| 101 | 108 |
|
| 102 |
- self.room_jid = str(self.contact.jid)
|
|
| 109 |
+ self.room_jid: str = str(self.contact.jid)
|
|
| 103 | 110 |
|
| 104 | 111 |
# Stores nickname we want to kick
|
| 105 |
- self._kick_nick = None
|
|
| 112 |
+ self._kick_nick: Optional[str] = None
|
|
| 106 | 113 |
|
| 107 | 114 |
# Stores nickname we want to ban
|
| 108 |
- self._ban_jid = None
|
|
| 115 |
+ self._ban_jid: Optional[str] = None
|
|
| 109 | 116 |
|
| 110 | 117 |
# Last sent message text
|
| 111 |
- self.last_sent_txt = ''
|
|
| 118 |
+ self.last_sent_txt: str = ''
|
|
| 112 | 119 |
|
| 113 | 120 |
# Attribute, encryption plugins use to signal the message can be sent
|
| 114 |
- self.sendmessage = False
|
|
| 121 |
+ self.sendmessage: bool = False
|
|
| 122 |
+ |
|
| 123 |
+ # XEP-0308 Message Correction
|
|
| 124 |
+ self.correcting: bool = False
|
|
| 125 |
+ self.last_sent_msg: Optional[str] = None
|
|
| 115 | 126 |
|
| 116 | 127 |
self.roster = GroupchatRoster(self.account, self.room_jid, self)
|
| 117 | 128 |
self.xml.roster_revealer.add(self.roster)
|
| ... | ... | @@ -126,13 +137,13 @@ def __init__(self, account, jid): |
| 126 | 137 |
|
| 127 | 138 |
# muc attention flag (when we are mentioned in a muc)
|
| 128 | 139 |
# if True, the room has mentioned us
|
| 129 |
- self.attention_flag = False
|
|
| 140 |
+ self.attention_flag: bool = False
|
|
| 130 | 141 |
|
| 131 | 142 |
# sorted list of nicks who mentioned us (last at the end)
|
| 132 |
- self.attention_list = []
|
|
| 133 |
- self.nick_hits = []
|
|
| 134 |
- self.__nick_completion = None
|
|
| 135 |
- self.last_key_tabs = False
|
|
| 143 |
+ self.attention_list: List[str] = []
|
|
| 144 |
+ self.nick_hits: List[str] = []
|
|
| 145 |
+ self.__nick_completion: Optional[NickCompletionGenerator] = None
|
|
| 146 |
+ self.last_key_tabs: bool = False
|
|
| 136 | 147 |
|
| 137 | 148 |
self.setup_seclabel()
|
| 138 | 149 |
|
| ... | ... | @@ -158,7 +169,7 @@ def __init__(self, account, jid): |
| 158 | 169 |
self._update_avatar()
|
| 159 | 170 |
|
| 160 | 171 |
# Holds CaptchaRequest widget
|
| 161 |
- self._captcha_request = None
|
|
| 172 |
+ self._captcha_request: Optional[DataFormWidget] = None
|
|
| 162 | 173 |
|
| 163 | 174 |
# MUC Info
|
| 164 | 175 |
self._subject_data = None
|
| ... | ... | @@ -166,7 +177,7 @@ def __init__(self, account, jid): |
| 166 | 177 |
self.xml.info_box.add(self._muc_info_box)
|
| 167 | 178 |
|
| 168 | 179 |
# Groupchat settings
|
| 169 |
- self._groupchat_settings_box = None
|
|
| 180 |
+ self._groupchat_settings_box: Optional[GroupChatSettings] = None
|
|
| 170 | 181 |
|
| 171 | 182 |
# Groupchat invite
|
| 172 | 183 |
self.xml.quick_invite_button.set_action_name(
|
| ... | ... | @@ -211,7 +222,7 @@ def __init__(self, account, jid): |
| 211 | 222 |
# instance object
|
| 212 | 223 |
app.plugin_manager.gui_extension_point('groupchat_control', self)
|
| 213 | 224 |
|
| 214 |
- def _connect_contact_signals(self):
|
|
| 225 |
+ def _connect_contact_signals(self) -> None:
|
|
| 215 | 226 |
self.contact.multi_connect({
|
| 216 | 227 |
'state-changed': self._on_muc_state_changed,
|
| 217 | 228 |
'avatar-update': self._on_avatar_update,
|
| ... | ... | @@ -260,7 +271,7 @@ def _nick_completion(self): |
| 260 | 271 |
return self.__nick_completion
|
| 261 | 272 |
|
| 262 | 273 |
@property
|
| 263 |
- def subject(self):
|
|
| 274 |
+ def subject(self) -> str:
|
|
| 264 | 275 |
if self._subject_data is None:
|
| 265 | 276 |
return ''
|
| 266 | 277 |
return self._subject_data.subject
|
| ... | ... | @@ -269,7 +280,7 @@ def subject(self): |
| 269 | 280 |
def disco_info(self):
|
| 270 | 281 |
return app.storage.cache.get_last_disco_info(self.contact.jid)
|
| 271 | 282 |
|
| 272 |
- def add_actions(self):
|
|
| 283 |
+ def add_actions(self) -> None:
|
|
| 273 | 284 |
super().add_actions()
|
| 274 | 285 |
actions = [
|
| 275 | 286 |
('groupchat-settings-', None, self._on_groupchat_settings),
|
| ... | ... | @@ -368,7 +379,7 @@ def update_actions(self, *args): |
| 368 | 379 |
|
| 369 | 380 |
self._get_action('kick-').set_enabled(joined)
|
| 370 | 381 |
|
| 371 |
- def remove_actions(self):
|
|
| 382 |
+ def remove_actions(self) -> None:
|
|
| 372 | 383 |
super().remove_actions()
|
| 373 | 384 |
actions = [
|
| 374 | 385 |
'groupchat-settings-',
|
| ... | ... | @@ -398,7 +409,7 @@ def is_irc(self) -> bool: |
| 398 | 409 |
return False
|
| 399 | 410 |
return self.disco_info.is_irc
|
| 400 | 411 |
|
| 401 |
- def _is_subject_change_allowed(self):
|
|
| 412 |
+ def _is_subject_change_allowed(self) -> Optional[Any]:
|
|
| 402 | 413 |
contact = self.contact.get_self()
|
| 403 | 414 |
if contact is None:
|
| 404 | 415 |
return False
|
| ... | ... | @@ -410,7 +421,7 @@ def _is_subject_change_allowed(self): |
| 410 | 421 |
return False
|
| 411 | 422 |
return self.disco_info.muc_subjectmod or False
|
| 412 | 423 |
|
| 413 |
- def _show_page(self, name):
|
|
| 424 |
+ def _show_page(self, name: str) -> None:
|
|
| 414 | 425 |
transition = Gtk.StackTransitionType.SLIDE_DOWN
|
| 415 | 426 |
if name == 'groupchat':
|
| 416 | 427 |
transition = Gtk.StackTransitionType.SLIDE_UP
|
| ... | ... | @@ -422,7 +433,7 @@ def _show_page(self, name): |
| 422 | 433 |
self.xml.info_close_button.grab_focus()
|
| 423 | 434 |
self.xml.stack.set_visible_child_full(name, transition)
|
| 424 | 435 |
|
| 425 |
- def _get_current_page(self):
|
|
| 436 |
+ def _get_current_page(self) -> str:
|
|
| 426 | 437 |
return self.xml.stack.get_visible_child_name()
|
| 427 | 438 |
|
| 428 | 439 |
def _on_muc_disco_update(self, _event):
|
| ... | ... | @@ -624,11 +635,11 @@ def _on_roster_row_activated(self, _roster, nick): |
| 624 | 635 |
def _on_avatar_update(self, _contact, _signal_name):
|
| 625 | 636 |
self._update_avatar()
|
| 626 | 637 |
|
| 627 |
- def _update_avatar(self):
|
|
| 638 |
+ def _update_avatar(self) -> None:
|
|
| 628 | 639 |
surface = self.contact.get_avatar(AvatarSize.CHAT, self.scale_factor)
|
| 629 | 640 |
self.xml.avatar_image.set_from_surface(surface)
|
| 630 | 641 |
|
| 631 |
- def draw_banner_text(self):
|
|
| 642 |
+ def draw_banner_text(self) -> None:
|
|
| 632 | 643 |
"""
|
| 633 | 644 |
Draw the text in the fat line at the top of the window that houses the
|
| 634 | 645 |
room jid
|
| ... | ... | @@ -702,14 +713,15 @@ def _on_gc_message_received(self, event): |
| 702 | 713 |
self._client.get_own_jid().bare)
|
| 703 | 714 |
|
| 704 | 715 |
def add_message(self,
|
| 705 |
- text,
|
|
| 706 |
- contact='',
|
|
| 707 |
- tim=None,
|
|
| 708 |
- displaymarking=None,
|
|
| 709 |
- message_id=None,
|
|
| 710 |
- stanza_id=None,
|
|
| 711 |
- additional_data=None,
|
|
| 712 |
- notify=True):
|
|
| 716 |
+ text: str,
|
|
| 717 |
+ contact: str = '',
|
|
| 718 |
+ tim: Optional[float] = None,
|
|
| 719 |
+ displaymarking: Optional[Displaymarking] = None,
|
|
| 720 |
+ message_id: Optional[str] = None,
|
|
| 721 |
+ stanza_id: Optional[str] = None,
|
|
| 722 |
+ additional_data: Optional[AdditionalDataDict] = None,
|
|
| 723 |
+ notify: bool = True
|
|
| 724 |
+ ) -> None:
|
|
| 713 | 725 |
|
| 714 | 726 |
if contact == self.contact.nickname:
|
| 715 | 727 |
kind = 'outgoing'
|
| ... | ... | @@ -809,7 +821,7 @@ def _nec_ping(self, event): |
| 809 | 821 |
elif event.name == 'ping-error':
|
| 810 | 822 |
self.add_info_message(event.error)
|
| 811 | 823 |
|
| 812 |
- def _set_control_active(self):
|
|
| 824 |
+ def _set_control_active(self) -> None:
|
|
| 813 | 825 |
self.xml.formattings_button.set_sensitive(True)
|
| 814 | 826 |
self.msg_textview.set_sensitive(True)
|
| 815 | 827 |
self.msg_textview.set_editable(True)
|
| ... | ... | @@ -822,7 +834,7 @@ def _set_control_active(self): |
| 822 | 834 |
|
| 823 | 835 |
self.update_actions()
|
| 824 | 836 |
|
| 825 |
- def _set_control_inactive(self):
|
|
| 837 |
+ def _set_control_inactive(self) -> None:
|
|
| 826 | 838 |
self.xml.formattings_button.set_sensitive(False)
|
| 827 | 839 |
self.msg_textview.set_sensitive(False)
|
| 828 | 840 |
self.msg_textview.set_editable(False)
|
| ... | ... | @@ -834,7 +846,7 @@ def _set_control_inactive(self): |
| 834 | 846 |
|
| 835 | 847 |
self.update_actions()
|
| 836 | 848 |
|
| 837 |
- def rejoin(self):
|
|
| 849 |
+ def rejoin(self) -> None:
|
|
| 838 | 850 |
self._client.get_module('MUC').join(self.room_jid)
|
| 839 | 851 |
|
| 840 | 852 |
# def send_pm(self, nick, message=None):
|
| ... | ... | @@ -1115,7 +1127,11 @@ def _on_message_sent(self, event): |
| 1115 | 1127 |
self.msg_textview.get_style_context().remove_class(
|
| 1116 | 1128 |
'gajim-msg-correcting')
|
| 1117 | 1129 |
|
| 1118 |
- def send_message(self, message, xhtml=None, process_commands=True):
|
|
| 1130 |
+ def send_message(self,
|
|
| 1131 |
+ message: str,
|
|
| 1132 |
+ xhtml: Optional[str] = None,
|
|
| 1133 |
+ process_commands: bool = True
|
|
| 1134 |
+ ) -> None:
|
|
| 1119 | 1135 |
"""
|
| 1120 | 1136 |
Call this function to send our message
|
| 1121 | 1137 |
"""
|
| ... | ... | @@ -1182,7 +1198,7 @@ def shutdown(self, reason=None): |
| 1182 | 1198 |
super(GroupchatControl, self).shutdown()
|
| 1183 | 1199 |
app.check_finalize(self)
|
| 1184 | 1200 |
|
| 1185 |
- def safe_shutdown(self):
|
|
| 1201 |
+ def safe_shutdown(self) -> bool:
|
|
| 1186 | 1202 |
# whether to ask for confirmation before closing muc
|
| 1187 | 1203 |
if app.settings.get('confirm_close_muc') and self.contact.is_joined:
|
| 1188 | 1204 |
return False
|
| ... | ... | @@ -1219,12 +1235,12 @@ def on_cancel(is_checked): |
| 1219 | 1235 |
|
| 1220 | 1236 |
on_yes(self)
|
| 1221 | 1237 |
|
| 1222 |
- def _close_control(self):
|
|
| 1238 |
+ def _close_control(self) -> None:
|
|
| 1223 | 1239 |
app.window.activate_action(
|
| 1224 | 1240 |
'remove-chat',
|
| 1225 | 1241 |
GLib.Variant('as', [self.account, str(self.room_jid)]))
|
| 1226 | 1242 |
|
| 1227 |
- def set_control_active(self, state):
|
|
| 1243 |
+ def set_control_active(self, state: bool) -> None:
|
|
| 1228 | 1244 |
self.attention_flag = False
|
| 1229 | 1245 |
BaseControl.set_control_active(self, state)
|
| 1230 | 1246 |
|
| ... | ... | @@ -1396,7 +1412,7 @@ def delegate_action(self, action): |
| 1396 | 1412 |
|
| 1397 | 1413 |
return Gdk.EVENT_PROPAGATE
|
| 1398 | 1414 |
|
| 1399 |
- def focus(self):
|
|
| 1415 |
+ def focus(self) -> None:
|
|
| 1400 | 1416 |
page_name = self._get_current_page()
|
| 1401 | 1417 |
if page_name == 'groupchat':
|
| 1402 | 1418 |
self.msg_textview.grab_focus()
|
| ... | ... | @@ -1547,7 +1563,7 @@ def _on_room_captcha_error(self, _contact, _signal_name, error): |
| 1547 | 1563 |
self.xml.captcha_error_label.set_text(error_text)
|
| 1548 | 1564 |
self._show_page('captcha-error')
|
| 1549 | 1565 |
|
| 1550 |
- def _remove_captcha_request(self):
|
|
| 1566 |
+ def _remove_captcha_request(self) -> None:
|
|
| 1551 | 1567 |
if self._captcha_request is None:
|
| 1552 | 1568 |
return
|
| 1553 | 1569 |
if self._captcha_request in self.xml.captcha_box.get_children():
|
| ... | ... | @@ -24,6 +24,10 @@ |
| 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 Optional
|
|
| 28 |
+ |
|
| 29 |
+from nbxmpp import JID
|
|
| 30 |
+ |
|
| 27 | 31 |
from gajim.common import app
|
| 28 | 32 |
from gajim.common import helpers
|
| 29 | 33 |
from gajim.common.i18n import _
|
| ... | ... | @@ -43,7 +47,7 @@ class PrivateChatControl(ChatControl): |
| 43 | 47 |
# will be processed with this command host.
|
| 44 | 48 |
COMMAND_HOST = PrivateChatCommands
|
| 45 | 49 |
|
| 46 |
- def __init__(self, account, jid):
|
|
| 50 |
+ def __init__(self, account: str, jid: JID) -> None:
|
|
| 47 | 51 |
self._client = app.get_client(account)
|
| 48 | 52 |
self._room_contact = self._client.get_module('Contacts').get_contact(
|
| 49 | 53 |
jid.bare)
|
| ... | ... | @@ -53,7 +57,7 @@ def __init__(self, account, jid): |
| 53 | 57 |
# self.register_events([
|
| 54 | 58 |
# ('update-gc-avatar', ged.GUI1, self._on_update_gc_avatar),
|
| 55 | 59 |
|
| 56 |
- def _connect_contact_signals(self):
|
|
| 60 |
+ def _connect_contact_signals(self) -> None:
|
|
| 57 | 61 |
self.contact.multi_connect({
|
| 58 | 62 |
'user-avatar-update': self._on_user_avatar_update,
|
| 59 | 63 |
'user-joined': self._on_user_joined,
|
| ... | ... | @@ -68,10 +72,10 @@ def _connect_contact_signals(self): |
| 68 | 72 |
})
|
| 69 | 73 |
|
| 70 | 74 |
@property
|
| 71 |
- def room_name(self):
|
|
| 75 |
+ def room_name(self) -> str:
|
|
| 72 | 76 |
return self._room_contact.name
|
| 73 | 77 |
|
| 74 |
- def get_our_nick(self):
|
|
| 78 |
+ def get_our_nick(self) -> str:
|
|
| 75 | 79 |
muc_data = self._client.get_module('MUC').get_muc_data(
|
| 76 | 80 |
self._room_contact.jid)
|
| 77 | 81 |
return muc_data.nick
|
| ... | ... | @@ -136,8 +140,12 @@ def _on_room_joined(self, *args): |
| 136 | 140 |
return
|
| 137 | 141 |
self.got_connected()
|
| 138 | 142 |
|
| 139 |
- def send_message(self, message, xhtml=None, process_commands=True,
|
|
| 140 |
- attention=False):
|
|
| 143 |
+ def send_message(self,
|
|
| 144 |
+ message: str,
|
|
| 145 |
+ xhtml: Optional[str] = None,
|
|
| 146 |
+ process_commands: bool = True,
|
|
| 147 |
+ attention: bool = False
|
|
| 148 |
+ ) -> None:
|
|
| 141 | 149 |
"""
|
| 142 | 150 |
Call this method to send the message
|
| 143 | 151 |
"""
|
| ... | ... | @@ -161,7 +169,7 @@ def send_message(self, message, xhtml=None, process_commands=True, |
| 161 | 169 |
process_commands=process_commands,
|
| 162 | 170 |
attention=attention)
|
| 163 | 171 |
|
| 164 |
- def update_ui(self):
|
|
| 172 |
+ def update_ui(self) -> None:
|
|
| 165 | 173 |
ChatControl.update_ui(self)
|
| 166 | 174 |
|
| 167 | 175 |
def _on_user_avatar_update(self, *args):
|
| ... | ... | @@ -14,6 +14,7 @@ |
| 14 | 14 |
from gajim.common import app
|
| 15 | 15 |
from gajim.common import ged
|
| 16 | 16 |
from gajim.common.const import Display
|
| 17 |
+from gajim.common.const import Direction
|
|
| 17 | 18 |
from gajim.common.helpers import ask_for_status_message
|
| 18 | 19 |
from gajim.common.i18n import _
|
| 19 | 20 |
from gajim.common.nec import EventHelper
|
| ... | ... | @@ -260,19 +261,19 @@ def _on_action(self, action, _param): |
| 260 | 261 |
# return None
|
| 261 | 262 |
|
| 262 | 263 |
if action == 'switch-next-tab':
|
| 263 |
- self.select_next_chat(True)
|
|
| 264 |
+ self.select_next_chat(Direction.NEXT)
|
|
| 264 | 265 |
return None
|
| 265 | 266 |
|
| 266 | 267 |
if action == 'switch-prev-tab':
|
| 267 |
- self.select_next_chat(False)
|
|
| 268 |
+ self.select_next_chat(Direction.PREV)
|
|
| 268 | 269 |
return None
|
| 269 | 270 |
|
| 270 | 271 |
if action == 'switch-next-unread-tab-right':
|
| 271 |
- self.select_next_chat(True, unread_first=True)
|
|
| 272 |
+ self.select_next_chat(Direction.NEXT, unread_first=True)
|
|
| 272 | 273 |
return None
|
| 273 | 274 |
|
| 274 | 275 |
if action == 'switch-next-unread-tab-left':
|
| 275 |
- self.select_next_chat(False, unread_first=True)
|
|
| 276 |
+ self.select_next_chat(Direction.PREV, unread_first=True)
|
|
| 276 | 277 |
return None
|
| 277 | 278 |
|
| 278 | 279 |
if action.startswith('switch-tab-'):
|
| ... | ... | @@ -443,12 +444,12 @@ def select_chat(self, account: str, jid: JID) -> None: |
| 443 | 444 |
self._main_stack.show_chat_page()
|
| 444 | 445 |
self._chat_page.select_chat(account, jid)
|
| 445 | 446 |
|
| 446 |
- def select_next_chat(self, forwards: bool,
|
|
| 447 |
+ def select_next_chat(self, direction: Direction,
|
|
| 447 | 448 |
unread_first: bool = False) -> None:
|
| 448 | 449 |
chat_list_stack = self._chat_page.get_chat_list_stack()
|
| 449 | 450 |
chat_list = chat_list_stack.get_current_chat_list()
|
| 450 | 451 |
if chat_list is not None:
|
| 451 |
- chat_list.select_next_chat(forwards, unread_first)
|
|
| 452 |
+ chat_list.select_next_chat(direction, unread_first)
|
|
| 452 | 453 |
|
| 453 | 454 |
def select_chat_number(self, number: int) -> None:
|
| 454 | 455 |
chat_list_stack = self._chat_page.get_chat_list_stack()
|