Fix #1839 (User mood/activity)

- Added as always new theming variables:
    CHAR_ROSTER_MOOD, CHAR_ROSTER_ACTIVITY (a SNOWMAN!)
    COLOR_ROSTER_MOOD, COLOR_ROSTER_ACTIVITY
- Added two new notification types in Theme.INFO_COLORS (mood/activity)
- Added new configuration options:
    display_mood/activity/tune_notifications (those can be set for a
    specific JID)
    enable_user_tune/nick/activity/mood
- Added /activity and /mood commands, with completions
- Moved the old /activity to /last_activity
- Details are show in the ContactInfoWin if there is room, or with "i"
  on a contact in the roster.
This commit is contained in:
mathieui 2013-03-11 23:06:52 +01:00
parent d2d0416214
commit cec1151ecb
9 changed files with 496 additions and 41 deletions

View file

@ -347,11 +347,29 @@ display_tune_notifications = false
# in the roster).
# If this is set to false, then the display_tune_notifications
# option will be ignored.
receive_user_tune = true
enable_user_tune = true
# Display user mood notifications as information messages or not
display_mood_notifications = false
# Receive the mood notifications or not (in order to display informations
# in the roster).
# If this is set to false, then the display_mood_notifications
# option will be ignored.
enable_user_mood = true
# Display user activity notifications as information messages or not
display_activity_notifications = false
# Receive the activity notifications or not (in order to display informations
# in the roster).
# If this is set to false, then the display_activity_notifications
# option will be ignored.
enable_user_activity = true
# If set to true, use the nickname broadcasted by the user if none has been
# set manually.
use_pep_nick = true
enable_user_nick = true
# if true, chat states will be sent to the people you are talking to.
# Chat states are, for example, messages informing that you are composing

View file

@ -118,11 +118,40 @@ section of this documentation.
If set to true, notifications about the music your contacts listen to
will be displayed in the info buffer as 'Tune' messages.
*display_mood_notifications*:: false
If set to true, notifications about the mood of your contacts
will be displayed in the info buffer as 'Mood' messages.
*display_activity_notifications*:: false
If set to true, notifications about the current activity of your contacts
will be displayed in the info buffer as 'Activity' messages.
*display_user_color_in_join_part*:: false
If set to true, the color of the nick will be used in MUCs information
messages, instead of the default color from the theme.
*enable_user_activity*:: true
Set this to false if you dont want to receive the mood of your contacts
anymore.
*enable_user_mood*:: true
Set this to false if you dont want to receive the mood of your contacts
anymore.
*enable_user_nick*:: true
Set to false if you dont want your contacts to hint you their identity.
*enable_user_tune*:: true
If this is set to false, you will no longer be subscribed to tune events,
and the display_tune_notifications option will be ignored.
*enable_vertical_tab_list*:: false
If true, a vertical list of tabs, with their name, is displayed on the left of
@ -281,11 +310,6 @@ section of this documentation.
If the message takes more than one line, the popup will stay visible
two more second per additional lines.
*receive_user_tune*:: true
If this is set to false, you will no longer be subscribed to tune events,
and the display_tune_notifications option will be ignored.
*remote_fifo_path*:: ./poezio.fifo
The path of the FIFO used to send the commands (see the exec_remote option).
@ -543,11 +567,26 @@ bar = false
Disable the beeps triggered by this conversation. Works in MucTab,
PrivateTab and ConversationTab.
*display_activity_notifications*:: false
If set to true, notifications about the current activity of your contacts
will be displayed in the info buffer as 'Activity' messages.
*display_mood_notifications*:: false
If set to true, notifications about the mood of your contacts
will be displayed in the info buffer as 'Mood' messages.
*display_user_color_in_join_part*:: false
If set to true, the color of the nick will be used in MUCs information
messages, instead of the default color from the theme.
*display_tune_notifications*:: false
If set to true, notifications about the music your contacts listen to
will be displayed in the info buffer as 'Tune' messages.
*hide_exit_join*:: -1
Exact same thing than hide_status_change, except that it concerns

View file

@ -72,10 +72,18 @@ class Connection(sleekxmpp.ClientXMPP):
self.register_plugin('xep_0115')
self.register_plugin('xep_0191')
if config.get('receive_user_tune', 'true') != 'false':
if config.get('enable_user_tune', 'true') != 'false':
self.register_plugin('xep_0118')
if config.get('use_pep_nick', 'true') != 'false':
if config.get('enable_user_nick', 'true') != 'false':
self.register_plugin('xep_0172')
if config.get('enable_user_mood', 'true') != 'false':
self.register_plugin('xep_0107')
if config.get('enable_user_activity', 'true') != 'false':
self.register_plugin('xep_0108')
if config.get('send_poezio_info', 'true') == 'true':
info = {'name':'poezio',
'version': options.version}

View file

@ -68,6 +68,8 @@ class Contact(object):
self._name = ''
self.error = None
self.tune = {}
self.mood = ''
self.activity = ''
@property
def groups(self):

View file

@ -20,6 +20,7 @@ from threading import Event
from datetime import datetime
from xml.etree import cElementTree as ET
import pep
import common
import theming
import logging
@ -230,7 +231,6 @@ class Core(object):
self.key_func.update(key_func)
# Add handlers
self.xmpp.add_event_handler("user_tune_publish", self.on_tune_event)
self.xmpp.add_event_handler('connected', self.on_connected)
self.xmpp.add_event_handler('disconnected', self.on_disconnected)
self.xmpp.add_event_handler('no_auth', self.on_failed_auth)
@ -260,8 +260,14 @@ class Core(object):
self.xmpp.add_event_handler("attention", self.on_attention)
self.xmpp.add_event_handler("ssl_cert", self.validate_ssl)
self.all_stanzas = Callback('custom matcher', connection.MatchAll(None), self.incoming_stanza)
if config.get('use_pep_nick', 'true') != 'false':
if config.get('enable_user_tune', 'true') != 'false':
self.xmpp.add_event_handler("user_tune_publish", self.on_tune_event)
if config.get('enable_user_nick', 'true') != 'false':
self.xmpp.add_event_handler("user_nick_publish", self.on_nick_received)
if config.get('enable_user_mood', 'true') != 'false':
self.xmpp.add_event_handler("user_mood_publish", self.on_mood)
if config.get('enable_user_activity', 'true') != 'false':
self.xmpp.add_event_handler("user_activity_publish", self.on_activity)
self.xmpp.register_handler(self.all_stanzas)
self.initial_joins = []
@ -2132,7 +2138,7 @@ class Core(object):
serv_list.add(serv)
return the_input.auto_completion(list(serv_list), ' ')
def command_activity(self, arg):
def command_last_activity(self, arg):
"""
/activity <jid>
"""
@ -2158,12 +2164,72 @@ class Core(object):
self.information(msg, 'Info')
jid = safeJID(arg)
if jid == '':
return self.command_help('activity')
return self.command_help('last_activity')
self.xmpp.plugin['xep_0012'].get_last_activity(jid, block=False, callback=callback)
def completion_activity(self, the_input):
def completion_last_activity(self, the_input):
return the_input.auto_completion([jid for jid in roster.jids()], '', quotify=False)
def command_mood(self, arg):
"""
/mood [<mood> [text]]
"""
args = common.shell_split(arg)
if not args:
return self.xmpp.plugin['xep_0107'].stop(block=False)
mood = args[0]
if mood not in pep.MOODS:
return self.information('%s is not a correct value for a mood.' % mood, 'Error')
if len(args) > 1:
text = args[1]
else:
text = None
self.xmpp.plugin['xep_0107'].publish_mood(mood, text, block=False)
def completion_mood(self, the_input):
"""Completion for /mood"""
return the_input.auto_completion(list(pep.MOODS.keys()), '', quotify=False)
def command_activity(self, arg):
"""
/activity [<general> [specific] [text]]
"""
args = common.shell_split(arg)
length = len(args)
if not length:
return self.xmpp.plugin['xep_0108'].stop(block=False)
general = args[0]
if general not in pep.ACTIVITIES:
return self.information('%s is not a correct value for an activity' % general, 'Error')
specific = None
text = None
if length == 2:
if args[1] in pep.ACTIVITIES[general]:
specific = args[1]
else:
text = args[1]
elif length == 3:
specific = args[1]
text = args[2]
if specific and specific not in pep.ACTIVITIES[general]:
return self.information('%s is not a correct value for an activity' % specific, 'Error')
self.xmpp.plugin['xep_0108'].publish_activity(general, specific, text, block=False)
def completion_activity(self, the_input):
"""Completion for /activity"""
txt = the_input.get_text()
args = common.shell_split(txt)
n = len(args)
if txt.endswith(' '):
n += 1
if n == 2:
return the_input.auto_completion(list(pep.ACTIVITIES.keys()), '', quotify=False)
elif n == 3:
if args[1] in pep.ACTIVITIES:
l = list(pep.ACTIVITIES[args[1]])
l.remove('category')
return the_input.auto_completion(l, '', quotify=False)
def command_invite(self, arg):
"""/invite <to> <room> [reason]"""
args = common.shell_split(arg)
@ -2233,6 +2299,10 @@ class Core(object):
msg = arg
else:
msg = None
if config.get('enable_user_mood', 'true') != 'false':
self.xmpp.plugin['xep_0107'].stop(block=False)
if config.get('enable_user_activity', 'true') != 'false':
self.xmpp.plugin['xep_0108'].stop(block=False)
self.plugin_manager.disable_plugins()
self.disconnect(msg)
self.running = False
@ -2489,11 +2559,25 @@ class Core(object):
completion=self.completion_runkey)
self.register_command('self', self.command_self,
shortdesc=_('Remind you of who you are.'))
self.register_command('activity', self.command_activity,
self.register_command('last_activity', self.command_last_activity,
usage='<jid>',
desc=_('Informs you of the last activity of a JID.'),
shortdesc=_('Get the activity of someone.'),
completion=self.completion_activity)
completion=self.completion_last_activity)
if config.get('enable_user_mood', 'true') != 'false':
self.register_command('activity', self.command_activity,
usage='[<general> [specific] [text]]',
desc=_('Send your current activity to your contacts (use the completion).'
' Nothing means "stop broadcasting an activity".'),
shortdesc=_('Send your activity.'),
completion=self.completion_activity)
if config.get('eanble_user_activity', 'true') != 'false':
self.register_command('mood', self.command_mood,
usage='[<mood> [text]]',
desc=_('Send your current mood to your contacts (use the completion).'
' Nothing means "stop broadcasting a mood".'),
shortdesc=_('Send your mood.'),
completion=self.completion_mood)
####################### XMPP Event Handlers ##################################
@ -2555,7 +2639,7 @@ class Core(object):
else:
remote_nick = ''
# check for a received nick
if not remote_nick and config.get('use_pep_nick', 'true') != 'false':
if not remote_nick and config.get('enable_user_nick', 'true') != 'false':
if message.xml.find('{http://jabber.org/protocol/nick}nick') is not None:
remote_nick = message['nick']['nick']
# bind the nick to the conversation
@ -2633,6 +2717,68 @@ class Core(object):
item = message['pubsub_event']['items']['item']
if item.xml.find('{http://jabber.org/protocol/nick}nick') is not None:
contact.name = item['nick']['nick']
else:
contact.name= ''
def on_mood(self, message):
"""
Called when a pep notification for an user mood
is received.
"""
contact = roster[message['from'].bare]
if not contact:
return
item = message['pubsub_event']['items']['item']
if item.xml.find('{http://jabber.org/protocol/mood}mood') is not None:
mood = item['mood']['value']
if mood:
mood = pep.MOODS.get(mood, mood)
text = item['mood']['text']
if text:
mood = '%s (%s)' % (mood, text)
contact.mood = mood
else:
contact.mood = ''
else:
contact.mood = ''
if config.get_by_tabname('display_mood_notifications', 'false', contact.bare_jid) == 'true':
if contact.mood:
self.information('Mood from '+ contact.bare_jid + ': ' + contact.mood, 'Mood')
else:
self.information(contact.bare_jid + ' stopped having his/her mood.', 'Mood')
def on_activity(self, message):
"""
Called when a pep notification for an user activity
is received.
"""
contact = roster[message['from'].bare]
if not contact:
return
item = message['pubsub_event']['items']['item']
if item.xml.find('{http://jabber.org/protocol/activity}activity') is not None:
try:
activity = item['activity']['value']
except ValueError:
return
if activity[0]:
general = pep.ACTIVITIES.get(activity[0])
s = general['category']
if activity[1]:
s = s + '/' + general.get(activity[1], 'other')
text = item['activity']['text']
if text:
s = '%s (%s)' % (s, text)
contact.activity = s
else:
contact.activity = ''
else:
contact.activity = ''
if config.get_by_tabname('display_activity_notifications', 'false', contact.bare_jid) == 'true':
if contact.activity:
self.information('Activity from '+ contact.bare_jid + ': ' + contact.activity, 'Activity')
else:
self.information(contact.bare_jid + ' stopped doing his/her activity.', 'Activity')
def on_tune_event(self, message):
"""
@ -2656,10 +2802,13 @@ class Core(object):
}
else:
contact.tune = {}
if config.get('display_tune_notifications', 'false') == 'true' and contact.tune:
self.information(
'Tune from '+ message['from'].bare + ': ' + common.format_tune_string(contact.tune),
'Tune')
if config.get_by_tabname('display_tune_notifications', 'false', contact.bare_jid) == 'true':
if contact.tune:
self.information(
'Tune from '+ message['from'].bare + ': ' + common.format_tune_string(contact.tune),
'Tune')
else:
self.information(contact.bare_jid + ' stopped listening to music.', 'Tune')
def on_groupchat_message(self, message):
"""
@ -3068,7 +3217,7 @@ class Core(object):
status=self.status.message,
show=self.status.show)
if config.get('use_pep_nick', 'true') != 'false':
if config.get('enable_user_nick', 'true') != 'false':
self.xmpp.plugin['xep_0172'].publish_nick(nick=self.own_nick)
### Other handlers ###

215
src/pep.py Normal file
View file

@ -0,0 +1,215 @@
# -*- coding:utf-8 -*-
## src/common/pep.py
##
## Copyright (C) 2007 Piotr Gaczkowski <doomhammerng AT gmail.com>
## Copyright (C) 2007-2012 Yann Leboulanger <asterix AT lagaule.org>
## Copyright (C) 2008 Brendan Taylor <whateley AT gmail.com>
## Jean-Marie Traissard <jim AT lapin.org>
## Jonathan Schleifer <js-common.gajim AT webkeks.org>
## Stephan Erb <steve-e AT h3c.de>
##
## This file is part of Gajim.
##
## Gajim is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published
## by the Free Software Foundation; version 3 only.
##
## Gajim is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with Gajim. If not, see <http://www.gnu.org/licenses/>.
##
from gettext import gettext as _
MOODS = {
'afraid': _('Afraid'),
'amazed': _('Amazed'),
'amorous': _('Amorous'),
'angry': _('Angry'),
'annoyed': _('Annoyed'),
'anxious': _('Anxious'),
'aroused': _('Aroused'),
'ashamed': _('Ashamed'),
'bored': _('Bored'),
'brave': _('Brave'),
'calm': _('Calm'),
'cautious': _('Cautious'),
'cold': _('Cold'),
'confident': _('Confident'),
'confused': _('Confused'),
'contemplative': _('Contemplative'),
'contented': _('Contented'),
'cranky': _('Cranky'),
'crazy': _('Crazy'),
'creative': _('Creative'),
'curious': _('Curious'),
'dejected': _('Dejected'),
'depressed': _('Depressed'),
'disappointed': _('Disappointed'),
'disgusted': _('Disgusted'),
'dismayed': _('Dismayed'),
'distracted': _('Distracted'),
'embarrassed': _('Embarrassed'),
'envious': _('Envious'),
'excited': _('Excited'),
'flirtatious': _('Flirtatious'),
'frustrated': _('Frustrated'),
'grateful': _('Grateful'),
'grieving': _('Grieving'),
'grumpy': _('Grumpy'),
'guilty': _('Guilty'),
'happy': _('Happy'),
'hopeful': _('Hopeful'),
'hot': _('Hot'),
'humbled': _('Humbled'),
'humiliated': _('Humiliated'),
'hungry': _('Hungry'),
'hurt': _('Hurt'),
'impressed': _('Impressed'),
'in_awe': _('In Awe'),
'in_love': _('In Love'),
'indignant': _('Indignant'),
'interested': _('Interested'),
'intoxicated': _('Intoxicated'),
'invincible': _('Invincible'),
'jealous': _('Jealous'),
'lonely': _('Lonely'),
'lost': _('Lost'),
'lucky': _('Lucky'),
'mean': _('Mean'),
'moody': _('Moody'),
'nervous': _('Nervous'),
'neutral': _('Neutral'),
'offended': _('Offended'),
'outraged': _('Outraged'),
'playful': _('Playful'),
'proud': _('Proud'),
'relaxed': _('Relaxed'),
'relieved': _('Relieved'),
'remorseful': _('Remorseful'),
'restless': _('Restless'),
'sad': _('Sad'),
'sarcastic': _('Sarcastic'),
'satisfied': _('Satisfied'),
'serious': _('Serious'),
'shocked': _('Shocked'),
'shy': _('Shy'),
'sick': _('Sick'),
'sleepy': _('Sleepy'),
'spontaneous': _('Spontaneous'),
'stressed': _('Stressed'),
'strong': _('Strong'),
'surprised': _('Surprised'),
'thankful': _('Thankful'),
'thirsty': _('Thirsty'),
'tired': _('Tired'),
'undefined': _('Undefined'),
'weak': _('Weak'),
'worried': _('Worried')}
ACTIVITIES = {
'doing_chores': {'category': _('Doing Chores'),
'buying_groceries': _('Buying Groceries'),
'cleaning': _('Cleaning'),
'cooking': _('Cooking'),
'doing_maintenance': _('Doing Maintenance'),
'doing_the_dishes': _('Doing the Dishes'),
'doing_the_laundry': _('Doing the Laundry'),
'gardening': _('Gardening'),
'running_an_errand': _('Running an Errand'),
'walking_the_dog': _('Walking the Dog')},
'drinking': {'category': _('Drinking'),
'having_a_beer': _('Having a Beer'),
'having_coffee': _('Having Coffee'),
'having_tea': _('Having Tea')},
'eating': {'category': _('Eating'),
'having_a_snack': _('Having a Snack'),
'having_breakfast': _('Having Breakfast'),
'having_dinner': _('Having Dinner'),
'having_lunch': _('Having Lunch')},
'exercising': {'category': _('Exercising'),
'cycling': _('Cycling'),
'dancing': _('Dancing'),
'hiking': _('Hiking'),
'jogging': _('Jogging'),
'playing_sports': _('Playing Sports'),
'running': _('Running'),
'skiing': _('Skiing'),
'swimming': _('Swimming'),
'working_out': _('Working out')},
'grooming': {'category': _('Grooming'),
'at_the_spa': _('At the Spa'),
'brushing_teeth': _('Brushing Teeth'),
'getting_a_haircut': _('Getting a Haircut'),
'shaving': _('Shaving'),
'taking_a_bath': _('Taking a Bath'),
'taking_a_shower': _('Taking a Shower')},
'having_appointment': {'category': _('Having an Appointment')},
'inactive': {'category': _('Inactive'),
'day_off': _('Day Off'),
'hanging_out': _('Hanging out'),
'hiding': _('Hiding'),
'on_vacation': _('On Vacation'),
'praying': _('Praying'),
'scheduled_holiday': _('Scheduled Holiday'),
'sleeping': _('Sleeping'),
'thinking': _('Thinking')},
'relaxing': {'category': _('Relaxing'),
'fishing': _('Fishing'),
'gaming': _('Gaming'),
'going_out': _('Going out'),
'partying': _('Partying'),
'reading': _('Reading'),
'rehearsing': _('Rehearsing'),
'shopping': _('Shopping'),
'smoking': _('Smoking'),
'socializing': _('Socializing'),
'sunbathing': _('Sunbathing'),
'watching_tv': _('Watching TV'),
'watching_a_movie': _('Watching a Movie')},
'talking': {'category': _('Talking'),
'in_real_life': _('In Real Life'),
'on_the_phone': _('On the Phone'),
'on_video_phone': _('On Video Phone')},
'traveling': {'category': _('Traveling'),
'commuting': _('Commuting'),
'cycling': _('Cycling'),
'driving': _('Driving'),
'in_a_car': _('In a Car'),
'on_a_bus': _('On a Bus'),
'on_a_plane': _('On a Plane'),
'on_a_train': _('On a Train'),
'on_a_trip': _('On a Trip'),
'walking': _('Walking')},
'working': {'category': _('Working'),
'coding': _('Coding'),
'in_a_meeting': _('In a Meeting'),
'studying': _('Studying'),
'writing': _('Writing')}}
LOCATION_DATA = {
'accuracy': _('accuracy'),
'alt': _('alt'),
'area': _('area'),
'bearing': _('bearing'),
'building': _('building'),
'country': _('country'),
'countrycode': _('countrycode'),
'datum': _('datum'),
'description': _('description'),
'error': _('error'),
'floor': _('floor'),
'lat': _('lat'),
'locality': _('locality'),
'lon': _('lon'),
'postalcode': _('postalcode'),
'region': _('region'),
'room': _('room'),
'speed': _('speed'),
'street': _('street'),
'text': _('text'),
'timestamp': _('timestamp'),
'uri': _('uri')}

View file

@ -2076,7 +2076,7 @@ class RosterInfoTab(Tab):
self.key_func["M-Y"] = self.move_cursor_to_prev_group
self.key_func["M-[1;5B"] = self.move_cursor_to_next_group
self.key_func["M-[1;5A"] = self.move_cursor_to_prev_group
self.key_func["l"] = self.command_activity
self.key_func["l"] = self.command_last_activity
self.key_func["o"] = self.toggle_offline_show
self.key_func["v"] = self.get_contact_version
self.key_func["i"] = self.show_contact_info
@ -2139,11 +2139,11 @@ class RosterInfoTab(Tab):
completion=self.completion_file)
self.register_command('clear_infos', self.command_clear_infos,
shortdesc=_('Clear the info buffer.'))
self.register_command('activity', self.command_activity,
self.register_command('last_activity', self.command_last_activity,
usage=_('<jid>'),
desc=_('Informs you of the last activity of a JID.'),
shortdesc=_('Get the activity of someone.'),
completion=self.core.completion_activity)
completion=self.core.completion_last_activity)
self.core.xmpp.add_event_handler('session_start',
lambda event: self.core.xmpp.plugin['xep_0030'].get_info(
jid=self.core.xmpp.boundjid.domain,
@ -2274,11 +2274,10 @@ class RosterInfoTab(Tab):
"""
self.core.disconnect()
def command_activity(self, arg=None):
def command_last_activity(self, arg=None):
"""
/activity [jid]
"""
item = self.roster_win.selected_row
if arg:
jid = arg
@ -2289,7 +2288,7 @@ class RosterInfoTab(Tab):
else:
self.core.information('No JID selected.', 'Error')
return
self.core.command_activity(jid)
self.core.command_last_activity(jid)
def resize(self):
if not self.visible:
@ -2845,14 +2844,18 @@ class RosterInfoTab(Tab):
if isinstance(selected_row, Contact):
cont = selected_row
res = selected_row.get_highest_priority_resource()
msg = 'Contact: %s (%s)\n%s connected resource%s\nCurrent status: %s\nCurrent tune: %s' % (
cont.bare_jid,
res.presence if res else 'unavailable',
len(cont),
'' if len(cont) == 1 else 's',
res.status if res else '',
common.format_tune_string(cont.tune),
)
acc = []
acc.append('Contact: %s (%s)' % (cont.bare_jid, res.presence if res else 'unavailable'))
if res:
acc.append('%s connected resource%s' % (len(cont), '' if len(cont) == 1 else 's'))
acc.append('Current status: %s' % res.status)
if cont.tune:
acc.append('Tune: %s' % common.format_tune_string(cont.tune))
if cont.mood:
acc.append('Mood: %s' % cont.mood)
if cont.activity:
acc.append('Activity: %s' % cont.activity)
msg = '\n'.join(acc)
elif isinstance(selected_row, Resource):
res = selected_row
msg = 'Resource: %s (%s)\nCurrent status: %s\nPriority: %s' % (
@ -2959,11 +2962,11 @@ class ConversationTab(ChatTab):
shortdesc=_('Get the software version of the user.'))
self.register_command('info', self.command_info,
shortdesc=_('Get the status of the contact.'))
self.register_command('activity', self.command_activity,
self.register_command('last_activity', self.command_last_activity,
usage=_('[jid]'),
desc=_('Get the last activity of the given or the current contact.'),
shortdesc=_('Get the activity.'),
completion=self.core.completion_activity)
completion=self.core.completion_last_activity)
self.resize()
self.update_commands()
self.update_keys()
@ -3023,12 +3026,12 @@ class ConversationTab(ChatTab):
self.text_win.refresh()
self.input.refresh()
def command_activity(self, arg):
def command_last_activity(self, arg):
"""
/activity [jid]
"""
if arg.strip():
return self.core.command_activity(arg)
return self.core.command_last_activity(arg)
def callback(iq):
if iq['type'] != 'result':

View file

@ -202,7 +202,11 @@ class Theme(object):
CHAR_ROSTER_ERROR = ''
CHAR_ROSTER_TUNE = ''
CHAR_ROSTER_ASKED = '?'
CHAR_ROSTER_ACTIVITY = ''
CHAR_ROSTER_MOOD = ''
COLOR_ROSTER_MOOD = (2, -1)
COLOR_ROSTER_ACTIVITY = (3, -1)
COLOR_ROSTER_TUNE = (6, -1)
COLOR_ROSTER_ERROR = (1, -1)
COLOR_JOIN_CHAR = (4, -1)
@ -221,6 +225,8 @@ class Theme(object):
'help': (10, -1),
'headline': (11, -1, 'b'),
'tune': (6, -1),
'mood': (2, -1),
'activity': (3, -1),
'default': (7, -1),
}

View file

@ -1938,6 +1938,10 @@ class RosterWin(Win):
added += len(get_theme().CHAR_ROSTER_ERROR)
if contact.tune:
added += len(get_theme().CHAR_ROSTER_TUNE)
if contact.mood:
added += len(get_theme().CHAR_ROSTER_MOOD)
if contact.activity:
added += len(get_theme().CHAR_ROSTER_ACTIVITY)
if config.getl('show_roster_jids', 'true') == 'false' and contact.name:
display_name = '%s' % contact.name
@ -1958,7 +1962,10 @@ class RosterWin(Win):
self.addstr(get_theme().CHAR_ROSTER_ERROR, to_curses_attr(get_theme().COLOR_ROSTER_ERROR))
if contact.tune:
self.addstr(get_theme().CHAR_ROSTER_TUNE, to_curses_attr(get_theme().COLOR_ROSTER_TUNE))
if contact.activity:
self.addstr(get_theme().CHAR_ROSTER_ACTIVITY, to_curses_attr(get_theme().COLOR_ROSTER_ACTIVITY))
if contact.mood:
self.addstr(get_theme().CHAR_ROSTER_MOOD, to_curses_attr(get_theme().COLOR_ROSTER_MOOD))
self.finish_line()
def draw_resource_line(self, y, resource, colored):
@ -2028,6 +2035,14 @@ class ContactInfoWin(Win):
self.addstr(i, 0, 'Current Tune: %s' % common.format_tune_string(contact.tune), to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
i += 1
if contact.mood:
self.addstr(i, 0, 'Mood: %s' % contact.mood, to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
i += 1
if contact.activity:
self.addstr(i, 0, 'Activity: %s' % contact.activity, to_curses_attr(get_theme().COLOR_NORMAL_TEXT))
i += 1
def draw_group_info(self, group):
"""
draw the group information