| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  | /* global Signal:false */ | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  | /* global Backbone: false */ | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | /* global ConversationController: false */ | 
					
						
							| 
									
										
										
										
											2018-05-02 17:58:48 -04:00
										 |  |  |  | /* global drawAttention: false */ | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  | /* global i18n: false */ | 
					
						
							| 
									
										
										
										
											2018-05-02 17:58:48 -04:00
										 |  |  |  | /* global isFocused: false */ | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  | /* global Signal: false */ | 
					
						
							|  |  |  |  | /* global storage: false */ | 
					
						
							|  |  |  |  | /* global Whisper: false */ | 
					
						
							| 
									
										
										
										
											2018-05-10 17:07:42 -07:00
										 |  |  |  | /* global _: false */ | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | // eslint-disable-next-line func-names
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  | (function() { | 
					
						
							|  |  |  |  |   'use strict'; | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |   window.Whisper = window.Whisper || {}; | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |   const { Settings } = Signal.Types; | 
					
						
							| 
									
										
										
										
											2015-03-17 15:06:21 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 18:02:49 -04:00
										 |  |  |  |   const SettingNames = { | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |     COUNT: 'count', | 
					
						
							|  |  |  |  |     NAME: 'name', | 
					
						
							|  |  |  |  |     MESSAGE: 'message', | 
					
						
							|  |  |  |  |   }; | 
					
						
							| 
									
										
										
										
											2016-02-17 16:08:17 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |   Whisper.Notifications = new (Backbone.Collection.extend({ | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     initialize() { | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       this.isEnabled = false; | 
					
						
							|  |  |  |  |       this.on('add', this.update); | 
					
						
							|  |  |  |  |       this.on('remove', this.onRemove); | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       this.lastNotification = null; | 
					
						
							| 
									
										
										
										
											2018-05-10 17:07:42 -07:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |       // Testing indicated that trying to create/destroy notifications too quickly
 | 
					
						
							|  |  |  |  |       //   resulted in notifications that stuck around forever, requiring the user
 | 
					
						
							|  |  |  |  |       //   to manually close them. This introduces a minimum amount of time between calls,
 | 
					
						
							|  |  |  |  |       //   and batches up the quick successive update() calls we get from an incoming
 | 
					
						
							|  |  |  |  |       //   read sync, which might have a number of messages referenced inside of it.
 | 
					
						
							| 
									
										
										
										
											2018-05-10 17:27:22 -07:00
										 |  |  |  |       this.fastUpdate = this.update; | 
					
						
							| 
									
										
										
										
											2018-05-10 17:07:42 -07:00
										 |  |  |  |       this.update = _.debounce(this.update, 1000); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     onClick(conversationId) { | 
					
						
							|  |  |  |  |       const conversation = ConversationController.get(conversationId); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       this.trigger('click', conversation); | 
					
						
							|  |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     update() { | 
					
						
							| 
									
										
										
										
											2018-05-10 17:27:22 -07:00
										 |  |  |  |       if (this.lastNotification) { | 
					
						
							|  |  |  |  |         this.lastNotification.close(); | 
					
						
							|  |  |  |  |         this.lastNotification = null; | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       const { isEnabled } = this; | 
					
						
							| 
									
										
										
										
											2018-05-02 17:58:48 -04:00
										 |  |  |  |       const isAppFocused = isFocused(); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       const isAudioNotificationEnabled = | 
					
						
							|  |  |  |  |         storage.get('audio-notification') || false; | 
					
						
							|  |  |  |  |       const isAudioNotificationSupported = Settings.isAudioNotificationSupported(); | 
					
						
							| 
									
										
										
										
											2018-05-04 15:37:38 -04:00
										 |  |  |  |       const isNotificationGroupingSupported = Settings.isNotificationGroupingSupported(); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       const numNotifications = this.length; | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |       const userSetting = this.getUserSetting(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |       const status = Signal.Notifications.getStatus({ | 
					
						
							|  |  |  |  |         isAppFocused, | 
					
						
							|  |  |  |  |         isAudioNotificationEnabled, | 
					
						
							|  |  |  |  |         isAudioNotificationSupported, | 
					
						
							| 
									
										
										
										
											2018-05-02 18:33:58 -04:00
										 |  |  |  |         isEnabled, | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |         numNotifications, | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |         userSetting, | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-02-23 16:25:11 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-07-21 12:00:08 -07:00
										 |  |  |  |       window.log.info( | 
					
						
							| 
									
										
										
										
											2018-05-04 15:37:38 -04:00
										 |  |  |  |         'Update notifications:', | 
					
						
							|  |  |  |  |         Object.assign({}, status, { | 
					
						
							|  |  |  |  |           isNotificationGroupingSupported, | 
					
						
							|  |  |  |  |         }) | 
					
						
							|  |  |  |  |       ); | 
					
						
							| 
									
										
										
										
											2018-03-02 14:43:03 -05:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |       if (status.type !== 'ok') { | 
					
						
							|  |  |  |  |         if (status.shouldClearNotifications) { | 
					
						
							| 
									
										
										
										
											2018-05-10 17:27:22 -07:00
										 |  |  |  |           this.reset([]); | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2017-09-29 09:15:28 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |         return; | 
					
						
							|  |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2016-02-17 16:08:17 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |       let title; | 
					
						
							|  |  |  |  |       let message; | 
					
						
							|  |  |  |  |       let iconUrl; | 
					
						
							| 
									
										
										
										
											2017-04-27 18:31:35 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       // NOTE: i18n has more complex rules for pluralization than just
 | 
					
						
							|  |  |  |  |       // distinguishing between zero (0) and other (non-zero),
 | 
					
						
							|  |  |  |  |       // e.g. Russian:
 | 
					
						
							|  |  |  |  |       // http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html
 | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |       const newMessageCountLabel = `${numNotifications} ${ | 
					
						
							|  |  |  |  |         numNotifications === 1 ? i18n('newMessage') : i18n('newMessages') | 
					
						
							|  |  |  |  |       }`;
 | 
					
						
							| 
									
										
										
										
											2016-02-17 16:08:17 -08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |       const last = this.last().toJSON(); | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |       switch (userSetting) { | 
					
						
							| 
									
										
										
										
											2018-05-02 18:02:49 -04:00
										 |  |  |  |         case SettingNames.COUNT: | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           title = 'Signal'; | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |           message = newMessageCountLabel; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |         case SettingNames.NAME: { | 
					
						
							|  |  |  |  |           const lastMessageTitle = last.title; | 
					
						
							|  |  |  |  |           title = newMessageCountLabel; | 
					
						
							|  |  |  |  |           // eslint-disable-next-line prefer-destructuring
 | 
					
						
							|  |  |  |  |           iconUrl = last.iconUrl; | 
					
						
							|  |  |  |  |           if (numNotifications === 1) { | 
					
						
							|  |  |  |  |             message = `${i18n('notificationFrom')} ${lastMessageTitle}`; | 
					
						
							|  |  |  |  |           } else { | 
					
						
							|  |  |  |  |             message = `${i18n( | 
					
						
							|  |  |  |  |               'notificationMostRecentFrom' | 
					
						
							|  |  |  |  |             )} ${lastMessageTitle}`;
 | 
					
						
							|  |  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2018-05-02 18:02:49 -04:00
										 |  |  |  |         case SettingNames.MESSAGE: | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           if (numNotifications === 1) { | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |             // eslint-disable-next-line prefer-destructuring
 | 
					
						
							|  |  |  |  |             title = last.title; | 
					
						
							|  |  |  |  |             // eslint-disable-next-line prefer-destructuring
 | 
					
						
							|  |  |  |  |             message = last.message; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           } else { | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |             title = newMessageCountLabel; | 
					
						
							|  |  |  |  |             message = `${i18n('notificationMostRecent')} ${last.message}`; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           } | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |           // eslint-disable-next-line prefer-destructuring
 | 
					
						
							|  |  |  |  |           iconUrl = last.iconUrl; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |         default: | 
					
						
							| 
									
										
										
										
											2018-07-21 12:00:08 -07:00
										 |  |  |  |           window.log.error( | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |             `Error: Unknown user notification setting: '${userSetting}'` | 
					
						
							|  |  |  |  |           ); | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |           break; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       } | 
					
						
							| 
									
										
										
										
											2017-09-29 09:15:28 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |       const shouldHideExpiringMessageBody = | 
					
						
							|  |  |  |  |         last.isExpiringMessage && Signal.OS.isMacOS(); | 
					
						
							|  |  |  |  |       if (shouldHideExpiringMessageBody) { | 
					
						
							|  |  |  |  |         message = i18n('newMessage'); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |       drawAttention(); | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-02 19:06:03 -04:00
										 |  |  |  |       const notification = new Notification(title, { | 
					
						
							|  |  |  |  |         body: message, | 
					
						
							|  |  |  |  |         icon: iconUrl, | 
					
						
							| 
									
										
										
										
											2018-05-04 15:28:05 -04:00
										 |  |  |  |         tag: isNotificationGroupingSupported ? 'signal' : undefined, | 
					
						
							| 
									
										
										
										
											2018-05-02 19:06:03 -04:00
										 |  |  |  |         silent: !status.shouldPlayNotificationSound, | 
					
						
							|  |  |  |  |       }); | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |       notification.onclick = () => this.onClick(last.conversationId); | 
					
						
							|  |  |  |  |       this.lastNotification = notification; | 
					
						
							| 
									
										
										
										
											2017-09-29 09:15:28 -07:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-05-09 18:12:31 -04:00
										 |  |  |  |       // We continue to build up more and more messages for our notifications
 | 
					
						
							|  |  |  |  |       // until the user comes back to our app or closes the app. Then we’ll
 | 
					
						
							|  |  |  |  |       // clear everything out. The good news is that we'll have a maximum of
 | 
					
						
							|  |  |  |  |       // 1 notification in the Notification area (something like
 | 
					
						
							|  |  |  |  |       // ‘10 new messages’) assuming that `Notification::close` does its job.
 | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 18:04:00 -04:00
										 |  |  |  |     getUserSetting() { | 
					
						
							| 
									
										
										
										
											2018-05-02 18:02:49 -04:00
										 |  |  |  |       return storage.get('notification-setting') || SettingNames.MESSAGE; | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     onRemove() { | 
					
						
							| 
									
										
										
										
											2018-07-21 12:00:08 -07:00
										 |  |  |  |       window.log.info('Remove notification'); | 
					
						
							| 
									
										
										
										
											2018-05-10 17:27:22 -07:00
										 |  |  |  |       this.update(); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     clear() { | 
					
						
							| 
									
										
										
										
											2018-07-21 12:00:08 -07:00
										 |  |  |  |       window.log.info('Remove all notifications'); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       this.reset([]); | 
					
						
							| 
									
										
										
										
											2018-05-10 17:27:22 -07:00
										 |  |  |  |       this.update(); | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |     // We don't usually call this, but when the process is shutting down, we should at
 | 
					
						
							|  |  |  |  |     //   least try to remove the notification immediately instead of waiting for the
 | 
					
						
							|  |  |  |  |     //   normal debounce.
 | 
					
						
							|  |  |  |  |     fastClear() { | 
					
						
							|  |  |  |  |       this.reset([]); | 
					
						
							|  |  |  |  |       this.fastUpdate(); | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     enable() { | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       const needUpdate = !this.isEnabled; | 
					
						
							|  |  |  |  |       this.isEnabled = true; | 
					
						
							|  |  |  |  |       if (needUpdate) { | 
					
						
							|  |  |  |  |         this.update(); | 
					
						
							|  |  |  |  |       } | 
					
						
							|  |  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2018-05-02 16:43:32 -04:00
										 |  |  |  |     disable() { | 
					
						
							| 
									
										
										
										
											2018-04-27 17:25:04 -04:00
										 |  |  |  |       this.isEnabled = false; | 
					
						
							|  |  |  |  |     }, | 
					
						
							|  |  |  |  |   }))(); | 
					
						
							| 
									
										
										
										
											2015-03-17 15:06:21 -07:00
										 |  |  |  | })(); |