From 820eb3e16f478fbade93a1762a3e4b418793094b Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 14 Dec 2016 22:07:20 +0300 Subject: [PATCH] Initial Web Push support #981 --- app/js/lib/config.js | 3 +- app/js/lib/ng_utils.js | 110 ++++++++++++++++++++++++++++++++++++++ app/js/lib/push_worker.js | 48 ++++++++++++++++- app/js/services.js | 74 +++++++++---------------- app/service_worker.js | 4 +- 5 files changed, 187 insertions(+), 52 deletions(-) diff --git a/app/js/lib/config.js b/app/js/lib/config.js index d60d1c26..48b95077 100644 --- a/app/js/lib/config.js +++ b/app/js/lib/config.js @@ -37,7 +37,8 @@ Config.Modes = { ios_standalone: window.navigator.standalone && navigator.userAgent.match(/iOS|iPhone|iPad/), chrome_packed: window.chrome && chrome.app && chrome.app.window && true || false, animations: true, - memory_only: false + memory_only: false, + push_api: location.search.indexOf('push=1') == -1 } Config.Navigator = { diff --git a/app/js/lib/ng_utils.js b/app/js/lib/ng_utils.js index d9865138..73d4eb19 100755 --- a/app/js/lib/ng_utils.js +++ b/app/js/lib/ng_utils.js @@ -1980,3 +1980,113 @@ angular.module('izhukov.utils', []) return timeParams }) + + .service('WebPushApiManager', function ($timeout, $q, $rootScope) { + + var isAvailable = true + var isPushEnabled = false + var started = false + + if (!('PushManager' in window) || + !('Notification' in window) || + !('serviceWorker' in navigator)) { + console.warn('Push messaging is not supported.') + isAvailable = false + } + + if (Notification.permission === 'denied') { + console.warn('The user has blocked notifications.') + } + + function start() { + if (!started) { + started = true + getSubscription() + } + } + + function getSubscription() { + if (!isAvailable) { + return + } + navigator.serviceWorker.ready.then(function(reg) { + reg.pushManager.getSubscription().then(function(subscription) { + if (!subscription) { + console.log('Not yet subscribed to Push') + subscribe() + return + } + + isPushEnabled = true + pushSubscriptionNotify('init', subscription) + }) + .catch(function(err) { + console.log('Error during getSubscription()', err) + }) + }) + } + + function subscribe() { + if (!isAvailable) { + return + } + navigator.serviceWorker.ready.then(function(reg) { + reg.pushManager.subscribe({userVisibleOnly: true}).then(function(subscription) { + // The subscription was successful + isPushEnabled = true + pushSubscriptionNotify('subscribe', subscription) + }) + .catch(function(e) { + if (Notification.permission === 'denied') { + console.log('Permission for Notifications was denied') + } else { + console.log('Unable to subscribe to push.', e) + } + }) + }) + } + + function unsubscribe() { + if (!isAvailable) { + return + } + navigator.serviceWorker.ready.then(function(reg) { + reg.pushManager.getSubscription().then(function (subscription) { + pushSubscriptionNotify('unsubscribe', subscription) + + isPushEnabled = false + + if (subscription) { + setTimeout(function() { + subscription.unsubscribe().then(function(successful) { + isPushEnabled = false + }).catch(function(e) { + console.error('Unsubscription error: ', e) + }) + }, 3000) + } + + }).catch(function(e) { + console.error('Error thrown while unsubscribing from ' + + 'push messaging.', e) + }) + }) + } + + function pushSubscriptionNotify(event, subscription) { + console.warn(dT(), 'Push', event, subscription.toJSON()) + $rootScope.$emit('push_' + event, { + tokenType: 10, + tokenValue: JSON.stringify(subscription.toJSON()) + }) + } + + return { + isAvailable: isAvailable, + start: start, + isPushEnabled: isPushEnabled, + subscribe: subscribe, + unsubscribe: unsubscribe + } + + }) \ No newline at end of file diff --git a/app/js/lib/push_worker.js b/app/js/lib/push_worker.js index 4b322000..b87c8561 100644 --- a/app/js/lib/push_worker.js +++ b/app/js/lib/push_worker.js @@ -1 +1,47 @@ -console.log('push worker placeholder') +console.log('Push worker placeholder') + + +var port + +self.addEventListener('push', function(event) { + var obj = event.data.json() + console.log('push obj', obj) + fireNotification(obj, event) +}) + +self.onmessage = function(e) { + console.log(e) + port = e.ports[0] +} + +function fireNotification(obj, event) { + var title = obj.title || 'Telegram' + var body = obj.description || '' + var icon = 'img/Telegram72.png' + + event.waitUntil(self.registration.showNotification(title, { + body: body, + icon: icon + })) +} + + +self.addEventListener('notificationclick', function(event) { + console.log('On notification click: ', event.notification.tag) + event.notification.close() + + // This looks to see if the current is already open and + // focuses if it is + event.waitUntil(clients.matchAll({ + type: 'window' + }).then(function(clientList) { + for (var i = 0; i < clientList.length; i++) { + var client = clientList[i] + if ('focus' in client) { + return client.focus() + } + } + if (clients.openWindow) + return clients.openWindow('') + })) +}) \ No newline at end of file diff --git a/app/js/services.js b/app/js/services.js index 3094b3db..e8f92af8 100755 --- a/app/js/services.js +++ b/app/js/services.js @@ -3516,7 +3516,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } }) - .service('NotificationsManager', function ($rootScope, $window, $interval, $q, _, MtpApiManager, AppPeersManager, IdleManager, Storage, AppRuntimeManager, FileManager) { + .service('NotificationsManager', function ($rootScope, $window, $interval, $q, _, MtpApiManager, AppPeersManager, IdleManager, Storage, AppRuntimeManager, FileManager, WebPushApiManager) { navigator.vibrate = navigator.vibrate || navigator.mozVibrate || navigator.webkitVibrate var notificationsMsSiteMode = false @@ -3598,18 +3598,17 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) }) var registeredDevice = false - if (window.navigator.mozSetMessageHandler) { - window.navigator.mozSetMessageHandler('push', function (e) { - console.log(dT(), 'received push', e) - $rootScope.$broadcast('push_received') - }) - - window.navigator.mozSetMessageHandler('push-register', function (e) { - console.log(dT(), 'received push', e) - registeredDevice = false - registerDevice() - }) - } + $rootScope.$on('push_init', function (e, tokenData) { + if (tokenData) { + registerDevice(tokenData) + } + }) + $rootScope.$on('push_subscribe', function (e, tokenData) { + registerDevice(tokenData) + }) + $rootScope.$on('push_unsubscribe', function (e, tokenData) { + unregisterDevice(tokenData) + }) return { start: start, @@ -3702,7 +3701,7 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) function start () { updateNotifySettings() $rootScope.$on('settings_changed', updateNotifySettings) - registerDevice() + WebPushApiManager.start() if (!notificationsUiSupport) { return false @@ -3904,40 +3903,26 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) notificationsCount = 0 } - var registerDevicePeriod = 1000 - var registerDeviceTO - function registerDevice () { - if (registeredDevice) { + function registerDevice (tokenData) { + if (registeredDevice && + angular.equals(registeredDevice, tokenData)) { return false } - if (navigator.push && Config.Navigator.ffos && Config.Modes.packed) { - var req = navigator.push.register() - - req.onsuccess = function (e) { - clearTimeout(registerDeviceTO) - console.log(dT(), 'Push registered', req.result) - registeredDevice = req.result - MtpApiManager.invokeApi('account.registerDevice', { - token_type: 4, - token: registeredDevice - }) - } - - req.onerror = function (e) { - console.error('Push register error', e, e.toString()) - registerDeviceTO = setTimeout(registerDevice, registerDevicePeriod) - registerDevicePeriod = Math.min(30000, registerDevicePeriod * 1.5) - } - } + MtpApiManager.invokeApi('account.registerDevice', { + token_type: tokenData.tokenType, + token: tokenData.tokenValue + }).then(function () { + registeredDevice = tokenData + }) } - function unregisterDevice () { + function unregisterDevice (tokenData) { if (!registeredDevice) { return false } MtpApiManager.invokeApi('account.unregisterDevice', { - token_type: 4, - token: registeredDevice + token_type: tokenData.tokenType, + token: tokenData.tokenValue }).then(function () { registeredDevice = false }) @@ -4533,15 +4518,6 @@ angular.module('myApp.services', ['myApp.i18n', 'izhukov.utils']) } started = true - if ('registerProtocolHandler' in navigator) { - try { - navigator.registerProtocolHandler('tg', '#im?tgaddr=%s', 'Telegram Web') - } catch (e) {} - try { - navigator.registerProtocolHandler('web+tg', '#im?tgaddr=%s', 'Telegram Web') - } catch (e) {} - } - if (window.navigator.mozSetMessageHandler) { console.log(dT(), 'Set activity message handler') window.navigator.mozSetMessageHandler('activity', function (activityRequest) { diff --git a/app/service_worker.js b/app/service_worker.js index 3ad22968..dfdecfa0 100644 --- a/app/service_worker.js +++ b/app/service_worker.js @@ -1 +1,3 @@ -importScripts('js/lib/push_worker.js') +// Version 7 +importScripts('js/lib/push_worker.js?3') +