diff frontends/src/quick_frontend/quick_app.py @ 1972:02d21a589be2

quick_frontend, primitivus: notifications refactoring replaced old "alerts" system by a more generic one which use listeners and can activate callbacks on notification click.
author Goffi <goffi@goffi.org>
date Mon, 27 Jun 2016 22:36:22 +0200
parents 200cd707a46d
children 19b9d3f8a6c7
line wrap: on
line diff
--- a/frontends/src/quick_frontend/quick_app.py	Mon Jun 27 21:45:13 2016 +0200
+++ b/frontends/src/quick_frontend/quick_app.py	Mon Jun 27 22:36:22 2016 +0200
@@ -34,6 +34,7 @@
 
 import sys
 from collections import OrderedDict
+import time
 
 try:
     # FIXME: to be removed when an acceptable solution is here
@@ -51,13 +52,7 @@
     def __init__(self, profile):
         self.profile = profile
         self.whoami = None
-        self.data = {}
-
-    def __getitem__(self, key):
-        return self.data[key]
-
-    def __setitem__(self, key, value):
-        self.data[key] = value
+        self.notifications = {}  # key: bare jid or '' for general, value: notif data
 
     def plug(self):
         """Plug the profile to the host"""
@@ -268,6 +263,8 @@
 
         self.current_action_ids = set() # FIXME: to be removed
         self.current_action_ids_cb = {} # FIXME: to be removed
+        self._notif_id = 0
+        self._notifications = OrderedDict()
         self.media_dir = self.bridge.getConfig('', 'media_dir')
         self.features = None
 
@@ -284,12 +281,6 @@
         """widgets currently visible (must be implemented by frontend)"""
         raise NotImplementedError
 
-    @property
-    def alerts_count(self):
-        """Count the over whole alerts for all contact lists"""
-        # FIXME
-        # return sum([sum(clist._alerts.values()) for clist in self.contact_lists.values()])
-
     def registerSignal(self, function_name, handler=None, iface="core", with_profile=True):
         """Register a handler for a signal
 
@@ -330,6 +321,10 @@
                 args: (entity, new_nick, profile)
             - presence: called when a presence is received
                 args: (entity, show, priority, statuses, profile)
+            - notification: called when a new notification is emited
+                args: (entity, notification_data, profile)
+            - notification_clear: called when notifications are cleared
+                args: (entity, type_, profile)
             - menu: called when a menu item is added or removed
                 args: (type_, path, path_i18n, item) were values are:
                     type_: same as in [sat.core.sat_main.SAT.importMenu]
@@ -496,19 +491,6 @@
 
         chat_widget.messageNew(uid, timestamp, from_jid, target, msg, subject, type_, extra, profile)
 
-        # ContactList alert
-        if not from_me:
-            visible = False
-            for widget in self.visible_widgets:
-                if isinstance(widget, quick_chat.QuickChat) and widget.manageMessage(from_jid, type_):
-                    visible = True
-                    break
-            if visible: # FIXME: à virer gof:
-                if self.isHidden():  # the window is hidden
-                    self.updateAlertsCounter(extra_inc=1)
-            else:
-                contact_list.addAlert(from_jid.bare if type_ == C.MESS_TYPE_GROUPCHAT else from_jid)
-
     def messageSend(self, to_jid, message, subject=None, mess_type="auto", extra=None, callback=None, errback=None, profile_key=C.PROF_KEY_NONE):
         if subject is None:
             subject = {}
@@ -602,6 +584,76 @@
         #         contact_list.setCache(from_jid, 'chat_state', to_display)
         #         widget.update(from_jid)
 
+    def notify(self, type_, entity=None, message=None, subject=None, callback=None, cb_args=None, widget=None, profile=C.PROF_KEY_NONE):
+        """Trigger an event notification
+
+        @param type_(unicode): notifation kind,
+            one of C.NOTIFY_* constant or any custom type specific to frontend
+        @param entity(jid.JID, None): entity involved in the notification
+            if entity is in contact list, a indicator may be added in front of it
+        @param message(unicode, None): message of the notification
+        @param subject(unicode, None): subject of the notification
+        @param callback(callable, None): method to call when notification is selected
+        @param cb_args(list, None): list of args for callback
+        @param widget(object, None): widget where the notification happened
+        """
+        notif_dict = self.profiles[profile].notifications
+        key = '' if entity is None else entity.bare
+        type_notifs = notif_dict.setdefault(key, {}).setdefault(type_, [])
+        notif_data = {
+            'id': self._notif_id,
+            'time': time.time(),
+            'entity': entity,
+            'callback': callback,
+            'cb_args': cb_args,
+            'message': message,
+            'subject': subject,
+            }
+        if widget is not None:
+            notif_data[widget] = widget
+        type_notifs.append(notif_data)
+        self._notifications[self._notif_id] = notif_data
+        self.callListeners('notification', entity, notif_data, profile=profile)
+
+    def getNotifs(self, entity, type_=None, profile=C.PROF_KEY_NONE):
+        """return notifications for given entity
+
+        @param entity(jid.JID, None): bare jid of the entity to check
+            None to get general notifications
+        @param type_(unicode, None): notification type to filter
+            None to get all notifications
+        @return (list[dict]): list of notifications
+        """
+        notif_dict = self.profiles[profile].notifications
+        key = '' if entity is None else entity.bare
+        key_notifs = notif_dict.setdefault(key, {})
+        if type_ is not None:
+            return key_notifs.get(type_, [])
+        ret = []
+        for notifs_list in key_notifs.itervalues():
+            ret.extend(notifs_list)
+        return ret
+
+    def clearNotifs(self, entity, type_=None, profile=C.PROF_KEY_NONE):
+        """return notifications for given entity
+
+        @param entity(jid.JID, None): bare jid of the entity to check
+            None to clear general notifications (but keep entities ones)
+        @param type_(unicode, None): notification type to filter
+            None to clear all notifications
+        @return (list[dict]): list of notifications
+        """
+        notif_dict = self.profiles[profile].notifications
+        key = '' if entity is None else entity.bare
+        try:
+            if type_ is None:
+                del notif_dict[key]
+            else:
+                del notif_dict[key][type_]
+        except KeyError:
+            return
+        self.callListeners('notificationsClear', entity, type_, profile=profile)
+
     def psEventHandler(self, category, service_s, node, event_type, data, profile):
         """Called when a PubSub event is received.
 
@@ -688,13 +740,6 @@
         """
         raise NotImplementedError
 
-    def updateAlertsCounter(self, extra_inc=0):
-        """Update the over whole alerts counter.
-
-        @param extra_inc (int): extra counter
-        """
-        pass
-
     def paramUpdateHandler(self, name, value, namespace, profile):
         log.debug(_(u"param update: [%(namespace)s] %(name)s = %(value)s") % {'namespace': namespace, 'name': name, 'value': value})
         if (namespace, name) == ("Connection", "JabberID"):