Daniel Brötzmann pushed to branch master at gajim / gajim
Commits: 0ebc5ff9 by wurstsalat at 2022-01-07T23:51:53+01:00 BaseControl: Typing
- - - - - 020ae6f1 by wurstsalat at 2022-01-07T23:52:21+01:00 Types: Add BaseControl to ControlType
- - - - - bd8d0a97 by wurstsalat at 2022-01-07T23:53:33+01:00 Notifications: Use AvatarSize const
- - - - - d161c1f0 by wurstsalat at 2022-01-07T23:55:10+01:00 GUI Interface: Typing
- - - - -
4 changed files:
- gajim/gtk/controls/base.py - gajim/gtk/notification.py - gajim/gtk/types.py - gajim/gui_interface.py
Changes:
===================================== gajim/gtk/controls/base.py ===================================== @@ -114,7 +114,7 @@ class BaseControl(ChatCommandProcessor, CommandTools, EventHelper): A base class containing a banner, ConversationView, MessageInputTextView """
- _type = None # type: ControlType + _type: Optional[ControlType] = None
def __init__(self, widget_name: str, account: str, jid: JID) -> None: EventHelper.__init__(self) @@ -208,7 +208,7 @@ def __init__(self, widget_name: str, account: str, jid: JID) -> None: self.msg_textview.connect('key-press-event', self._on_message_textview_key_press_event) self.msg_textview.connect('populate-popup', - self.on_msg_textview_populate_popup) + self._on_msg_textview_populate_popup) self.msg_textview.get_buffer().connect( 'changed', self._on_message_tv_buffer_changed)
@@ -255,7 +255,7 @@ def __init__(self, widget_name: str, account: str, jid: JID) -> None:
# XEP-0172 User Nickname # TODO: - self.user_nick = None + self.user_nick: Optional[str] = None
self.command_hits: List[str] = [] self.last_key_tabs: bool = False @@ -264,7 +264,7 @@ def __init__(self, widget_name: str, account: str, jid: JID) -> None:
self._client.get_module('Chatstate').set_active(self.contact)
- self.encryption = self.get_encryption_state() + self.encryption: Optional[str] = self.get_encryption_state() self.conversation_view.encryption_enabled = self.encryption is not None
# PluginSystem: adding GUI extension point for BaseControl @@ -283,10 +283,10 @@ def __init__(self, widget_name: str, account: str, jid: JID) -> None: # to properly use the super, because of the old code. CommandTools.__init__(self)
- def _connect_contact_signals(self): + def _connect_contact_signals(self) -> None: raise NotImplementedError
- def _get_action(self, name: str) -> Gio.Action: + def _get_action(self, name: str) -> Gio.SimpleAction: return app.window.lookup_action(f'{name}{self.control_id}')
def process_event(self, event): @@ -329,7 +329,10 @@ def _on_message_updated(self, event): self.conversation_view.show_message_retraction( event.properties.moderation.stanza_id, text)
- def _on_conversation_view_key_press(self, _listbox, event): + def _on_conversation_view_key_press(self, + _listbox: ConversationView, + event: Gdk.EventKey + ) -> int: if event.get_state() & Gdk.ModifierType.SHIFT_MASK: if event.keyval in (Gdk.KEY_Page_Down, Gdk.KEY_Page_Up): return Gdk.EVENT_PROPAGATE @@ -395,7 +398,7 @@ def allow_shutdown(self, method, on_response_yes, on_response_no): """ on_response_yes(self)
- def focus(self): + def focus(self) -> None: raise NotImplementedError
def draw_banner(self) -> None: @@ -432,22 +435,11 @@ def repaint_themed_widgets(self) -> None: """ self.draw_banner()
- def _update_toolbar(self): + def _update_toolbar(self) -> None: """ Derived types MAY implement this """
- def get_tab_label(self, chatstate): - """ - Return a suitable tab label string. Returns a tuple such as: (label_str, - color) either of which can be None if chatstate is given that means we - have HE SENT US a chatstate and we want it displayed - - Derivded classes MUST implement this. - """ - # Return a markup'd label and optional Gtk.Color in a tuple like: - # return (label_str, None) - def set_session(self, session): oldsession = None if hasattr(self, 'session'): @@ -577,7 +569,10 @@ def mark_as_read(self, send_marker: bool = True) -> None: self._type) self.last_msg_id = None
- def change_encryption(self, action, param): + def change_encryption(self, + action: Gio.SimpleAction, + param: GLib.Variant + ) -> None: encryption = param.get_string() if encryption == 'disabled': encryption = None @@ -622,16 +617,16 @@ def set_lock_image(self) -> None: self.xml.authentication_button.set_visible(visible) self.xml.lock_image.set_sensitive(visible)
- def _on_authentication_button_clicked(self, _button): + def _on_authentication_button_clicked(self, _button: Gtk.Button) -> None: app.plugin_manager.extension_point( 'encryption_dialog' + self.encryption, self)
- def set_encryption_state(self, encryption): + def set_encryption_state(self, encryption: Optional[str]) -> None: self.encryption = encryption self.conversation_view.encryption_enabled = encryption is not None self.contact.settings.set('encryption', self.encryption or '')
- def get_encryption_state(self): + def get_encryption_state(self) -> Optional[str]: state = self.contact.settings.get('encryption') if not state: return None @@ -668,7 +663,7 @@ def set_speller(self) -> None:
spell_checker.connect('notify::language', self.on_language_changed)
- def get_speller_language(self): + def get_speller_language(self) -> Optional[Gspell.Language]: lang = self.contact.settings.get('speller_language') if not lang: # use the default one @@ -680,7 +675,7 @@ def get_speller_language(self): gspell_lang = Gspell.language_get_default() return gspell_lang
- def on_language_changed(self, checker, _param): + def on_language_changed(self, checker: Gspell.Checker, _param: Any) -> None: gspell_lang = checker.get_language() self.contact.settings.set('speller_language', gspell_lang.get_code())
@@ -716,7 +711,10 @@ def shutdown(self) -> None:
self.unregister_events()
- def on_msg_textview_populate_popup(self, _textview, menu): + def _on_msg_textview_populate_popup(self, + _textview: MessageInputTextView, + menu: Gtk.Widget + ) -> None: """ Override the default context menu and we prepend an option to switch languages @@ -754,17 +752,19 @@ def paste_clipboard_as_quote(self, _item: Gtk.MenuItem) -> None: return self.insert_as_quote(text)
- def on_quote(self, _widget, text): + def on_quote(self, _widget: Gtk.Widget, text: str) -> None: self.insert_as_quote(text)
- def on_mention(self, _widget, name): + def on_mention(self, _widget: Gtk.Widget, name: str) -> None: gc_refer_to_nick_char = app.settings.get('gc_refer_to_nick_char') text = f'{name}{gc_refer_to_nick_char} ' message_buffer = self.msg_textview.get_buffer() message_buffer.insert_at_cursor(text) GLib.idle_add(self.msg_textview.grab_focus)
- def _on_message_textview_paste_event(self, _texview): + def _on_message_textview_paste_event(self, + _texview: MessageInputTextView + ) -> None: clipboard = Gtk.Clipboard.get(Gdk.SELECTION_CLIPBOARD) image = clipboard.wait_for_image() if image is not None: @@ -824,7 +824,7 @@ def _get_pref_ft_method(self) -> Optional[str]: return 'jingle' return None
- def _start_filetransfer(self, path): + def _start_filetransfer(self, path: str) -> None: method = self._get_pref_ft_method() if method is None: return @@ -836,7 +836,10 @@ def _start_filetransfer(self, path): app.interface.instances['file_transfers'].send_file( self.account, self.contact, path)
- def _on_send_file(self, action, _param): + def _on_send_file(self, + action: Gio.SimpleAction, + _param: Optional[GLib.Variant] + ) -> None: name = action.get_name() if 'httpupload' in name: app.interface.send_httpupload(self) @@ -857,7 +860,10 @@ def _on_send_file(self, action, _param): app.interface.instances['file_transfers'].show_file_send_request( self.account, self.contact)
- def _on_message_textview_key_press_event(self, textview, event): + def _on_message_textview_key_press_event(self, + textview: MessageInputTextView, + event: Gdk.EventKey + ) -> bool: # pylint: disable=too-many-nested-blocks if event.keyval == Gdk.KEY_space: self.space_pressed = True @@ -978,7 +984,10 @@ def _on_message_textview_key_press_event(self, textview, event):
return False
- def _on_autoscroll_changed(self, _widget, autoscroll): + def _on_autoscroll_changed(self, + _widget: ScrolledView, + autoscroll: bool + ) -> None: if not autoscroll: self._jump_to_end_button.toggle(True) return @@ -986,23 +995,41 @@ def _on_autoscroll_changed(self, _widget, autoscroll): self._jump_to_end_button.toggle(False) app.window.mark_as_read(self.account, self.contact.jid)
- def _on_jump_to_end(self, _button): + def _on_jump_to_end(self, _button: Gtk.Button) -> None: self.scroll_to_end(force=True) self._jump_to_end_button.reset_unread_count()
- def _on_drag_data_received(self, widget, context, x_coord, y_coord, - selection, target_type, timestamp): + def _on_drag_data_received(self, + widget: Gtk.Widget, + context: Gdk.DragContext, + x_coord: int, + y_coord: int, + selection: Gtk.SelectionData, + target_type: int, + timestamp: int + ) -> None: """ Derived types SHOULD implement this """
- def _on_drag_leave(self, *args): + def _on_drag_leave(self, + _widget: Gtk.Widget, + _context: Gdk.DragContext, + _time: int + ) -> None: self.xml.drop_area.set_no_show_all(True) self.xml.drop_area.hide()
- def _on_drag_motion(self, *args): + def _on_drag_motion(self, + _widget: Gtk.Widget, + _context: Gdk.DragContext, + _x_coord: int, + _y_coord: int, + _time: int + ) -> bool: self.xml.drop_area.set_no_show_all(False) self.xml.drop_area.show_all() + return True
def drag_data_file_transfer(self, selection: Gtk.SelectionData) -> None: # we may have more than one file dropped @@ -1017,7 +1044,7 @@ def drag_data_file_transfer(self, selection: Gtk.SelectionData) -> None:
self._start_filetransfer(path)
- def get_seclabel(self): + def get_seclabel(self) -> Optional[str]: idx = self.xml.label_selector.get_active() if idx == -1: return None @@ -1032,7 +1059,7 @@ def get_seclabel(self): def get_our_nick(self) -> str: return app.nicks[self.account]
- def _on_send_message(self, *args): + def _on_send_message(self, *args: Any) -> None: self.msg_textview.replace_emojis() message = self.msg_textview.get_text() self.send_message(message) @@ -1086,7 +1113,9 @@ def send_message(self,
self.msg_textview.clear()
- def _on_message_tv_buffer_changed(self, textbuffer): + def _on_message_tv_buffer_changed(self, + textbuffer: Gtk.TextBuffer + ) -> None: has_text = self.msg_textview.has_text() app.window.lookup_action( f'send-message-{self.control_id}').set_enabled(has_text) @@ -1095,7 +1124,8 @@ def _on_message_tv_buffer_changed(self, textbuffer): app.plugin_manager.extension_point( 'typing' + self.encryption, self)
- self._client.get_module('Chatstate').set_keyboard_activity(self.contact) + self._client.get_module('Chatstate').set_keyboard_activity( + self.contact) if not has_text: self._client.get_module('Chatstate').set_chatstate_delayed( self.contact, Chatstate.ACTIVE) @@ -1301,7 +1331,7 @@ def set_emoticon_popover(self) -> None: self.xml.emoticons_button.connect('clicked', self._on_emoticon_button_clicked)
- def _on_emoticon_button_clicked(self, _widget): + def _on_emoticon_button_clicked(self, _widget: Gtk.Button) -> None: # Present GTK emoji chooser (not cross platform compatible) self.msg_textview.emit('insert-emoji') self.xml.emoticons_button.set_property('active', False) @@ -1315,7 +1345,7 @@ def _on_formatting_menuitem_activate(self, def _style_changed(self, *args): self.update_text_tags()
- def update_text_tags(self): + def update_text_tags(self) -> None: self.conversation_view.update_text_tags()
def set_control_active(self, state: bool) -> None:
===================================== gajim/gtk/notification.py ===================================== @@ -42,6 +42,7 @@ from gajim.common import app from gajim.common import ged from gajim.common import events +from gajim.common.const import AvatarSize from gajim.common.const import StyleAttr from gajim.common.i18n import _ from gajim.common.helpers import allow_showing_notification @@ -239,7 +240,8 @@ def _get_avatar_for_notification(account: str, scale = get_monitor_scale_factor() client = app.get_client(account) contact = client.get_module('Contacts').get_contact(jid) - return app.interface.get_avatar(contact, 32, scale, pixbuf=True) + return app.interface.get_avatar( + contact, AvatarSize.NOTIFICATION, scale, pixbuf=True)
def _on_popup_destroy(self, *args): self._win32_active_popup = None
===================================== gajim/gtk/types.py ===================================== @@ -18,6 +18,7 @@ from typing import TYPE_CHECKING
if TYPE_CHECKING: + from .controls.base import BaseControl from .controls.chat import ChatControl from .controls.private import PrivateChatControl from .controls.groupchat import GroupchatControl @@ -38,6 +39,7 @@
ControlType = Union [ + 'BaseControl', 'ChatControl', 'PrivateChatControl', 'GroupchatControl'
===================================== gajim/gui_interface.py ===================================== @@ -57,32 +57,38 @@ from nbxmpp import Hashes2 from nbxmpp import JID
-from gajim.common import app -from gajim.common.dbus import logind -from gajim.common.dbus import music_track -from gajim.common.events import AccountDisabled, AccountEnabled, FileCompleted, FileHashError -from gajim.common.events import FileProgress -from gajim.common.events import FileError - -from gajim.gui import menus from gajim.dialog_messages import get_dialog
+from gajim.common import app +from gajim.common import ged +from gajim.common import exceptions from gajim.common import idle -from gajim.common.zeroconf import connection_zeroconf from gajim.common import proxy65_manager from gajim.common import socks5 from gajim.common import helpers from gajim.common import passwords + +from gajim.common.dbus import logind +from gajim.common.dbus import music_track +from gajim.common.events import AccountEnabled +from gajim.common.events import AccountDisabled +from gajim.common.events import FileCompleted +from gajim.common.events import FileHashError +from gajim.common.events import FileProgress +from gajim.common.events import FileError +from gajim.common.zeroconf import connection_zeroconf from gajim.common.helpers import ask_for_status_message from gajim.common.structs import OutgoingMessage from gajim.common.i18n import _ from gajim.common.client import Client from gajim.common.preview import PreviewManager -from gajim.common.const import Display +from gajim.common.const import Display, FTState from gajim.common.file_props import FileProp
-from gajim.common import ged -from gajim.common import exceptions +from gajim.common.modules.contacts import GroupchatContact +from gajim.common.modules.contacts import GroupchatParticipant +from gajim.common.modules.contacts import BareContact +from gajim.common.modules.httpupload import HTTPFileTransfer
from gajim.gui.avatar import AvatarStorage from gajim.gui.notification import Notification @@ -95,13 +101,17 @@ from gajim.gui.filechoosers import FileChooserDialog from gajim.gui.filetransfer import FileTransfersWindow from gajim.gui.main import MainWindow +from gajim.gui.menus import build_accounts_menu from gajim.gui.util import get_app_window from gajim.gui.util import get_app_windows from gajim.gui.util import get_color_for_account from gajim.gui.util import open_window +from gajim.gui.types import ControlType
log = logging.getLogger('gajim.interface')
+ContactT = Union[BareContact, GroupchatContact, GroupchatParticipant] +
class Interface: def __init__(self): @@ -189,7 +199,7 @@ def __init__(self): self._network_status_changed) self._network_state: bool = self._network_monitor.get_network_available()
- def _create_core_handlers_list(self): + def _create_core_handlers_list(self) -> None: # pylint: disable=line-too-long self.handlers = { 'information': [self.handle_event_information], @@ -209,7 +219,7 @@ def _create_core_handlers_list(self): } # pylint: enable=line-too-long
- def _register_core_handlers(self): + def _register_core_handlers(self) -> None: """ Register core handlers in Global Events Dispatcher (GED).
@@ -297,7 +307,7 @@ def handle_event_plain_connection(event): @staticmethod def handle_event_http_auth(event): # ('HTTP_AUTH', account, (method, url, transaction_id, iq_obj, msg)) - def _response(_account, answer): + def _response(answer: str) -> None: event.conn.get_module('HTTPAuth').build_http_auth_answer( event.stanza, answer)
@@ -321,10 +331,10 @@ def _response(_account, answer): [DialogButton.make('Cancel', text=_('_No'), callback=_response, - args=[event, 'no']), + args=['no']), DialogButton.make('Accept', callback=_response, - args=[event, 'yes'])]).show() + args=['yes'])]).show()
@staticmethod def handle_event_client_cert_passphrase(event): @@ -588,7 +598,10 @@ def __compare_hashes(account: str, file_props: FileProp) -> None: if session: session.end_session()
- def send_httpupload(self, chat_control, path=None): + def send_httpupload(self, + chat_control: ControlType, + path: Optional[str] = None + ) -> None: if path is not None: self._send_httpupload(chat_control, path) return @@ -598,11 +611,14 @@ def send_httpupload(self, chat_control, path=None): select_multiple=True, transient_for=app.window)
- def _on_file_dialog_ok(self, chat_control, paths): + def _on_file_dialog_ok(self, + chat_control: ControlType, + paths: list[str] + ) -> None: for path in paths: self._send_httpupload(chat_control, path)
- def _send_httpupload(self, chat_control, path): + def _send_httpupload(self, chat_control: ControlType, path: str) -> None: client = app.get_client(chat_control.account) try: transfer = client.get_module('HTTPUpload').make_transfer( @@ -620,7 +636,11 @@ def _send_httpupload(self, chat_control, path): chat_control.add_file_transfer(transfer) client.get_module('HTTPUpload').start_transfer(transfer)
- def _on_http_upload_state_changed(self, transfer, _signal_name, state): + def _on_http_upload_state_changed(self, + transfer: HTTPFileTransfer, + _signal_name: str, + state: FTState + ) -> None: # Note: This has to be a bound method in order to connect the signal if state.is_finished: uri = transfer.get_transformed_uri() @@ -638,7 +658,10 @@ def _on_http_upload_state_changed(self, transfer, _signal_name, state): client = app.get_client(transfer.account) client.send_message(message)
- def _on_cancel_upload(self, transfer, _signal_name): + def _on_cancel_upload(self, + transfer: HTTPFileTransfer, + _signal_name: str + ) -> None: # Note: This has to be a bound method in order to connect the signal client = app.get_client(transfer.account) client.get_module('HTTPUpload').cancel_transfer(transfer) @@ -648,7 +671,7 @@ def create_groupchat(account: str, room_jid: str, config: Dict[str, Union[str, bool]] ) -> None: - if app.window.chat_exists(account, room_jid): + if app.window.chat_exists(account, JID.from_string(room_jid)): log.error('Trying to create groupchat ' 'which is already added as chat') return @@ -667,18 +690,18 @@ def show_add_join_groupchat(account: str, client.get_module('MUC').join( jid, nick=nickname, password=password)
- app.window.add_group_chat(account, jid, select=True) + app.window.add_group_chat(account, JID.from_string(jid), select=True)
@staticmethod def start_chat_from_jid(account: str, jid: str, message: Optional[str] = None ) -> None: - jid = JID.from_string(jid) - if app.window.chat_exists(account, jid): - app.window.select_chat(account, jid) + jid_ = JID.from_string(jid) + if app.window.chat_exists(account, jid_): + app.window.select_chat(account, jid_) if message is not None: - control = app.window.get_control(account, jid) + control = app.window.get_control(account, jid_) if control is None: return control.msg_textview.insert_text(message) @@ -779,7 +802,7 @@ def enable_account(self, account: str) -> None: app.block_signed_in_notifications[account] = True
app.settings.set_account_setting(account, 'active', True) - menus.build_accounts_menu() + build_accounts_menu() app.app.update_app_actions_state()
app.ged.raise_event(AccountEnabled(account=account)) @@ -799,7 +822,7 @@ def disable_account(self, account: str) -> None:
app.settings.set_account_setting(account, 'roster_version', '') app.settings.set_account_setting(account, 'active', False) - menus.build_accounts_menu() + build_accounts_menu() app.app.update_app_actions_state()
app.ged.raise_event(AccountDisabled(account=account)) @@ -954,12 +977,12 @@ def save_avatar(self, data: bytes) -> Optional[str]: return self.avatar_storage.save_avatar(data)
def get_avatar(self, - contact, - size, - scale, - show=None, - pixbuf=False, - style='circle'): + contact: ContactT, + size: int, + scale: int, + show: Optional[str] = None, + pixbuf: bool = False, + style: str = 'circle'): if pixbuf: return self.avatar_storage.get_pixbuf( contact, size, scale, show, style=style) @@ -1010,7 +1033,10 @@ def _on_delete(win, _event): view.updateNamespace({'gajim': app}) app.ipython_window = window
- def _network_status_changed(self, monitor, _param): + def _network_status_changed(self, + monitor: Gio.NetworkMonitor, + _network_available: bool + ) -> None: connected = monitor.get_network_available() if connected == self._network_state: return
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/0b5f4816d6ea99fda06de73778fc4a02...