summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlorent Le Coz <louiz@louiz.org>2011-04-10 03:52:46 +0200
committerFlorent Le Coz <louiz@louiz.org>2011-04-10 03:52:46 +0200
commita6c56682b74acb7ef568913bbc964b4f17cf3202 (patch)
treea69f53ea655b34831bbff0572dcc487429057f9e
parent35b6e146cb6a0b313d6297f0d91654aa21f58c1b (diff)
downloadpoezio-a6c56682b74acb7ef568913bbc964b4f17cf3202.tar.gz
poezio-a6c56682b74acb7ef568913bbc964b4f17cf3202.tar.bz2
poezio-a6c56682b74acb7ef568913bbc964b4f17cf3202.tar.xz
poezio-a6c56682b74acb7ef568913bbc964b4f17cf3202.zip
Implement paused chate state. fixed #2124
-rw-r--r--src/core.py2
-rw-r--r--src/keyboard.py2
-rw-r--r--src/tabs.py54
-rw-r--r--src/timed_events.py15
4 files changed, 69 insertions, 4 deletions
diff --git a/src/core.py b/src/core.py
index 8629ecc8..76f5026e 100644
--- a/src/core.py
+++ b/src/core.py
@@ -629,7 +629,6 @@ class Core(object):
"""
res = read_char(self.stdscr)
while res is None:
- log.debug('checking events')
self.check_timed_events()
res = read_char(self.stdscr)
return res
@@ -707,6 +706,7 @@ class Core(object):
if not options.debug:
curses.raw()
theme.init_colors()
+ stdscr.idlok(True)
stdscr.keypad(True)
curses.ungetch(" ") # H4X: without this, the screen is
stdscr.getkey() # erased on the first "getkey()"
diff --git a/src/keyboard.py b/src/keyboard.py
index cca854fa..8688d439 100644
--- a/src/keyboard.py
+++ b/src/keyboard.py
@@ -51,7 +51,7 @@ def read_char(s):
# last_char_time = time.time()
s.timeout(1000)
(first, char) = get_next_byte(s)
- if first is None:
+ if first is None and char is None:
return None
if not isinstance(first, int): # Keyboard special, like KEY_HOME etc
return char
diff --git a/src/tabs.py b/src/tabs.py
index c84ba0fa..ac434745 100644
--- a/src/tabs.py
+++ b/src/tabs.py
@@ -40,6 +40,8 @@ import common
import core
import singleton
import xhtml
+import weakref
+import timed_events
import multiuserchat as muc
@@ -50,6 +52,8 @@ from contact import Contact, Resource
from user import User
from logger import logger
+from datetime import datetime, timedelta
+
SHOW_NAME = {
'dnd': _('busy'),
'away': _('away'),
@@ -245,6 +249,12 @@ class ChatTab(Tab):
# we know that the remote user wants chatstates, or not.
# None means we don’t know yet, and we send only "active" chatstates
self.chatstate = None # can be "active", "composing", "paused", "gone", "inactive"
+ # We keep a weakref of the event that will set our chatstate to "paused", so that
+ # we can delete it or change it if we need to
+ self.timed_event_paused = None
+ # if that’s None, then no paused chatstate was sent recently
+ # if that’s a weakref returning None, then a paused chatstate was sent
+ # since the last input
self.key_func['M-/'] = self.last_words_completion
self.key_func['^M'] = self.on_enter
self.commands['say'] = (self.command_say,
@@ -281,6 +291,7 @@ class ChatTab(Tab):
"""
Send an empty chatstate message
"""
+ state = '%s' % state
msg = self.core.xmpp.make_message(self.get_name())
msg['type'] = self.message_type
msg['chat_state'] = state
@@ -294,9 +305,41 @@ class ChatTab(Tab):
if config.get('send_chat_states', 'true') == 'true' and self.remote_wants_chatstates:
if not empty_before and empty_after:
self.send_chat_state("active")
- elif empty_before and not empty_after:
+ elif (empty_before or (self.timed_event_paused is not None and not self.timed_event_paused())) and not empty_after:
self.send_chat_state("composing")
+ def set_paused_delay(self, composing):
+ """
+ we create a timed event that will put us to paused
+ in a few seconds
+ """
+ if config.get('send_chat_states', 'true') != 'true':
+ return
+ if self.timed_event_paused:
+ # check the weakref
+ event = self.timed_event_paused()
+ if event:
+ # the event already exists: we just update
+ # its date
+ event.change_date(datetime.now() + timedelta(seconds=4))
+ return
+ new_event = timed_events.DelayedEvent(4, self.send_chat_state, 'paused')
+ self.core.add_timed_event(new_event)
+ self.timed_event_paused = weakref.ref(new_event)
+
+ def cancel_paused_delay(self):
+ """
+ Remove that event from the list and set it to None.
+ Called for example when the input is emptied, or when the message
+ is sent
+ """
+ if self.timed_event_paused:
+ event = self.timed_event_paused()
+ if event:
+ self.core.timed_events.remove(event)
+ del event
+ self.timed_event_paused = None
+
def command_say(self, line):
raise NotImplementedError
@@ -643,6 +686,9 @@ class MucTab(ChatTab):
self.input.do_command(key)
empty_after = self.input.get_text() == '' or (self.input.get_text().startswith('/') and not self.input.get_text().startswith('//'))
self.send_composing_chat_state(empty_before, empty_after)
+ if not empty_before and empty_after:
+ self.cancel_paused_delay()
+ self.set_paused_delay(empty_before and not empty_after)
return False
def completion(self):
@@ -975,6 +1021,9 @@ class PrivateTab(ChatTab):
self.input.do_command(key)
empty_after = self.input.get_text() == '' or (self.input.get_text().startswith('/') and not self.input.get_text().startswith('//'))
self.send_composing_chat_state(empty_before, empty_after)
+ if not empty_before and empty_after:
+ self.cancel_paused_delay()
+ self.set_paused_delay(empty_before and not empty_after)
return False
def on_lose_focus(self):
@@ -1399,6 +1448,9 @@ class ConversationTab(ChatTab):
self.input.do_command(key)
empty_after = self.input.get_text() == '' or (self.input.get_text().startswith('/') and not self.input.get_text().startswith('//'))
self.send_composing_chat_state(empty_before, empty_after)
+ if not empty_before and empty_after:
+ self.cancel_paused_delay()
+ self.set_paused_delay(empty_before and not empty_after)
return False
def on_lose_focus(self):
diff --git a/src/timed_events.py b/src/timed_events.py
index 7cb92cde..66d3449e 100644
--- a/src/timed_events.py
+++ b/src/timed_events.py
@@ -31,6 +31,7 @@ class TimedEvent(object):
Note that these events can NOT be used for very small delay or a very
precise date, since the check for events is done once per second, as
a maximum.
+ The callback and its arguments should be passed as the lasts arguments.
"""
def __init__(self, date, callback, *args):
self._callback = callback
@@ -57,12 +58,24 @@ class TimedEvent(object):
else:
return False
+ def change_date(self, date):
+ """
+ Simply change the date of the event
+ """
+ self.next_call_date = date
+
+ def add_delay(self, delay):
+ """
+ Add a delay (in seconds) to the date
+ """
+ self.next_call_date += datetime.timedelta(seconds=delay)
+
class DelayedEvent(TimedEvent):
"""
The date is calculated from now + a delay in seconds
Use it if you want an event to happen in, e.g. 6 seconds
"""
def __init__(self, delay, callback, *args):
- date = datetime.datetime.now() + datetime.timedelta(0, delay)
+ date = datetime.datetime.now() + datetime.timedelta(seconds=delay)
TimedEvent.__init__(self, date, callback, args)