nw-skeleton

Source: app-wrapper/js/helper/system/appNotificationsHelper.js

/**
 * @fileOverview AppNotificationsHelper class file
 * @author Dino Ivankov <dinoivankov@gmail.com>
 * @version 1.3.1
 */

const _ = require('lodash');
const path = require('path');
const AppBaseClass = require('../../lib/appBase').AppBaseClass;

var _appWrapper;
var appState;

/**
 * AppNotificationsHelper class - handles and manages app and desktop notifications
 *
 * @class
 * @extends {appWrapper.AppBaseClass}
 * @memberof appWrapper.helpers.systemHelpers
 */
class AppNotificationsHelper extends AppBaseClass {

    /**
     * Creates AppNotificationsHelper instance
     *
     * @constructor
     * @return {AppNotificationsHelper}              Instance of AppNotificationsHelper class
     */
    constructor() {
        super();

        if (window && window.getAppWrapper && _.isFunction(window.getAppWrapper)){
            _appWrapper = window.getAppWrapper();
            appState = _appWrapper.getAppState();
        }

        this.timeouts = {
            notificationQueue: null
        };

        return this;
    }

    /**
     * Adds app notification
     *
     * @param {Object} notification Notification object
     * @return {undefined}
     */
    async addNotification(notification){
        let nd = appState.appNotificationsData;
        let cn = nd.currentNotification;
        if (cn && cn.message == notification.message && cn.type == notification.type){
            cn.count++;
            cn.timestamps.push(new Date().toString());
        } else {
            if (nd.newNotifications.length){
                if (nd.newNotifications[0].message == notification.message && nd.newNotifications[0].type == notification.type){
                    nd.newNotifications[0].count++;
                    nd.newNotifications[0].timestamps.push(new Date().toString());
                } else {
                    if (notification.immediate){
                        nd.notificationExpired = true;
                        nd.newNotifications.unshift(notification);
                    } else {
                        nd.newNotifications.push(notification);
                    }
                }
            } else {
                if (notification.immediate){
                    nd.notificationExpired = true;
                    nd.newNotifications.unshift(notification);
                } else {
                    nd.newNotifications.push(notification);
                }
            }
        }
    }

    /**
     * Adds chrome desktop notification
     *
     * @async
     * @param {Object}  notification    Notification object
     * @param {Object}  options         Notification options
     * @param {Object}  callbacks       Object with onButtonClicked, onClicked, onClosed notification handlers
     * @return {string}                 Chrome notification id
     */
    async addChromeNotification (notification, options, callbacks){
        if (!options){
            options = {};
        }
        options = _.defaultsDeep(options, {
            title: notification.message,
            type: 'image',
            message: '',
            iconUrl: 'file://' + path.join(_appWrapper.getExecPath(), this.getConfig('appNotifications.defaultIcon')),
            imageUrl: 'file://' + path.join(_appWrapper.getExecPath(), this.getConfig('appNotifications.defaultImage')),
            requireInteraction: true,
            isClickable: false,
            priority: 0,
            // buttons: [
            //     {
            //         title: 'Ok'
            //     },
            //     {
            //         title: 'Cancel'
            //     }
            // ],
        });
        if (!options.iconUrl){
            delete options.iconUrl;
        }

        if (!options.imageUrl){
            delete options.imageUrl;
        }

        return await this.showChromeNotification(options, callbacks);
    }

    /**
     * Shows chrome notification
     *
     * @async
     * @param  {Object} options     Chrome notification options
     * @param {Object}  callbacks   Object with onButtonClicked, onClicked, onClosed notification handlers
     * @return {string}             Chrome notification id
     */
    async showChromeNotification (options, callbacks) {
        this.log('Showing desktop notification "{1}"', 'info', [options.title]);

        let listeners = chrome.notifications.onClicked.getListeners();
        _.each(listeners, function(listener){
            chrome.notifications.onClicked.removeListener(listener.callback);
        });
        listeners = chrome.notifications.onClosed.getListeners();
        _.each(listeners, function(listener){
            chrome.notifications.onClosed.removeListener(listener.callback);
        });

        listeners = chrome.notifications.onButtonClicked.getListeners();
        _.each(listeners, function(listener){
            chrome.notifications.onButtonClicked.removeListener(listener.callback);
        });

        var returnPromise;
        var resolveReference;
        returnPromise = new Promise((resolve) => {
            resolveReference = resolve;
        });

        if (callbacks && _.isObject(callbacks)){
            chrome.notifications.onClicked.addListener((notificationId) => {
                // console.log('notif clickedd', notificationId);
                chrome.notifications.clear(notificationId);
                if (callbacks.onClicked && _.isFunction(callbacks.onClicked)){
                    callbacks.onClicked(notificationId);
                }
            });
            chrome.notifications.onClosed.addListener((notificationId, byUser) => {
                // console.log('notif closedd', notificationId, byUser);
                chrome.notifications.clear(notificationId);
                if (callbacks.onClosed && _.isFunction(callbacks.onClosed)){
                    callbacks.onClosed(notificationId, byUser);
                }
            });
            chrome.notifications.onButtonClicked.addListener((notificationId, buttonIndex) => {
                // console.log('notif button click', notificationId, buttonIndex);
                if (callbacks.onButtonClicked && _.isFunction(callbacks.onButtonClicked)){
                    callbacks.onButtonClicked(notificationId, buttonIndex);
                }
            });
        }

        chrome.notifications.create(_appWrapper.getHelper('util').uuid(), options, (notificationId) => { resolveReference(notificationId);});
        return returnPromise;
    }

    /**
     * Update chrome desktop notification
     *
     * @async
     * @param  {string} notificationId Chrome notification id
     * @param  {Object} options        Chrome notification options
     * @return {undefined}
     */
    async updateDesktopNotification (notificationId, options) {
        chrome.notifications.update(notificationId, options);
    }

    /**
     * Adds desktop notification
     *
     * @async
     * @param {Object} notification     Notification object
     * @param {Objcet} options          Notification options
     * @param {object} callbacks        Object with onshow, onClicked, onClosed and onerror notification handlers
     * @return {Notification}           Desktop notification instance
     */
    async addDesktopNotification (notification, options, callbacks){
        if (!options){
            options = {};
        }
        options = _.defaultsDeep(options, {
            body: '',
            icon: 'file://' + path.join(_appWrapper.getExecPath(), this.getConfig('appNotifications.defaultIcon')),
            badge: 'file://' + path.join(_appWrapper.getExecPath(), this.getConfig('appNotifications.defaultBadge')),
            image: 'file://' + path.join(_appWrapper.getExecPath(), this.getConfig('appNotifications.defaultImage')),
            vibrate: [200, 100, 200],
            requireInteraction: true,
            tag: _appWrapper.getHelper('util').uuid(),
            renotify: false,
        });

        if (options.message){
            options.body = options.message;
            delete options.message;
        }

        if (Notification.permission === 'granted') {
            return this.showDesktopNotification(notification, options, callbacks);
        } else if (Notification.permission !== 'denied') {
            var returnPromise;
            var resolveReference;
            returnPromise = new Promise((resolve) => {
                resolveReference = resolve;
            });
            Notification.requestPermission( (permission) => {
                if (permission === 'granted') {
                    let desktopNotification = this.showDesktopNotification(notification, options, callbacks);
                    resolveReference(desktopNotification);
                }
            });
            return returnPromise;
        }
    }

    /**
     * Shows desktop notification
     *
     * @param {Object} notification     Notification object
     * @param {Objcet} options          Notification options
     * @param {object} callbacks        Object with onshow, onClicked, onClosed and onerror notification handlers
     * @return {Notification}           Desktop notification instance
     */
    showDesktopNotification (notification, options, callbacks) {
        this.log('Showing desktop notification "{1}"', 'info', [notification.message]);
        let desktopNotification = new Notification(notification.message, options);
        if (callbacks && _.isObject(callbacks)){
            if (callbacks.onshow && _.isFunction(callbacks.onshow)){
                desktopNotification.onshow = callbacks.onshow;
            }
            if (callbacks.onClicked && _.isFunction(callbacks.onClicked)){
                desktopNotification.onclick = callbacks.onClicked;
            }
            if (callbacks.onClosed && _.isFunction(callbacks.onClosed)){
                desktopNotification.onclose = callbacks.onClosed;
            }
            if (callbacks.onerror && _.isFunction(callbacks.onerror)){
                desktopNotification.onerror = (e) => {
                    this.log('Desktop notification error "{1}"', 'error', [e]);
                    callbacks.onerror(e);
                };
            } else {
                desktopNotification.onerror = (e) => {
                    this.log('Desktop notification error "{1}"', 'error', [e]);
                };
            }
        }
        return desktopNotification;
    }
}

exports.AppNotificationsHelper = AppNotificationsHelper;