Refactor UserActivity
- Use IconTheme for mood icons - Simplify modules because nbxmpp handles more stuff
|
@ -60,6 +60,8 @@ from gajim.gtk.util import get_icon_name
|
|||
from gajim.gtk.util import get_cursor
|
||||
from gajim.gtk.util import ensure_proper_control
|
||||
from gajim.gtk.util import format_mood
|
||||
from gajim.gtk.util import format_activity
|
||||
from gajim.gtk.util import get_activity_icon_name
|
||||
|
||||
from gajim.command_system.implementation.hosts import ChatCommands
|
||||
from gajim.command_system.framework import CommandHost # pylint: disable=unused-import
|
||||
|
@ -131,7 +133,6 @@ class ChatControl(ChatControlBase):
|
|||
self.update_toolbar()
|
||||
|
||||
self._pep_images = {}
|
||||
self._pep_images['activity'] = self.xml.get_object('activity_image')
|
||||
self._pep_images['tune'] = self.xml.get_object('tune_image')
|
||||
self._pep_images['geoloc'] = self.xml.get_object('location_image')
|
||||
self.update_all_pep_types()
|
||||
|
@ -233,6 +234,8 @@ class ChatControl(ChatControlBase):
|
|||
self._on_nickname_received)
|
||||
app.ged.register_event_handler('mood-received', ged.GUI1,
|
||||
self._on_mood_received)
|
||||
app.ged.register_event_handler('activity-received', ged.GUI1,
|
||||
self._on_activity_received)
|
||||
if self.TYPE_ID == message_control.TYPE_CHAT:
|
||||
# Dont connect this when PrivateChatControl is used
|
||||
app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
|
||||
|
@ -416,6 +419,7 @@ class ChatControl(ChatControlBase):
|
|||
for pep_type in self._pep_images:
|
||||
self.update_pep(pep_type)
|
||||
self._update_pep(PEPEventType.MOOD)
|
||||
self._update_pep(PEPEventType.ACTIVITY)
|
||||
|
||||
def update_pep(self, pep_type):
|
||||
if isinstance(self.contact, GC_Contact):
|
||||
|
@ -453,6 +457,9 @@ class ChatControl(ChatControlBase):
|
|||
if type_ == PEPEventType.MOOD:
|
||||
icon = 'mood-%s' % data.mood
|
||||
formated_text = format_mood(*data)
|
||||
elif type_ == PEPEventType.ACTIVITY:
|
||||
icon = get_activity_icon_name(data.activity, data.subactivity)
|
||||
formated_text = format_activity(*data)
|
||||
|
||||
image.set_from_icon_name(icon, Gtk.IconSize.MENU)
|
||||
image.set_tooltip_markup(formated_text)
|
||||
|
@ -461,11 +468,17 @@ class ChatControl(ChatControlBase):
|
|||
def _get_pep_widget(self, type_):
|
||||
if type_ == PEPEventType.MOOD:
|
||||
return self.xml.get_object('mood_image')
|
||||
if type_ == PEPEventType.ACTIVITY:
|
||||
return self.xml.get_object('activity_image')
|
||||
|
||||
@ensure_proper_control
|
||||
def _on_mood_received(self, _event):
|
||||
self._update_pep(PEPEventType.MOOD)
|
||||
|
||||
@ensure_proper_control
|
||||
def _on_activity_received(self, _event):
|
||||
self._update_pep(PEPEventType.ACTIVITY)
|
||||
|
||||
@ensure_proper_control
|
||||
def _on_nickname_received(self, _event):
|
||||
self.update_ui()
|
||||
|
@ -1086,6 +1099,8 @@ class ChatControl(ChatControlBase):
|
|||
self._on_nickname_received)
|
||||
app.ged.remove_event_handler('mood-received', ged.GUI1,
|
||||
self._on_mood_received)
|
||||
app.ged.remove_event_handler('activity-received', ged.GUI1,
|
||||
self._on_activity_received)
|
||||
if self.TYPE_ID == message_control.TYPE_CHAT:
|
||||
app.ged.remove_event_handler('update-roster-avatar', ged.GUI1,
|
||||
self._nec_update_avatar)
|
||||
|
|
|
@ -93,8 +93,6 @@ class Config:
|
|||
'trayicon': [opt_str, 'always', _("When to show notification area icon. Can be 'never', 'on_event', 'always'."), False],
|
||||
'allow_hide_roster': [opt_bool, False, _("Allow to hide the roster window even if the tray icon is not shown."), False],
|
||||
'iconset': [opt_str, DEFAULT_ICONSET, '', True],
|
||||
'mood_iconset': [opt_str, DEFAULT_MOOD_ICONSET, '', True],
|
||||
'activity_iconset': [opt_str, DEFAULT_ACTIVITY_ICONSET, '', True],
|
||||
'use_transports_iconsets': [opt_bool, True, '', True],
|
||||
'notif_signin_color': [opt_color, '#32CD32', _('Contact signed in notification color.')], # limegreen
|
||||
'notif_signout_color': [opt_color, '#FF0000', _('Contact signout notification color')], # red
|
||||
|
|
|
@ -221,8 +221,6 @@ class ConfigPaths:
|
|||
'emoticons', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
|
||||
('MY_ICONSETS',
|
||||
'iconsets', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
|
||||
('MY_ACTIVITY_ICONSETS',
|
||||
'activities', PathLocation.DATA, PathType.FOLDER_OPTIONAL),
|
||||
|
||||
# Cache paths
|
||||
('CACHE_DB', 'cache.db', PathLocation.CACHE, PathType.FILE),
|
||||
|
|
|
@ -1098,13 +1098,6 @@ def get_current_show(account):
|
|||
status = app.connections[account].connected
|
||||
return app.SHOW_LIST[status]
|
||||
|
||||
def get_activity_iconset_path(iconset):
|
||||
if os.path.isdir(os.path.join(configpaths.get('DATA'), 'activities', iconset)):
|
||||
return os.path.join(configpaths.get('DATA'), 'activities', iconset)
|
||||
if os.path.isdir(os.path.join(configpaths.get('MY_ACTIVITY_ICONSETS'),
|
||||
iconset)):
|
||||
return os.path.join(configpaths.get('MY_ACTIVITY_ICONSETS'), iconset)
|
||||
|
||||
def prepare_and_validate_gpg_keyID(account, jid, keyID):
|
||||
"""
|
||||
Return an eight char long keyID that can be used with for GPG encryption
|
||||
|
|
|
@ -35,7 +35,9 @@ ZEROCONF_MODULES = ['iq',
|
|||
_imported_modules = [] # type: List[tuple]
|
||||
_modules = {} # type: Dict[str, Dict[str, Any]]
|
||||
_store_publish_modules = [
|
||||
'UserMood'] # type: List[str]
|
||||
'UserMood',
|
||||
'UserActivity',
|
||||
] # type: List[str]
|
||||
|
||||
for file in Path(__file__).parent.iterdir():
|
||||
if file.stem == '__init__':
|
||||
|
|
|
@ -59,7 +59,7 @@ class Message:
|
|||
nbxmpp.NS_IBB])
|
||||
|
||||
def _message_received(self, _con, stanza, properties):
|
||||
if properties.is_mam_message or properties.is_pubsub_event:
|
||||
if properties.is_mam_message or properties.is_pubsub:
|
||||
return
|
||||
# Check if a child of the message contains any
|
||||
# namespaces that we handle in other modules.
|
||||
|
|
|
@ -14,92 +14,62 @@
|
|||
|
||||
# XEP-0108: User Activity
|
||||
|
||||
from typing import Any
|
||||
from typing import Tuple
|
||||
|
||||
import logging
|
||||
|
||||
import nbxmpp
|
||||
from gi.repository import GLib
|
||||
|
||||
from gajim.common.const import PEPEventType, ACTIVITIES
|
||||
from gajim.common.exceptions import StanzaMalformed
|
||||
from gajim.common.modules.pep import AbstractPEPModule, AbstractPEPData
|
||||
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
|
||||
|
||||
log = logging.getLogger('gajim.c.m.user_activity')
|
||||
|
||||
|
||||
class UserActivityData(AbstractPEPData):
|
||||
class UserActivity(BaseModule):
|
||||
|
||||
type_ = PEPEventType.ACTIVITY
|
||||
_nbxmpp_extends = 'Activity'
|
||||
_nbxmpp_methods = [
|
||||
'set_activity',
|
||||
]
|
||||
|
||||
def as_markup_text(self):
|
||||
pep = self.data
|
||||
activity = pep['activity']
|
||||
subactivity = pep['subactivity'] if 'subactivity' in pep else None
|
||||
text = pep['text'] if 'text' in pep else None
|
||||
def __init__(self, con):
|
||||
BaseModule.__init__(self, con)
|
||||
self._register_pubsub_handler(self._activity_received)
|
||||
|
||||
if activity in ACTIVITIES:
|
||||
# Translate standard activities
|
||||
if subactivity in ACTIVITIES[activity]:
|
||||
subactivity = ACTIVITIES[activity][subactivity]
|
||||
activity = ACTIVITIES[activity]['category']
|
||||
|
||||
markuptext = '<b>' + GLib.markup_escape_text(activity)
|
||||
if subactivity:
|
||||
markuptext += ': ' + GLib.markup_escape_text(subactivity)
|
||||
markuptext += '</b>'
|
||||
if text:
|
||||
markuptext += ' (%s)' % GLib.markup_escape_text(text)
|
||||
return markuptext
|
||||
|
||||
|
||||
class UserActivity(AbstractPEPModule):
|
||||
|
||||
name = 'activity'
|
||||
namespace = nbxmpp.NS_ACTIVITY
|
||||
pep_class = UserActivityData
|
||||
store_publish = True
|
||||
_log = log
|
||||
|
||||
def _extract_info(self, item):
|
||||
activity_dict = {}
|
||||
activity_tag = item.getTag('activity', namespace=self.namespace)
|
||||
if activity_tag is None:
|
||||
raise StanzaMalformed('No activity node')
|
||||
|
||||
if not activity_tag.getChildren():
|
||||
return None
|
||||
|
||||
for child in activity_tag.getChildren():
|
||||
name = child.getName().strip()
|
||||
data = child.getData().strip()
|
||||
if name == 'text':
|
||||
activity_dict['text'] = data
|
||||
@event_node(nbxmpp.NS_ACTIVITY)
|
||||
def _activity_received(self, _con, _stanza, properties):
|
||||
data = properties.pubsub_event.data
|
||||
for contact in app.contacts.get_contacts(self._account,
|
||||
str(properties.jid)):
|
||||
if data.activity is not None:
|
||||
contact.pep[PEPEventType.ACTIVITY] = data
|
||||
else:
|
||||
activity_dict['activity'] = name
|
||||
for subactivity in child.getChildren():
|
||||
subactivity_name = subactivity.getName().strip()
|
||||
activity_dict['subactivity'] = subactivity_name
|
||||
contact.pep.pop(PEPEventType.ACTIVITY, None)
|
||||
|
||||
if 'activity' not in activity_dict:
|
||||
raise StanzaMalformed('No activity value found')
|
||||
return activity_dict
|
||||
if properties.is_self_message:
|
||||
if data.activity is not None:
|
||||
self._con.pep[PEPEventType.ACTIVITY] = data
|
||||
else:
|
||||
self._con.pep.pop(PEPEventType.ACTIVITY, None)
|
||||
|
||||
def _build_node(self, data):
|
||||
item = nbxmpp.Node('activity', {'xmlns': self.namespace})
|
||||
if data is None:
|
||||
return item
|
||||
app.nec.push_incoming_event(
|
||||
NetworkEvent('activity-received',
|
||||
account=self._account,
|
||||
jid=properties.jid.getBare(),
|
||||
activity=data,
|
||||
is_self_message=properties.is_self_message))
|
||||
|
||||
activity, subactivity, message = data
|
||||
if not activity:
|
||||
return item
|
||||
|
||||
i = item.addChild(activity)
|
||||
if subactivity:
|
||||
i.addChild(subactivity)
|
||||
if message:
|
||||
i = item.addChild('text')
|
||||
i.addData(message)
|
||||
return item
|
||||
@store_publish
|
||||
def set_activity(self, activity):
|
||||
log.info('Send %s', activity)
|
||||
self._nbxmpp('Activity').set_activity(activity)
|
||||
|
||||
|
||||
def get_instance(*args, **kwargs):
|
||||
def get_instance(*args: Any, **kwargs: Any) -> Tuple[UserActivity, str]:
|
||||
return UserActivity(*args, **kwargs), 'UserActivity'
|
||||
|
|
Before Width: | Height: | Size: 345 B |
Before Width: | Height: | Size: 909 B After Width: | Height: | Size: 909 B |
Before Width: | Height: | Size: 842 B After Width: | Height: | Size: 842 B |
Before Width: | Height: | Size: 1005 B After Width: | Height: | Size: 1005 B |
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 957 B |
Before Width: | Height: | Size: 916 B After Width: | Height: | Size: 916 B |
Before Width: | Height: | Size: 808 B After Width: | Height: | Size: 808 B |
Before Width: | Height: | Size: 749 B After Width: | Height: | Size: 749 B |
Before Width: | Height: | Size: 980 B After Width: | Height: | Size: 980 B |
Before Width: | Height: | Size: 891 B After Width: | Height: | Size: 891 B |
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 906 B |
Before Width: | Height: | Size: 918 B After Width: | Height: | Size: 918 B |
Before Width: | Height: | Size: 712 B After Width: | Height: | Size: 712 B |
Before Width: | Height: | Size: 706 B After Width: | Height: | Size: 706 B |
Before Width: | Height: | Size: 906 B After Width: | Height: | Size: 906 B |
Before Width: | Height: | Size: 844 B After Width: | Height: | Size: 844 B |
Before Width: | Height: | Size: 969 B After Width: | Height: | Size: 969 B |
Before Width: | Height: | Size: 1016 B After Width: | Height: | Size: 1016 B |
Before Width: | Height: | Size: 868 B After Width: | Height: | Size: 868 B |
Before Width: | Height: | Size: 901 B After Width: | Height: | Size: 901 B |
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 957 B |
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 723 B |
Before Width: | Height: | Size: 625 B After Width: | Height: | Size: 625 B |
Before Width: | Height: | Size: 894 B After Width: | Height: | Size: 894 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 900 B After Width: | Height: | Size: 900 B |
Before Width: | Height: | Size: 846 B After Width: | Height: | Size: 846 B |
Before Width: | Height: | Size: 912 B After Width: | Height: | Size: 912 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 665 B After Width: | Height: | Size: 665 B |
Before Width: | Height: | Size: 759 B After Width: | Height: | Size: 759 B |
Before Width: | Height: | Size: 689 B After Width: | Height: | Size: 689 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 793 B After Width: | Height: | Size: 793 B |
Before Width: | Height: | Size: 1013 B After Width: | Height: | Size: 1013 B |
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 1012 B |
Before Width: | Height: | Size: 589 B After Width: | Height: | Size: 589 B |
Before Width: | Height: | Size: 907 B After Width: | Height: | Size: 907 B |
Before Width: | Height: | Size: 752 B After Width: | Height: | Size: 752 B |
Before Width: | Height: | Size: 917 B After Width: | Height: | Size: 917 B |
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 703 B After Width: | Height: | Size: 703 B |
Before Width: | Height: | Size: 997 B After Width: | Height: | Size: 997 B |
Before Width: | Height: | Size: 967 B After Width: | Height: | Size: 967 B |
Before Width: | Height: | Size: 981 B After Width: | Height: | Size: 981 B |
Before Width: | Height: | Size: 719 B After Width: | Height: | Size: 719 B |
Before Width: | Height: | Size: 866 B After Width: | Height: | Size: 866 B |
Before Width: | Height: | Size: 793 B After Width: | Height: | Size: 793 B |
Before Width: | Height: | Size: 990 B After Width: | Height: | Size: 990 B |
Before Width: | Height: | Size: 913 B After Width: | Height: | Size: 913 B |
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 921 B |
Before Width: | Height: | Size: 964 B After Width: | Height: | Size: 964 B |
Before Width: | Height: | Size: 621 B After Width: | Height: | Size: 621 B |
Before Width: | Height: | Size: 956 B After Width: | Height: | Size: 956 B |
Before Width: | Height: | Size: 958 B After Width: | Height: | Size: 958 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 955 B After Width: | Height: | Size: 955 B |
Before Width: | Height: | Size: 839 B After Width: | Height: | Size: 839 B |
Before Width: | Height: | Size: 792 B After Width: | Height: | Size: 792 B |
Before Width: | Height: | Size: 651 B After Width: | Height: | Size: 651 B |
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 865 B |
Before Width: | Height: | Size: 836 B After Width: | Height: | Size: 836 B |
Before Width: | Height: | Size: 868 B After Width: | Height: | Size: 868 B |
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 982 B |
Before Width: | Height: | Size: 960 B After Width: | Height: | Size: 960 B |
Before Width: | Height: | Size: 696 B After Width: | Height: | Size: 696 B |
Before Width: | Height: | Size: 897 B After Width: | Height: | Size: 897 B |
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 773 B |
Before Width: | Height: | Size: 825 B After Width: | Height: | Size: 825 B |
Before Width: | Height: | Size: 962 B After Width: | Height: | Size: 962 B |
Before Width: | Height: | Size: 797 B After Width: | Height: | Size: 797 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 757 B After Width: | Height: | Size: 757 B |
Before Width: | Height: | Size: 1005 B After Width: | Height: | Size: 1005 B |
Before Width: | Height: | Size: 726 B After Width: | Height: | Size: 726 B |
Before Width: | Height: | Size: 926 B After Width: | Height: | Size: 926 B |
Before Width: | Height: | Size: 815 B After Width: | Height: | Size: 815 B |
|
@ -37,7 +37,6 @@ from gi.repository import Gtk
|
|||
from gi.repository import Gdk
|
||||
from gi.repository import GLib
|
||||
|
||||
from gajim import gtkgui_helpers
|
||||
from gajim import vcard
|
||||
from gajim import dataforms_widget
|
||||
|
||||
|
@ -58,6 +57,7 @@ from gajim.gtk.add_contact import AddNewContactWindow
|
|||
from gajim.gtk.util import get_icon_name
|
||||
from gajim.gtk.util import resize_window
|
||||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.util import get_activity_icon_name
|
||||
|
||||
|
||||
log = logging.getLogger('gajim.dialogs')
|
||||
|
@ -369,9 +369,9 @@ class ChangeActivityDialog:
|
|||
group = None
|
||||
|
||||
for category in ACTIVITIES:
|
||||
icon_name = get_activity_icon_name(category)
|
||||
item = self.xml.get_object(category + '_image')
|
||||
item.set_from_pixbuf(
|
||||
gtkgui_helpers.load_activity_icon(category).get_pixbuf())
|
||||
item.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
||||
item.set_tooltip_text(ACTIVITIES[category]['category'])
|
||||
|
||||
vbox = self.xml.get_object(category + '_vbox')
|
||||
|
@ -386,7 +386,7 @@ class ChangeActivityDialog:
|
|||
else:
|
||||
rbtns[act] = group = Gtk.RadioButton()
|
||||
|
||||
icon = gtkgui_helpers.load_activity_icon(category, self.activity)
|
||||
icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
||||
hbox = Gtk.HBox(homogeneous=False, spacing=5)
|
||||
hbox.pack_start(icon, False, False, 0)
|
||||
lbl = Gtk.Label(
|
||||
|
@ -412,7 +412,8 @@ class ChangeActivityDialog:
|
|||
else:
|
||||
rbtns[act] = group = Gtk.RadioButton()
|
||||
|
||||
icon = gtkgui_helpers.load_activity_icon(category, activity)
|
||||
icon_name = get_activity_icon_name(category, activity)
|
||||
icon = Gtk.Image.new_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
||||
label = Gtk.Label(label=ACTIVITIES[category][activity])
|
||||
hbox = Gtk.HBox(homogeneous=False, spacing=5)
|
||||
hbox.pack_start(icon, False, False, 0)
|
||||
|
@ -681,12 +682,12 @@ class ChangeStatusMessageDialog(TimeoutDialog):
|
|||
ACTIVITIES:
|
||||
if 'subactivity' in self.pep_dict and self.pep_dict['subactivity'] \
|
||||
in ACTIVITIES[self.pep_dict['activity']]:
|
||||
img.set_from_pixbuf(gtkgui_helpers.load_activity_icon(
|
||||
self.pep_dict['activity'], self.pep_dict['subactivity']).\
|
||||
get_pixbuf())
|
||||
icon_name = get_activity_icon_name(self.pep_dict['activity'],
|
||||
self.pep_dict['subactivity'])
|
||||
img.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
||||
else:
|
||||
img.set_from_pixbuf(gtkgui_helpers.load_activity_icon(
|
||||
self.pep_dict['activity']).get_pixbuf())
|
||||
icon_name = get_activity_icon_name(self.pep_dict['activity'])
|
||||
img.set_from_icon_name(icon_name, Gtk.IconSize.MENU)
|
||||
if self.pep_dict['activity_text']:
|
||||
label.set_text(self.pep_dict['activity_text'])
|
||||
else:
|
||||
|
|
|
@ -43,6 +43,8 @@ from gajim.common.i18n import _
|
|||
from gajim.gtk.util import get_builder
|
||||
from gajim.gtk.util import get_icon_name
|
||||
from gajim.gtk.util import format_mood
|
||||
from gajim.gtk.util import format_activity
|
||||
|
||||
|
||||
log = logging.getLogger('gajim.gtk.tooltips')
|
||||
|
||||
|
@ -479,8 +481,8 @@ class RosterTooltip(StatusTable):
|
|||
self._ui.mood.show()
|
||||
self._ui.mood_label.show()
|
||||
|
||||
if 'activity' in contact.pep:
|
||||
activity = contact.pep['activity'].as_markup_text()
|
||||
if PEPEventType.ACTIVITY in contact.pep:
|
||||
activity = format_activity(*contact.pep[PEPEventType.ACTIVITY])
|
||||
self._ui.activity.set_markup(activity)
|
||||
self._ui.activity.show()
|
||||
self._ui.activity_label.show()
|
||||
|
|
|
@ -37,6 +37,7 @@ from gajim.common import configpaths
|
|||
from gajim.common import i18n
|
||||
from gajim.common.i18n import _
|
||||
from gajim.common.const import MOODS
|
||||
from gajim.common.const import ACTIVITIES
|
||||
|
||||
from gajim.gtk.const import GajimIconSet
|
||||
|
||||
|
@ -521,3 +522,27 @@ def format_mood(mood, text):
|
|||
if text is not None:
|
||||
markuptext += ' (%s)' % GLib.markup_escape_text(text)
|
||||
return markuptext
|
||||
|
||||
|
||||
def format_activity(activity, subactivity, text):
|
||||
if activity is None:
|
||||
return
|
||||
|
||||
if subactivity in ACTIVITIES[activity]:
|
||||
subactivity = ACTIVITIES[activity][subactivity]
|
||||
activity = ACTIVITIES[activity]['category']
|
||||
|
||||
markuptext = '<b>' + GLib.markup_escape_text(activity)
|
||||
if subactivity:
|
||||
markuptext += ': ' + GLib.markup_escape_text(subactivity)
|
||||
markuptext += '</b>'
|
||||
if text:
|
||||
markuptext += ' (%s)' % GLib.markup_escape_text(text)
|
||||
return markuptext
|
||||
|
||||
|
||||
def get_activity_icon_name(activity, subactivity=None):
|
||||
icon_name = 'activity-%s' % activity.replace('_', '-')
|
||||
if subactivity is not None:
|
||||
icon_name += '-%s' % subactivity.replace('_', '-')
|
||||
return icon_name
|
||||
|
|
|
@ -41,10 +41,7 @@ except Exception:
|
|||
|
||||
from gajim.common.i18n import _
|
||||
from gajim.common import app
|
||||
from gajim.common import helpers
|
||||
from gajim.common.const import PEPEventType
|
||||
from gajim.common.const import ACTIVITIES
|
||||
from gajim.common.const import MOODS
|
||||
|
||||
HAS_PYWIN32 = True
|
||||
if os.name == 'nt':
|
||||
|
@ -267,72 +264,15 @@ def create_list_multi(value_list, selected_values=None):
|
|||
treeview.show_all()
|
||||
return treeview
|
||||
|
||||
def load_activity_icon(category, activity=None):
|
||||
"""
|
||||
Load an icon from the activity iconset in 16x16
|
||||
"""
|
||||
iconset = app.config.get('activity_iconset')
|
||||
path = os.path.join(helpers.get_activity_iconset_path(iconset),
|
||||
category, '')
|
||||
if activity is None:
|
||||
activity = 'category'
|
||||
icon_list = _load_icon_list([activity], path)
|
||||
return icon_list[activity]
|
||||
|
||||
def get_pep_icon(pep_class):
|
||||
if pep_class == PEPEventType.TUNE:
|
||||
return 'audio-x-generic'
|
||||
|
||||
if pep_class == PEPEventType.ACTIVITY:
|
||||
pep_ = pep_class.data
|
||||
activity = pep_['activity']
|
||||
|
||||
has_known_activity = activity in ACTIVITIES
|
||||
has_known_subactivity = (has_known_activity and
|
||||
'subactivity' in pep_ and
|
||||
pep_['subactivity'] in ACTIVITIES[activity])
|
||||
|
||||
if has_known_activity:
|
||||
if has_known_subactivity:
|
||||
subactivity = pep_['subactivity']
|
||||
return load_activity_icon(activity, subactivity).get_pixbuf()
|
||||
return load_activity_icon(activity).get_pixbuf()
|
||||
return load_activity_icon('unknown').get_pixbuf()
|
||||
|
||||
if pep_class == PEPEventType.LOCATION:
|
||||
return 'applications-internet'
|
||||
|
||||
return None
|
||||
|
||||
def _load_icon_list(icons_list, path, pixbuf2=None):
|
||||
"""
|
||||
Load icons in icons_list from the given path, and add pixbuf2 on top left of
|
||||
each static images
|
||||
"""
|
||||
imgs = {}
|
||||
for icon in icons_list:
|
||||
# try to open a pixfile with the correct method
|
||||
icon_file = icon.replace(' ', '_')
|
||||
files = []
|
||||
files.append(path + icon_file + '.gif')
|
||||
files.append(path + icon_file + '.png')
|
||||
image = Gtk.Image()
|
||||
image.show()
|
||||
imgs[icon] = image
|
||||
for file_ in files: # loop seeking for either gif or png
|
||||
if os.path.exists(file_):
|
||||
image.set_from_file(file_)
|
||||
if pixbuf2 and image.get_storage_type() == Gtk.ImageType.PIXBUF:
|
||||
# add pixbuf2 on top-left corner of image
|
||||
pixbuf1 = image.get_pixbuf()
|
||||
pixbuf2.composite(pixbuf1, 0, 0,
|
||||
pixbuf2.get_property('width'),
|
||||
pixbuf2.get_property('height'), 0, 0, 1.0, 1.0,
|
||||
GdkPixbuf.InterpType.NEAREST, 255)
|
||||
image.set_from_pixbuf(pixbuf1)
|
||||
break
|
||||
return imgs
|
||||
|
||||
def label_set_autowrap(widget):
|
||||
"""
|
||||
Make labels automatically re-wrap if their containers are resized.
|
||||
|
|
|
@ -37,13 +37,13 @@ from enum import IntEnum, unique
|
|||
|
||||
from gi.repository import Gtk
|
||||
from gi.repository import Gdk
|
||||
from gi.repository import GdkPixbuf
|
||||
from gi.repository import Pango
|
||||
from gi.repository import GObject
|
||||
from gi.repository import GLib
|
||||
from gi.repository import Gio
|
||||
from nbxmpp.protocol import NS_FILE, NS_ROSTERX, NS_CONFERENCE
|
||||
from nbxmpp.structs import MoodData
|
||||
from nbxmpp.structs import ActivityData
|
||||
|
||||
from gajim import dialogs
|
||||
from gajim import vcard
|
||||
|
@ -87,6 +87,7 @@ from gajim.gtk.util import move_window
|
|||
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
|
||||
|
||||
|
||||
log = logging.getLogger('gajim.roster')
|
||||
|
@ -1049,10 +1050,11 @@ class RosterWindow:
|
|||
else:
|
||||
self.model[child_iter][Column.MOOD_PIXBUF] = None
|
||||
|
||||
if app.config.get('show_activity_in_roster') and 'activity' in \
|
||||
pep_dict:
|
||||
self.model[child_iter][Column.ACTIVITY_PIXBUF] = \
|
||||
gtkgui_helpers.get_pep_icon(pep_dict['activity'])
|
||||
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
|
||||
|
||||
|
@ -1314,7 +1316,7 @@ class RosterWindow:
|
|||
if pep_type == PEPEventType.MOOD:
|
||||
return app.config.get('show_mood_in_roster')
|
||||
|
||||
if pep_type == 'activity':
|
||||
if pep_type == PEPEventType.ACTIVITY:
|
||||
return app.config.get('show_activity_in_roster')
|
||||
|
||||
if pep_type == 'tune':
|
||||
|
@ -1329,6 +1331,7 @@ class RosterWindow:
|
|||
for pep_type in self._pep_type_to_model_column:
|
||||
self.draw_pep(jid, account, pep_type, contact=contact)
|
||||
self._draw_pep(account, jid, PEPEventType.MOOD)
|
||||
self._draw_pep(account, jid, PEPEventType.ACTIVITY)
|
||||
|
||||
def draw_pep(self, jid, account, pep_type, contact=None):
|
||||
if pep_type not in self._pep_type_to_model_column:
|
||||
|
@ -1366,6 +1369,10 @@ class RosterWindow:
|
|||
column = Column.MOOD_PIXBUF
|
||||
if data is not None:
|
||||
icon = 'mood-%s' % data.mood
|
||||
elif type_ == PEPEventType.ACTIVITY:
|
||||
column = Column.ACTIVITY_PIXBUF
|
||||
if data is not None:
|
||||
icon = get_activity_icon_name(data.activity, data.subactivity)
|
||||
|
||||
for child_iter in iters:
|
||||
self.model[child_iter][column] = icon
|
||||
|
@ -2094,15 +2101,14 @@ class RosterWindow:
|
|||
|
||||
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').send(
|
||||
(activity, subactivity, activity_text))
|
||||
connection.get_module('UserActivity').set_activity(ActivityData(
|
||||
activity, subactivity, activity_text))
|
||||
else:
|
||||
connection.get_module('UserActivity').send(None)
|
||||
connection.get_module('UserActivity').set_activity(None)
|
||||
|
||||
if 'mood' in pep_dict:
|
||||
mood = pep_dict['mood']
|
||||
|
@ -2630,8 +2636,7 @@ class RosterWindow:
|
|||
self.remove_contact(jid, obj.conn.name, backend=True)
|
||||
|
||||
def _nec_pep_received(self, obj):
|
||||
if obj.user_pep.type_ not in (PEPEventType.ACTIVITY,
|
||||
PEPEventType.TUNE,
|
||||
if obj.user_pep.type_ not in (PEPEventType.TUNE,
|
||||
PEPEventType.LOCATION):
|
||||
return
|
||||
|
||||
|
@ -2645,6 +2650,11 @@ class RosterWindow:
|
|||
self.draw_account(event.account)
|
||||
self._draw_pep(event.account, event.jid, PEPEventType.MOOD)
|
||||
|
||||
def _on_activity_received(self, event):
|
||||
if event.is_self_message:
|
||||
self.draw_account(event.account)
|
||||
self._draw_pep(event.account, event.jid, PEPEventType.ACTIVITY)
|
||||
|
||||
def _on_nickname_received(self, event):
|
||||
self.draw_contact(event.jid, event.account)
|
||||
|
||||
|
@ -5582,7 +5592,7 @@ class RosterWindow:
|
|||
# activity_pixbuf, TUNE_ICON, LOCATION_ICON, avatar_img,
|
||||
# padlock_pixbuf, visible]
|
||||
self.columns = [str, str, str, str, str,
|
||||
str, GdkPixbuf.Pixbuf, str, str,
|
||||
str, str, str, str,
|
||||
Gtk.Image, str, bool]
|
||||
|
||||
self.xml = get_builder('roster_window.ui')
|
||||
|
@ -5682,8 +5692,7 @@ class RosterWindow:
|
|||
# cell_data_func, func_arg)
|
||||
self.renderers_list = []
|
||||
self.renderers_propertys = {}
|
||||
self._pep_type_to_model_column = {
|
||||
'activity': Column.ACTIVITY_PIXBUF, 'tune': Column.TUNE_ICON,
|
||||
self._pep_type_to_model_column = {'tune': Column.TUNE_ICON,
|
||||
'geoloc': Column.LOCATION_ICON}
|
||||
|
||||
renderer_text = Gtk.CellRendererText()
|
||||
|
@ -5710,7 +5719,7 @@ class RosterWindow:
|
|||
self._fill_pep_pixbuf_renderer, Column.MOOD_PIXBUF),
|
||||
|
||||
('activity', Gtk.CellRendererPixbuf(), False,
|
||||
'pixbuf', Column.ACTIVITY_PIXBUF,
|
||||
'icon_name', Column.ACTIVITY_PIXBUF,
|
||||
self._fill_pep_pixbuf_renderer, Column.ACTIVITY_PIXBUF),
|
||||
|
||||
('tune', Gtk.CellRendererPixbuf(), False,
|
||||
|
@ -5836,6 +5845,8 @@ class RosterWindow:
|
|||
self._on_nickname_received)
|
||||
app.ged.register_event_handler('mood-received', ged.GUI1,
|
||||
self._on_mood_received)
|
||||
app.ged.register_event_handler('activity-received', ged.GUI1,
|
||||
self._on_activity_received)
|
||||
app.ged.register_event_handler('update-roster-avatar', ged.GUI1,
|
||||
self._nec_update_avatar)
|
||||
app.ged.register_event_handler('update-room-avatar', ged.GUI1,
|
||||
|
|