Philipp Hörist pushed to branch master at gajim / gajim
Commits: bf07c0ba by lovetox at 2020-08-14T00:22:48+02:00 Refactor publishing Mood/Activity
- Move publish code to Interface module
- - - - - 0d880cb1 by lovetox at 2020-08-14T00:23:31+02:00 Refactor TimeoutWindow
- Remove source when timeout is stopped - Adapt StatusChange dialog
- - - - - b2d52ad5 by lovetox at 2020-08-14T00:23:38+02:00 Refactor auto connect
- - - - - 03ffeab9 by lovetox at 2020-08-14T00:23:38+02:00 Refactor changing status
- Move code out of Roster module - Simplify code - Preferences: Add new setting which makes Gajim show the status change dialog on all status changes
- - - - -
18 changed files:
- gajim/common/app.py - gajim/common/client.py - gajim/common/config.py - gajim/common/helpers.py - gajim/common/modules/user_activity.py - gajim/common/modules/user_location.py - gajim/common/modules/user_mood.py - gajim/common/modules/user_tune.py - gajim/data/gui/preferences_window.ui - gajim/data/gui/status_change_window.ui - gajim/gtk/dialogs.py - gajim/gtk/preferences.py - gajim/gtk/status_change.py - gajim/gtk/status_selector.py - gajim/gtk/statusicon.py - gajim/gtk/util.py - gajim/gui_interface.py - gajim/roster_window.py
Changes:
===================================== gajim/common/app.py ===================================== @@ -378,6 +378,19 @@ def get_number_of_connected_accounts(accounts_list=None): connected_accounts = connected_accounts + 1 return connected_accounts
+def get_available_clients(account=None): + clients = [] + if account is not None: + client = connections.get(account) + if client is None or not client.state.is_available: + return [] + return [client] + + for client in connections.values(): + if client.state.is_available: + clients.append(client) + return clients + def get_connected_accounts(exclude_local=False): """ Returns a list of CONNECTED accounts
===================================== gajim/common/client.py ===================================== @@ -102,6 +102,10 @@ class Client(ConnectionHandlers): def state(self): return self._state
+ @property + def account(self): + return self._account + @property def status(self): return self._status @@ -384,6 +388,10 @@ class Client(ConnectionHandlers):
# We are connected if show == 'offline': + self.set_user_activity(None) + self.set_user_mood(None) + self.set_user_tune(None) + self.set_user_location(None) presence = self.get_module('Presence').get_presence( typ='unavailable', status=message, @@ -409,6 +417,18 @@ class Client(ConnectionHandlers): if include_muc: self.get_module('MUC').update_presence()
+ def set_user_activity(self, activity): + self.get_module('UserActivity').set_activity(activity) + + def set_user_mood(self, mood): + self.get_module('UserMood').set_mood(mood) + + def set_user_tune(self, tune): + self.get_module('UserTune').set_tune(tune) + + def set_user_location(self, location): + self.get_module('UserLocation').set_location(location) + def get_module(self, name): return modules.get(self._account, name)
===================================== gajim/common/config.py ===================================== @@ -246,6 +246,7 @@ class Config: 'show_help_start_chat': [opt_bool, True, _('Shows an info bar with helpful hints in the Start / Join Chat dialog')], 'check_for_update': [opt_bool, True, _('Check for Gajim updates periodically')], 'last_update_check': [opt_str, '', _('Date of the last update check')], + 'always_ask_for_status_message': [opt_bool, True], }, {}) # type: Tuple[Dict[str, List[Any]], Dict[Any, Any]]
__options_per_key = { @@ -269,7 +270,6 @@ class Config: 'autopriority_xa': [opt_int, 30], 'autopriority_dnd': [opt_int, 20], 'autoconnect': [opt_bool, False, '', True], - 'autoconnect_as': [opt_str, 'online', _('Status to be used automatically when connecting. Can be 'online', 'chat', 'away', 'xa' or 'dnd'. NOTE: This option is used only if 'restore_last_status' is disabled.'), True], 'restore_last_status': [opt_bool, False, _('If enabled, the last status will be restored.')], 'autoauth': [opt_bool, False, _('If enabled, contacts requesting authorization will be accepted automatically.')], 'active': [opt_bool, True, _('If disabled, this account will be disabled and will not appear in the contact list window.'), True],
===================================== gajim/common/helpers.py ===================================== @@ -1428,3 +1428,17 @@ def should_log(account, jid): no_log_for = no_log_for.split()
return (account not in no_log_for) and (jid not in no_log_for) + + +def ask_for_status_message(status, signin=False): + if status is None: + # We try to change the message + return True + + if signin: + return app.config.get('ask_online_status') + + if status == 'offline': + return app.config.get('ask_offline_status') + + return app.config.get('always_ask_for_status_message')
===================================== gajim/common/modules/user_activity.py ===================================== @@ -18,12 +18,12 @@ from typing import Any from typing import Tuple
from nbxmpp.namespaces import Namespace +from nbxmpp.structs import ActivityData
from gajim.common import app from gajim.common.nec import NetworkEvent from gajim.common.modules.base import BaseModule from gajim.common.modules.util import event_node -from gajim.common.modules.util import store_publish from gajim.common.const import PEPEventType
@@ -38,6 +38,11 @@ class UserActivity(BaseModule): BaseModule.__init__(self, con) self._register_pubsub_handler(self._activity_received)
+ self._current_activity = None + + def get_current_activity(self): + return self._current_activity + @event_node(Namespace.ACTIVITY) def _activity_received(self, _con, _stanza, properties): if properties.pubsub_event.retracted: @@ -56,6 +61,7 @@ class UserActivity(BaseModule): self._con.pep[PEPEventType.ACTIVITY] = data else: self._con.pep.pop(PEPEventType.ACTIVITY, None) + self._current_activity = data
app.nec.push_incoming_event( NetworkEvent('activity-received', @@ -64,9 +70,20 @@ class UserActivity(BaseModule): activity=data, is_self_message=properties.is_self_message))
- @store_publish def set_activity(self, activity): - self._log.info('Send %s', activity) + if activity is not None: + activity = ActivityData(*activity, None) + + if activity == self._current_activity: + return + + self._current_activity = activity + + if activity is None: + self._log.info('Remove user activity') + else: + self._log.info('Set %s', activity) + self._nbxmpp('Activity').set_activity(activity)
===================================== gajim/common/modules/user_location.py ===================================== @@ -35,6 +35,11 @@ class UserLocation(BaseModule): BaseModule.__init__(self, con) self._register_pubsub_handler(self._location_received)
+ self._current_location = None + + def get_current_location(self): + return self._current_location + @event_node(Namespace.LOCATION) def _location_received(self, _con, _stanza, properties): if properties.pubsub_event.retracted: @@ -53,6 +58,7 @@ class UserLocation(BaseModule): self._con.pep[PEPEventType.LOCATION] = data else: self._con.pep.pop(PEPEventType.LOCATION, None) + self._current_location = data
app.nec.push_incoming_event( NetworkEvent('location-received', @@ -63,6 +69,7 @@ class UserLocation(BaseModule):
@store_publish def set_location(self, location): + self._current_location = location self._log.info('Send %s', location) self._nbxmpp('Location').set_location(location)
===================================== gajim/common/modules/user_mood.py ===================================== @@ -18,12 +18,12 @@ from typing import Any from typing import Tuple
from nbxmpp.namespaces import Namespace +from nbxmpp.structs import MoodData
from gajim.common import app from gajim.common.nec import NetworkEvent from gajim.common.modules.base import BaseModule from gajim.common.modules.util import event_node -from gajim.common.modules.util import store_publish from gajim.common.const import PEPEventType
@@ -38,6 +38,11 @@ class UserMood(BaseModule): BaseModule.__init__(self, con) self._register_pubsub_handler(self._mood_received)
+ self._current_mood = None + + def get_current_mood(self): + return self._current_mood + @event_node(Namespace.MOOD) def _mood_received(self, _con, _stanza, properties): if properties.pubsub_event.retracted: @@ -56,6 +61,7 @@ class UserMood(BaseModule): self._con.pep[PEPEventType.MOOD] = data else: self._con.pep.pop(PEPEventType.MOOD, None) + self._current_mood = data
app.nec.push_incoming_event( NetworkEvent('mood-received', @@ -64,9 +70,20 @@ class UserMood(BaseModule): mood=data, is_self_message=properties.is_self_message))
- @store_publish def set_mood(self, mood): - self._log.info('Send %s', mood) + if mood is not None: + mood = MoodData(mood, None) + + if mood == self._current_mood: + return + + self._current_mood = mood + + if mood is None: + self._log.info('Remove user mood') + else: + self._log.info('Set %s', mood) + self._nbxmpp('Mood').set_mood(mood)
===================================== gajim/common/modules/user_tune.py ===================================== @@ -47,6 +47,9 @@ class UserTune(BaseModule): ('signed-in', ged.CORE, self._on_signed_in), ])
+ def get_current_tune(self): + return self._tune_data + @event_node(Namespace.TUNE) def _tune_received(self, _con, _stanza, properties): if properties.pubsub_event.retracted: @@ -65,6 +68,7 @@ class UserTune(BaseModule): self._con.pep[PEPEventType.TUNE] = data else: self._con.pep.pop(PEPEventType.TUNE, None) + self._tune_data = data
app.nec.push_incoming_event( NetworkEvent('tune-received', @@ -82,6 +86,12 @@ class UserTune(BaseModule): self._account, 'publish_tune'): return + + if tune == self._tune_data: + return + + self._tune_data = tune + self._log.info('Send %s', tune) self._nbxmpp('Tune').set_tune(tune)
@@ -110,7 +120,7 @@ class UserTune(BaseModule): def _on_music_track_changed(self, event): if self._tune_data == event.info: return - self._tune_data = event.info + self.set_tune(event.info)
===================================== gajim/data/gui/preferences_window.ui ===================================== @@ -827,14 +827,14 @@ </packing> </child> <child> - <object class="GtkCheckButton" id="status_change_checkbutton"> + <object class="GtkCheckButton" id="show_status_change_checkbutton"> <property name="label" translatable="yes">Show status changes (Default)</property> <property name="visible">True</property> <property name="can_focus">True</property> <property name="receives_default">False</property> <property name="tooltip_text" translatable="yes">If status change messages are shown in the group chat. This setting can be overridden in the group chat menu.</property> <property name="draw_indicator">True</property> - <signal name="toggled" handler="_on_status_change_toggled" swapped="no"/> + <signal name="toggled" handler="_on_show_status_change_toggled" swapped="no"/> </object> <packing> <property name="left_attach">0</property> @@ -1276,6 +1276,146 @@ <property name="border_width">18</property> <property name="orientation">vertical</property> <property name="spacing">6</property> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="valign">start</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">6</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkCheckButton" id="restore_last_status_checkbutton"> + <property name="label" translatable="yes">_Remember last status</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">If checked, the status and status message used in the last session will be restored</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_restore_last_status_checkbutton_toggled" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">General</property> + <property name="use_markup">True</property> + <style> + <class name="bold"/> + <class name="margin-top6"/> + </style> + </object> + </child> + </object> + <packing> + <property name="expand">True</property> + <property name="fill">True</property> + <property name="position">0</property> + </packing> + </child> + <child> + <object class="GtkFrame"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label_xalign">0</property> + <property name="shadow_type">none</property> + <child> + <object class="GtkAlignment"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <child> + <object class="GtkGrid"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="margin_top">6</property> + <property name="row_spacing">6</property> + <child> + <object class="GtkCheckButton" id="sign_in_status_checkbutton"> + <property name="label" translatable="yes">Sign _In</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Show the status change dialog on Sign In</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_sign_in_status_checkbutton_toggled" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">0</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="sign_out_status_checkbutton"> + <property name="label" translatable="yes">Sign _Out</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Show the status change dialog on Sign Out</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_sign_out_status_checkbutton_toggled" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">1</property> + </packing> + </child> + <child> + <object class="GtkCheckButton" id="status_change_checkbutton"> + <property name="label" translatable="yes">_Status Change</property> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="receives_default">False</property> + <property name="tooltip_text" translatable="yes">Show the status change dialog on all status changes</property> + <property name="halign">start</property> + <property name="use_underline">True</property> + <property name="draw_indicator">True</property> + <signal name="toggled" handler="on_status_change_checkbutton_toggled" swapped="no"/> + </object> + <packing> + <property name="left_attach">0</property> + <property name="top_attach">2</property> + </packing> + </child> + </object> + </child> + </object> + </child> + <child type="label"> + <object class="GtkLabel"> + <property name="visible">True</property> + <property name="can_focus">False</property> + <property name="label" translatable="yes">Ask for Status Message on …</property> + <style> + <class name="bold"/> + <class name="margin-top6"/> + </style> + </object> + </child> + </object> + <packing> + <property name="expand">False</property> + <property name="fill">True</property> + <property name="position">1</property> + </packing> + </child> <child> <object class="GtkFrame"> <property name="visible">True</property> @@ -1389,6 +1529,7 @@ $T will be replaced by auto-not-available timeout.</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Minutes</property> + <property name="xalign">0</property> <style> <class name="dim-label"/> </style> @@ -1403,6 +1544,7 @@ $T will be replaced by auto-not-available timeout.</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Message</property> + <property name="xalign">0</property> <style> <class name="dim-label"/> </style> @@ -1417,6 +1559,7 @@ $T will be replaced by auto-not-available timeout.</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Status</property> + <property name="xalign">0</property> <style> <class name="dim-label"/> </style> @@ -1444,139 +1587,9 @@ $T will be replaced by auto-not-available timeout.</property> <packing> <property name="expand">False</property> <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkFrame"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="valign">start</property> - <property name="label_xalign">0</property> - <property name="shadow_type">none</property> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="events">GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property> - <property name="valign">start</property> - <property name="margin_top">6</property> - <property name="orientation">vertical</property> - <property name="spacing">6</property> - <child> - <object class="GtkCheckButton" id="restore_last_status_checkbutton"> - <property name="label" translatable="yes">_Remember and restore status of the last session</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="tooltip_text" translatable="yes">If checked, the status and status message used in the last session will be restored</property> - <property name="halign">start</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_restore_last_status_checkbutton_toggled" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">True</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">12</property> - <child> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="halign">end</property> - <property name="label" translatable="yes">Ask for status message when I</property> - <property name="justify">right</property> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkBox"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="spacing">12</property> - <child> - <object class="GtkCheckButton" id="prompt_online_status_message_checkbutton"> - <property name="label" translatable="yes">Sign _in</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="halign">start</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_prompt_online_status_message_checkbutton_toggled" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">0</property> - </packing> - </child> - <child> - <object class="GtkCheckButton" id="prompt_offline_status_message_checkbutton"> - <property name="label" translatable="yes">Sign _out</property> - <property name="visible">True</property> - <property name="can_focus">True</property> - <property name="receives_default">False</property> - <property name="halign">start</property> - <property name="use_underline">True</property> - <property name="draw_indicator">True</property> - <signal name="toggled" handler="on_prompt_offline_status_message_checkbutton_toggled" swapped="no"/> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - <packing> - <property name="expand">False</property> - <property name="fill">False</property> - <property name="position">1</property> - </packing> - </child> - </object> - </child> - <child type="label"> - <object class="GtkLabel"> - <property name="visible">True</property> - <property name="can_focus">False</property> - <property name="label" translatable="yes">Status Messages</property> - <property name="use_markup">True</property> - <style> - <class name="bold"/> - <class name="margin-top6"/> - </style> - </object> - </child> - </object> - <packing> - <property name="expand">True</property> - <property name="fill">True</property> - <property name="position">1</property> + <property name="position">2</property> </packing> </child> - <child> - <placeholder/> - </child> </object> <packing> <property name="name">status</property>
===================================== gajim/data/gui/status_change_window.ui ===================================== @@ -48,7 +48,7 @@ <property name="focus_on_click">False</property> <property name="receives_default">True</property> <property name="popover">preset_popover</property> - <signal name="toggled" handler="_stop_timeout" swapped="no"/> + <signal name="toggled" handler="stop_timeout" swapped="no"/> <child> <object class="GtkLabel"> <property name="visible">True</property>
===================================== gajim/gtk/dialogs.py ===================================== @@ -524,14 +524,21 @@ class TimeoutWindow: Derived windows close automatically after reaching the timeout """ def __init__(self, timeout): - self.countdown_left = timeout - self.countdown_enabled = True self.title_text = '' + self._countdown_left = timeout + self._timeout_source_id = None
- def run_timeout(self): - if self.countdown_left > 0: + def start_timeout(self): + if self._countdown_left > 0: self.countdown() - GLib.timeout_add_seconds(1, self.countdown) + self._timeout_source_id = GLib.timeout_add_seconds( + 1, self.countdown) + + def stop_timeout(self, *args, **kwargs): + if self._timeout_source_id is not None: + GLib.source_remove(self._timeout_source_id) + self._timeout_source_id = None + self.set_title(self.title_text)
def on_timeout(self): """ @@ -539,17 +546,15 @@ class TimeoutWindow: """
def countdown(self): - if self.countdown_enabled: - if self.countdown_left <= 0: - self.on_timeout() - return False - self.set_title('%s [%s]' % ( - self.title_text, str(self.countdown_left))) - self.countdown_left -= 1 - return True + if self._countdown_left <= 0: + self._timeout_source_id = None + self.on_timeout() + return False
- self.set_title(self.title_text) - return False + self.set_title('%s [%s]' % ( + self.title_text, str(self._countdown_left))) + self._countdown_left -= 1 + return True
class ShortcutsWindow:
===================================== gajim/gtk/preferences.py ===================================== @@ -168,7 +168,7 @@ class Preferences(Gtk.ApplicationWindow): self._ui.join_leave_checkbutton.set_active(st)
st = app.config.get('print_status_muc_default') - self._ui.status_change_checkbutton.set_active(st) + self._ui.show_status_change_checkbutton.set_active(st)
# Displayed chat state notifications st = app.config.get('show_chatstate_in_tabs') @@ -266,9 +266,11 @@ class Preferences(Gtk.ApplicationWindow):
# Ask for status when online/offline st = app.config.get('ask_online_status') - self._ui.prompt_online_status_message_checkbutton.set_active(st) + self._ui.sign_in_status_checkbutton.set_active(st) st = app.config.get('ask_offline_status') - self._ui.prompt_offline_status_message_checkbutton.set_active(st) + self._ui.sign_out_status_checkbutton.set_active(st) + st = app.config.get('always_ask_for_status_message') + self._ui.status_change_checkbutton.set_active(st)
### Style tab ### # Themes @@ -568,7 +570,7 @@ class Preferences(Gtk.ApplicationWindow): for control in self._get_all_muc_controls(): control.update_actions()
- def _on_status_change_toggled(self, widget): + def _on_show_status_change_toggled(self, widget): self.on_checkbutton_toggled(widget, 'print_status_muc_default') for control in self._get_all_muc_controls(): control.update_actions() @@ -665,12 +667,15 @@ class Preferences(Gtk.ApplicationWindow): widget.set_inconsistent(False) self.on_per_account_checkbutton_toggled(widget, 'restore_last_status')
- def on_prompt_online_status_message_checkbutton_toggled(self, widget): + def on_sign_in_status_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'ask_online_status')
- def on_prompt_offline_status_message_checkbutton_toggled(self, widget): + def on_sign_out_status_checkbutton_toggled(self, widget): self.on_checkbutton_toggled(widget, 'ask_offline_status')
+ def on_status_change_checkbutton_toggled(self, widget): + self.on_checkbutton_toggled(widget, 'always_ask_for_status_message') + ### Style ### @staticmethod def on_theme_combobox_changed(combobox):
===================================== gajim/gtk/status_change.py ===================================== @@ -50,7 +50,7 @@ ACTIVITY_PAGELIST = [
class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): - def __init__(self, callback, account=None, show=None, show_pep=True): + def __init__(self, callback=None, account=None, status=None, show_pep=True): Gtk.ApplicationWindow.__init__(self) countdown_time = app.config.get('change_status_window_timeout') TimeoutWindow.__init__(self, countdown_time) @@ -64,7 +64,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow):
self.account = account self._callback = callback - self._show = show + self._status = status self._show_pep = show_pep
self._ui = get_builder('status_change_window.ui') @@ -80,7 +80,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): self._preset_messages_dict = {} self._get_presets()
- if self._show: + if self._status: self._ui.activity_switch.set_active(self._pep_dict['activity']) self._ui.activity_page_button.set_sensitive( self._pep_dict['activity']) @@ -100,21 +100,18 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): self._ui.pep_grid.set_no_show_all(True) self._ui.pep_grid.hide()
- self._message_buffer.connect('changed', self._stop_timeout) + self._message_buffer.connect('changed', self.stop_timeout) self.connect('key-press-event', self._on_key_press) self._ui.connect_signals(self)
self.show_all() - self.run_timeout() + self.start_timeout()
def on_timeout(self): self._change_status()
- def _stop_timeout(self, *args): - self.countdown_enabled = False - def _on_key_press(self, _widget, event): - self.countdown_enabled = False + self.stop_timeout() if event.keyval in (Gdk.KEY_Return, Gdk.KEY_KP_Enter): if event.get_state() & Gdk.ModifierType.CONTROL_MASK: self._change_status() @@ -374,7 +371,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): self._ui.mood_button_label.set_text(_('No mood'))
def _on_preset_select(self, widget): - self.countdown_enabled = False + self.stop_timeout() self._ui.preset_popover.popdown() name = widget.get_name() self._message_buffer.set_text(self._preset_messages_dict[name][0]) @@ -390,13 +387,13 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): self._ui.mood_page_button.set_sensitive(self._pep_dict['mood'])
def _on_preset_remove(self, widget): - self.countdown_enabled = False + self.stop_timeout() name = widget.get_name() app.config.del_per('statusmsg', name) self._get_presets()
def _on_save_as_preset_clicked(self, _widget): - self.countdown_enabled = False + self.stop_timeout() start_iter, finish_iter = self._message_buffer.get_bounds() message_text = self._message_buffer.get_text( start_iter, finish_iter, True) @@ -452,7 +449,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): transient_for=self).show()
def _on_activity_page_clicked(self, _widget): - self.countdown_enabled = False + self.stop_timeout() self._ui.status_stack.set_visible_child_full( 'activity-page', Gtk.StackTransitionType.SLIDE_LEFT) @@ -467,7 +464,7 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): self._pep_dict['subactivity'] = ''
def _on_mood_page_clicked(self, _widget): - self.countdown_enabled = False + self.stop_timeout() self._ui.status_stack.set_visible_child_full( 'mood-page', Gtk.StackTransitionType.SLIDE_LEFT) @@ -487,24 +484,62 @@ class StatusChange(Gtk.ApplicationWindow, TimeoutWindow): self._draw_mood()
def _on_activity_switch(self, switch, *args): - self.countdown_enabled = False + self.stop_timeout() self._ui.activity_page_button.set_sensitive(switch.get_active())
def _on_mood_switch(self, switch, *args): - self.countdown_enabled = False + self.stop_timeout() self._ui.mood_page_button.set_sensitive(switch.get_active())
+ def _send_user_mood(self): + mood = None + if self._ui.mood_switch.get_active(): + mood = self._pep_dict['mood'] + + for client in app.get_available_clients(self.account): + if not app.config.get_per('accounts', client.account, + 'sync_with_global_status'): + continue + client.set_user_mood(mood) + + def _send_user_activity(self): + activity = None + if self._ui.activity_switch.get_active(): + activity = (self._pep_dict['activity'], + self._pep_dict['subactivity']) + + for client in app.get_available_clients(self.account): + if not app.config.get_per('accounts', client.account, + 'sync_with_global_status'): + continue + client.set_user_activity(activity) + + def _send_status_and_message(self, message): + if self.account is not None: + app.interface.roster.send_status(self.account, + self._status, + message) + return + + for account in app.connections: + if not app.config.get_per('accounts', account, + 'sync_with_global_status'): + continue + + app.interface.roster.send_status(account, self._status, message) + def _change_status(self, *args): + self.stop_timeout() beg, end = self._message_buffer.get_bounds() message = self._message_buffer.get_text(beg, end, True).strip() message = remove_invalid_xml_chars(message)
- if not self._ui.activity_switch.get_active(): - self._pep_dict['activity'] = '' - self._pep_dict['subactivity'] = '' + if self._show_pep: + self._send_user_activity() + self._send_user_mood()
- if not self._ui.mood_switch.get_active(): - self._pep_dict['mood'] = '' - - self._callback(message, self._pep_dict) + if self._callback is not None: + self._callback(message) + else: + self._send_status_and_message(message) self.destroy()
===================================== gajim/gtk/status_selector.py ===================================== @@ -22,7 +22,6 @@ from gajim.common.helpers import statuses_unified from gajim.common.i18n import _
from gajim.gtk.util import get_icon_name -from gajim.gtk.util import open_window
class StatusSelector(Gtk.MenuButton): @@ -100,25 +99,11 @@ class StatusSelector(Gtk.MenuButton): self.set_popover(self._status_popover)
def _on_change_status(self, button): - def _on_response(message, pep_dict): - if message is None: # None if user canceled - return - for account in app.contacts.get_accounts(): - sync_account = app.config.get_per( - 'accounts', account, 'sync_with_global_status') - if not sync_account: - continue - app.interface.roster.send_status(account, new_show, message) - app.interface.roster.send_pep(account, pep_dict) - self._status_popover.popdown() - new_show = button.get_name() - if new_show == 'change_status_message': - new_show = get_global_show() - open_window('StatusChange', callback=_on_response, show=new_show) - return - - app.interface.roster.get_status_message(new_show, _on_response) + new_status = button.get_name() + if new_status == 'change_status_message': + new_status = None + app.interface.change_status(status=new_status)
def update(self): show = get_global_show()
===================================== gajim/gtk/statusicon.py ===================================== @@ -24,8 +24,6 @@ import os from gi.repository import Gtk from gi.repository import GLib
-from gajim import dialogs - from gajim.common import app from gajim.common import helpers from gajim.common.i18n import _ @@ -354,35 +352,8 @@ class StatusIcon:
@staticmethod def _on_show(_widget, show): - # we all add some fake (we cannot select those nor have them as show) - # but this helps to align with roster's status_combobox index positions - status = ['online', 'chat', 'away', 'xa', 'dnd', - 'SEPARATOR', 'CHANGE_STATUS_MSG_MENUITEM', 'SEPARATOR', - 'offline'] - index = status.index(show) - if not helpers.statuses_unified(): - app.interface.roster.status_combobox.set_active(index + 2) - return - current = app.interface.roster.status_combobox.get_active() - if index != current: - app.interface.roster.status_combobox.set_active(index) + app.interface.change_status(status=show)
@staticmethod def _on_change_status(_widget): - model = app.interface.roster.status_combobox.get_model() - active = app.interface.roster.status_combobox.get_active() - status = model[active][2] - def on_response(message, pep_dict): - if message is None: # None if user press Cancel - return - accounts = app.connections.keys() - for acct in accounts: - if not app.config.get_per('accounts', - acct, - 'sync_with_global_status'): - continue - show = app.connections[acct].status - app.interface.roster.send_status(acct, show, message) - app.interface.roster.send_pep(acct, pep_dict) - dlg = dialogs.ChangeStatusMessageDialog(on_response, status) - dlg.dialog.present() + app.interface.change_status()
===================================== gajim/gtk/util.py ===================================== @@ -545,6 +545,12 @@ def format_mood(mood, text): return markuptext
+def get_account_mood_icon_name(account): + client = app.get_client(account) + mood = client.get_module('UserMood').get_current_mood() + return f'mood-{mood.mood}' if mood is not None else mood + + def format_activity(activity, subactivity, text): if activity is None: return None @@ -569,6 +575,14 @@ def get_activity_icon_name(activity, subactivity=None): return icon_name
+def get_account_activity_icon_name(account): + client = app.get_client(account) + activity = client.get_module('UserActivity').get_current_activity() + if activity is None: + return None + return get_activity_icon_name(activity.activity, activity.subactivity) + + def format_tune(artist, _length, _rating, source, title, _track, _uri): if artist is None and title is None and source is None: return None @@ -583,6 +597,12 @@ def format_tune(artist, _length, _rating, source, title, _track, _uri): return tune_string
+def get_account_tune_icon_name(account): + client = app.get_client(account) + tune = client.get_module('UserTune').get_current_tune() + return None if tune is None else 'audio-x-generic' + + def format_location(location): location = location._asdict() location_string = '' @@ -600,6 +620,12 @@ def format_location(location): return location_string.strip()
+def get_account_location_icon_name(account): + client = app.get_client(account) + location = client.get_module('UserLocation').get_current_location() + return None if location is None else 'applications-internet' + + def format_fingerprint(fingerprint): fplen = len(fingerprint) wordsize = fplen // 8
===================================== gajim/gui_interface.py ===================================== @@ -75,6 +75,7 @@ from gajim.common import socks5 from gajim.common import helpers from gajim.common import passwords from gajim.common import logging_helpers +from gajim.common.helpers import ask_for_status_message from gajim.common.structs import MUCData from gajim.common.nec import NetworkEvent from gajim.common.i18n import _ @@ -809,6 +810,9 @@ class Interface: app.config.get_per('accounts', account, 'publish_location')): location.enable()
+ if ask_for_status_message(obj.conn.status, signin=True): + open_window('StatusChange', status=obj.conn.status) + @staticmethod def show_httpupload_progress(transfer): FileTransferProgress(transfer) @@ -1657,31 +1661,58 @@ class Interface: """ Auto connect at startup """ - # dict of account that want to connect sorted by status - shows = {} - for a in app.connections: - if app.config.get_per('accounts', a, 'autoconnect'): - if app.config.get_per('accounts', a, 'restore_last_status'): - self.roster.send_status(a, app.config.get_per('accounts', - a, 'last_status'), helpers.from_one_line( - app.config.get_per('accounts', a, 'last_status_msg'))) - continue - show = app.config.get_per('accounts', a, 'autoconnect_as') - if show not in ['online', 'chat', 'away', 'xa', 'dnd']: - continue - if show not in shows: - shows[show] = [a] - else: - shows[show].append(a) - def on_message(message, pep_dict): - if message is None: - return - for a in shows[show]: - self.roster.send_status(a, show, message) - self.roster.send_pep(a, pep_dict) - for show in shows: - self.roster.get_status_message(show, on_message) - return False + + for account in app.connections: + if not app.config.get_per('accounts', account, 'autoconnect'): + continue + + status = 'online' + status_message = '' + + if app.config.get_per('accounts', account, 'restore_last_status'): + status = app.config.get_per('accounts', account, 'last_status') + status_message = app.config.get_per('accounts', + account, + 'last_status_msg') + status_message = helpers.from_one_line(status_message) + + self.roster.send_status(account, status, status_message) + + def change_status(self, status=None): + # status=None means we want to change the message only + + ask = ask_for_status_message(status) + + if status is None: + status = helpers.get_global_show() + + if ask: + open_window('StatusChange', status=status) + return + + for account in app.connections: + if not app.config.get_per('accounts', account, + 'sync_with_global_status'): + continue + + message = app.get_client(account).status_message + self.roster.send_status(account, status, message) + + def change_account_status(self, account, status=None): + # status=None means we want to change the message only + + ask = ask_for_status_message(status) + + client = app.get_client(account) + if status is None: + status = client.status + + if ask: + open_window('StatusChange', status=status, account=account) + return + + message = client.status_message + self.roster.send_status(account, status, message)
def show_systray(self): if not app.is_display(Display.WAYLAND):
===================================== gajim/roster_window.py ===================================== @@ -42,8 +42,6 @@ from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio from nbxmpp.namespaces import Namespace -from nbxmpp.structs import MoodData -from nbxmpp.structs import ActivityData
from gajim import dialogs from gajim import vcard @@ -55,6 +53,7 @@ from gajim.common import helpers from gajim.common.exceptions import GajimGeneralException from gajim.common import i18n from gajim.common.helpers import save_roster_position +from gajim.common.helpers import ask_for_status_message from gajim.common.i18n import _ from gajim.common.const import PEPEventType, AvatarSize, StyleAttr from gajim.common.dbus import location @@ -84,6 +83,10 @@ from gajim.gtk.util import get_metacontact_surface from gajim.gtk.util import get_builder from gajim.gtk.util import set_urgency_hint from gajim.gtk.util import get_activity_icon_name +from gajim.gtk.util import get_account_activity_icon_name +from gajim.gtk.util import get_account_mood_icon_name +from gajim.gtk.util import get_account_tune_icon_name +from gajim.gtk.util import get_account_location_icon_name from gajim.gtk.util import open_window
@@ -1006,29 +1009,17 @@ class RosterWindow:
self.model[child_iter][Column.NAME] = GLib.markup_escape_text(account_name)
- pep_dict = app.connections[account].pep - if app.config.get('show_mood_in_roster') and PEPEventType.MOOD in pep_dict: - self.model[child_iter][Column.MOOD_PIXBUF] = 'mood-%s' % pep_dict[PEPEventType.MOOD].mood - else: - self.model[child_iter][Column.MOOD_PIXBUF] = None + mood_icon_name = get_account_mood_icon_name(account) + self.model[child_iter][Column.MOOD_PIXBUF] = mood_icon_name
- if app.config.get('show_activity_in_roster') and PEPEventType.ACTIVITY in pep_dict: - activity = pep_dict[PEPEventType.ACTIVITY].activity - subactivity = pep_dict[PEPEventType.ACTIVITY].subactivity - icon_name = get_activity_icon_name(activity, subactivity) - self.model[child_iter][Column.ACTIVITY_PIXBUF] = icon_name - else: - self.model[child_iter][Column.ACTIVITY_PIXBUF] = None + activity_icon_name = get_account_activity_icon_name(account) + self.model[child_iter][Column.ACTIVITY_PIXBUF] = activity_icon_name
- if app.config.get('show_tunes_in_roster') and PEPEventType.TUNE in pep_dict: - self.model[child_iter][Column.TUNE_ICON] = 'audio-x-generic' - else: - self.model[child_iter][Column.TUNE_ICON] = None + tune_icon_name = get_account_tune_icon_name(account) + self.model[child_iter][Column.TUNE_ICON] = tune_icon_name
- if app.config.get('show_location_in_roster') and PEPEventType.LOCATION in pep_dict: - self.model[child_iter][Column.LOCATION_ICON] = 'applications-internet' - else: - self.model[child_iter][Column.LOCATION_ICON] = None + location_icon_name = get_account_location_icon_name(account) + self.model[child_iter][Column.LOCATION_ICON] = location_icon_name
def _really_draw_accounts(self): for acct in self.accounts_to_draw: @@ -2024,27 +2015,11 @@ class RosterWindow: if not app.account_is_available(account): self.set_connecting_state(account)
- self.send_status_continue(account, status, txt) - - def send_pep(self, account, pep_dict): - connection = app.connections[account] - if 'activity' in pep_dict: - activity = pep_dict['activity'] - subactivity = pep_dict.get('subactivity', None) - activity_text = pep_dict.get('activity_text', None) - connection.get_module('UserActivity').set_activity(ActivityData( - activity, subactivity, activity_text)) - else: - connection.get_module('UserActivity').set_activity(None) - - if 'mood' in pep_dict: - mood = pep_dict['mood'] - mood_text = pep_dict.get('mood_text', None) - connection.get_module('UserMood').set_mood(MoodData(mood, mood_text)) - else: - connection.get_module('UserMood').set_mood(None) + if status == 'offline': + self.delete_pep(app.get_jid_from_account(account), account)
- connection.get_module('UserTune').set_tune(None) + app.connections[account].change_status(status, txt) + self._status_selector.update()
def delete_pep(self, jid, account): if jid == app.get_jid_from_account(account): @@ -2059,13 +2034,6 @@ class RosterWindow: if ctrl: ctrl.update_all_pep_types()
- def send_status_continue(self, account, status, txt): - if status == 'offline': - self.delete_pep(app.get_jid_from_account(account), account) - - app.connections[account].change_status(status, txt) - self._status_selector.update() - def chg_contact_status(self, contact, show, status_message, account): """ When a contact changes their status @@ -2159,36 +2127,8 @@ class RosterWindow: app.interface.systray.change_status(show) self._status_selector.update()
- def get_status_message(self, show, callback, show_pep=True, - always_ask=False): - """ - Get the status message by: - - asking to user if needed depending on ask_on(ff)line_status and - always_ask - show_pep can be False to hide pep things from status message or True - """ - empty_pep = {'activity': '', - 'subactivity': '', - 'activity_text': '', - 'mood': '', - 'mood_text': ''} - if not always_ask and ((show == 'online' and not app.config.get( - 'ask_online_status')) or (show == 'offline' and not - app.config.get('ask_offline_status'))): - callback('', empty_pep) - return - - open_window('StatusChange', callback=callback, show=show, - show_pep=show_pep) - - def change_status(self, widget, account, status): - def _on_response(message, pep_dict): - if message is None: # None if user canceled - return - self.send_status(account, status, message) - self.send_pep(account, pep_dict) - self.get_status_message(status, _on_response) + def change_status(self, _widget, account, status): + app.interface.change_account_status(account, status=status)
def get_show(self, lcontact): prio = lcontact[0].priority @@ -2311,7 +2251,7 @@ class RosterWindow: get_msg = True break
- def on_continue3(message, pep_dict): + def on_continue3(message): self.quit_on_next_offline = 0 accounts_to_disconnect = [] for acct in accounts: @@ -2326,11 +2266,10 @@ class RosterWindow:
for acct in accounts_to_disconnect: self.send_status(acct, 'offline', message) - self.send_pep(acct, pep_dict)
- def on_continue2(message, pep_dict): + def on_continue2(message): if 'file_transfers' not in app.interface.instances: - on_continue3(message, pep_dict) + on_continue3(message) return # check if there is an active file transfer from gajim.common.modules.bytestream import is_transfer_active @@ -2354,12 +2293,11 @@ class RosterWindow: DialogButton.make('Remove', text=_('_Quit'), callback=on_continue3, - args=[message, - pep_dict])]).show() + args=[message])]).show() return - on_continue3(message, pep_dict) + on_continue3(message)
- def on_continue(message, pep_dict): + def on_continue(message): if message is None: # user pressed Cancel to change status message dialog return @@ -2396,15 +2334,17 @@ class RosterWindow: DialogButton.make('Remove', text=_('_Quit'), callback=on_continue2, - args=[message, - pep_dict])]).show() + args=[message])]).show() return - on_continue2(message, pep_dict) + on_continue2(message)
- if get_msg: - self.get_status_message('offline', on_continue, show_pep=False) + if get_msg and ask_for_status_message('offline'): + open_window('StatusChange', + status='offline', + callback=on_continue, + show_pep=False) else: - on_continue('', None) + on_continue('')
def _nec_presence_received(self, obj): account = obj.conn.name @@ -2925,15 +2865,8 @@ class RosterWindow: input_str=name, transient_for=self.window).show()
- def on_change_status_message_activate(self, widget, account): - show = app.connections[account].status - def _on_response(message, pep_dict): - if message is None: # None if user canceled - return - self.send_status(account, show, message) - self.send_pep(account, pep_dict) - open_window('StatusChange', account=account, callback=_on_response, - show=show) + def on_change_status_message_activate(self, _widget, account): + app.interface.change_account_status(account)
def on_add_to_roster(self, widget, contact, account): AddNewContactWindow(account, contact.jid, contact.name) @@ -3029,17 +2962,7 @@ class RosterWindow: # CTRL mask if modifier & Gdk.ModifierType.CONTROL_MASK: if keyval == Gdk.KEY_s: # CTRL + s - show = helpers.get_global_show() - def _on_response(message, pep_dict): - if message is not None: # None if user canceled - for account in app.contacts.get_accounts(): - sync_account = app.config.get_per( - 'accounts', account, 'sync_with_global_status') - if not sync_account: - continue - self.send_status(account, show, message) - self.send_pep(account, pep_dict) - open_window('StatusChange', callback=_on_response, show=show) + app.interface.change_status() return True if keyval == Gdk.KEY_k: # CTRL + k self.enable_rfilter('') @@ -3079,22 +3002,13 @@ class RosterWindow: account = model[path][Column.ACCOUNT] if account != 'all': if app.account_is_available(account): - self.on_change_status_message_activate(widget, account) + app.interface.change_account_status(account) return True + show = helpers.get_global_show() if show == 'offline': return True - def _on_response(message, pep_dict): - if message is None: # None if user canceled - return True - for acct in app.connections: - if not app.config.get_per('accounts', acct, - 'sync_with_global_status'): - continue - current_show = app.connections[acct].status - self.send_status(acct, current_show, message) - self.send_pep(acct, pep_dict) - open_window('StatusChange', callback=_on_response, show=show) + app.interface.change_status() return True
if event.button == 1: # Left click @@ -3218,17 +3132,20 @@ class RosterWindow:
def on_publish_tune_toggled(self, widget, account): active = widget.get_active() - app.connections[account].get_module('UserTune').set_enabled(active) + client = app.get_client(account) + client.get_module('UserTune').set_enabled(active)
def on_publish_location_toggled(self, widget, account): active = widget.get_active() + client = app.get_client(account) app.config.set_per('accounts', account, 'publish_location', active) if active: location.enable() else: - app.connections[account].get_module('UserLocation').set_location(None) + client = app.get_client(account) + client.set_user_location(None)
- app.connections[account].get_module('Caps').update_caps() + client.get_module('Caps').update_caps()
def on_add_new_contact(self, widget, account): AddNewContactWindow(account)
View it on GitLab: https://dev.gajim.org/gajim/gajim/-/compare/facb3faf4460da57ddbf65fdb8355465...