Commit 03ffeab9 authored by Philipp Hörist's avatar Philipp Hörist
Browse files

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
parent b2d52ad5
......@@ -102,6 +102,10 @@ def _set_state(self, state):
def state(self):
return self._state
@property
def account(self):
return self._account
@property
def status(self):
return self._status
......
......@@ -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 = {
......
......@@ -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')
......@@ -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>
......
......@@ -168,7 +168,7 @@ def __init__(self):
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 @@ def __init__(self):
# 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 @@ def _on_join_leave_toggled(self, widget):
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 @@ def on_restore_last_status_checkbutton_toggled(self, widget):
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):
......
......@@ -50,7 +50,7 @@
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 @@ def __init__(self, callback, account=None, show=None, show_pep=True):
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 @@ def __init__(self, callback, account=None, show=None, show_pep=True):
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'])
......@@ -497,6 +497,9 @@ def _send_user_mood(self):
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):
......@@ -506,16 +509,37 @@ def _send_user_activity(self):
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)
self._send_user_activity()
self._send_user_mood()
if self._show_pep:
self._send_user_activity()
self._send_user_mood()
self._callback(message)
if self._callback is not None:
self._callback(message)
else:
self._send_status_and_message(message)
self.destroy()
......@@ -22,7 +22,6 @@
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,24 +99,11 @@ def _create_popover(self):
self.set_popover(self._status_popover)
def _on_change_status(self, button):
def _on_response(message):
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)
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()
......
......@@ -24,8 +24,6 @@
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 @@ def _on_middle_click():
@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):
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)
dlg = dialogs.ChangeStatusMessageDialog(on_response, status)
dlg.dialog.present()
app.interface.change_status()
......@@ -75,6 +75,7 @@
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 @@ def handle_event_signed_in(self, obj):
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)
......@@ -1674,6 +1678,42 @@ def autoconnect(self):
self.roster.send_status(account, status, status_message)
def change_status(self, status=None):