view src/browser/sat_browser/notification.py @ 589:a5019e62c3e9 frontends_multi_profiles

browser side: big refactoring to base Libervia on QuickFrontend, first draft: /!\ not finished, partially working and highly instable - add collections module with an OrderedDict like class - SatWebFrontend inherit from QuickApp - general sat_frontends tools.jid module is used - bridge/json methods have moved to json module - UniBox is partially removed (should be totally removed before merge to trunk) - Signals are now register with the generic registerSignal method (which is called mainly in QuickFrontend) - the generic getOrCreateWidget method from QuickWidgetsManager is used instead of Libervia's specific methods - all Widget are now based more or less directly on QuickWidget - with the new QuickWidgetsManager.getWidgets method, it's no more necessary to check all widgets which are instance of a particular class - ChatPanel and related moved to chat module - MicroblogPanel and related moved to blog module - global and overcomplicated send method has been disabled: each class should manage its own sending - for consistency with other frontends, former ContactPanel has been renamed to ContactList and vice versa - for the same reason, ChatPanel has been renamed to Chat - for compatibility with QuickFrontend, a fake profile is used in several places, it is set to C.PROF_KEY_NONE (real profile is managed server side for obvious security reasons) - changed default url for web panel to SàT website, and contact address to generic SàT contact address - ContactList is based on QuickContactList, UI changes are done in update method - bride call (now json module) have been greatly improved, in particular call can be done in the same way as for other frontends (bridge.method_name(arg1, arg2, ..., callback=cb, errback=eb). Blocking method must be called like async methods due to javascript architecture - in bridge calls, a callback can now exists without errback - hard reload on BridgeSignals remote error has been disabled, a better option should be implemented - use of constants where that make sens, some style improvments - avatars are temporarily disabled - lot of code disabled, will be fixed or removed before merge - various other changes, check diff for more details server side: manage remote exception on getEntityData, removed getProfileJid call, added getWaitingConf, added getRoomsSubjects
author Goffi <goffi@goffi.org>
date Sat, 24 Jan 2015 01:45:39 +0100
parents 97c72fe4a5f2
children e11e34ac0f67
line wrap: on
line source

from __pyjamas__ import JS, wnd
from sat.core.log import getLogger
log = getLogger(__name__)
from sat.core.i18n import _

from pyjamas import Window
from pyjamas.Timer import Timer

import dialog

TIMER_DELAY = 5000


class Notification(object):
    """
    If the browser supports it, the user allowed it to and the tab is in the
    background, send desktop notifications on messages.

    Requires both Web Notifications and Page Visibility API.
    """

    def __init__(self):
        self.enabled = False
        user_agent = None
        notif_permission = None
        JS("""
        if (!('hidden' in document))
            document.hidden = false;

        user_agent = navigator.userAgent

        if (!('Notification' in window))
            return;

        notif_permission = Notification.permission

        if (Notification.permission === 'granted')
            this.enabled = true;

        else if (Notification.permission === 'default') {
            Notification.requestPermission(function(permission){
                if (permission !== 'granted')
                    return;

                self.enabled = true; //need to use self instead of this
            });
        }
        """)

        if "Chrome" in user_agent and notif_permission not in ['granted', 'denied']:
            self.user_agent = user_agent
            self._installChromiumWorkaround()

        wnd().onfocus = self.onFocus
        # wnd().onblur = self.onBlur
        self._notif_count = 0
        self._orig_title = Window.getTitle()

    def _installChromiumWorkaround(self):
        # XXX: Workaround for Chromium behaviour, it's doens't manage requestPermission on onLoad event
        # see https://code.google.com/p/chromium/issues/detail?id=274284
        # FIXME: need to be removed if Chromium behaviour changes
        try:
            version_full = [s for s in self.user_agent.split() if "Chrome" in s][0].split('/')[1]
            version = int(version_full.split('.')[0])
        except (IndexError, ValueError):
            log.warning("Can't find Chromium version")
            version = 0
        log.info("Chromium version: %d" % (version,))
        if version < 22:
            log.info("Notification use the old prefixed version or are unmanaged")
            return
        if version < 32:
            dialog.InfoDialog(_("Notifications activation for Chromium"), _('You need to activate notifications manually for your Chromium version.<br/>To activate notifications, click on the favicon on the left of the address bar')).show()
            return

        log.info("==> Installing Chromium notifications request workaround <==")
        self._old_click = wnd().onclick
        wnd().onclick = self._chromiumWorkaround

    def _chromiumWorkaround(self):
        log.info("Activating workaround")
        JS("""
            Notification.requestPermission(function(permission){
                if (permission !== 'granted')
                    return;
                self.enabled = true; //need to use self instead of this
            });
        """)
        wnd().onclick = self._old_click

    def onFocus(self):
        Window.setTitle(self._orig_title)
        self._notif_count = 0

    # def onBlur(self):
    #     pass

    def isHidden(self):
        JS("""return document.hidden;""")

    def _notify(self, title, body, icon):
        if not self.enabled:
            return
        notification = None
        JS("""
           notification = new Notification(title, {body: body, icon: icon});
           // Probably won’t work, but it doesn’t hurt to try.
           notification.addEventListener('click', function() {
               window.focus();
           });
           """)
        notification.onshow = lambda: Timer(TIMER_DELAY, lambda timer: notification.close())

    def highlightTab(self):
        self._notif_count += 1
        Window.setTitle("%s (%d)" % (self._orig_title, self._notif_count))

    def notify(self, title, body, icon='/media/icons/apps/48/sat.png'):
        if self.isHidden():
            self._notify(title, body, icon)
            self.highlightTab()