|  |  |  | /*global $, Whisper, Backbone, textsecure, extension*/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This script should only be included in background.html
 | 
					
						
							|  |  |  | (function() { | 
					
						
							|  |  |  |   'use strict'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   window.Whisper = window.Whisper || {}; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   var conversations = new Whisper.ConversationCollection(); | 
					
						
							|  |  |  |   var inboxCollection = new (Backbone.Collection.extend({ | 
					
						
							|  |  |  |     initialize: function() { | 
					
						
							|  |  |  |       this.on('change:timestamp change:name change:number', this.sort); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       this.listenTo(conversations, 'add change:active_at', this.addActive); | 
					
						
							|  |  |  |       this.listenTo(conversations, 'reset', function() { | 
					
						
							|  |  |  |         this.reset([]); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       this.on( | 
					
						
							|  |  |  |         'add remove change:unreadCount', | 
					
						
							|  |  |  |         _.debounce(this.updateUnreadCount.bind(this), 1000) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       this.startPruning(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       this.collator = new Intl.Collator(); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     comparator: function(m1, m2) { | 
					
						
							|  |  |  |       var timestamp1 = m1.get('timestamp'); | 
					
						
							|  |  |  |       var timestamp2 = m2.get('timestamp'); | 
					
						
							|  |  |  |       if (timestamp1 && !timestamp2) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (timestamp2 && !timestamp1) { | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (timestamp1 && timestamp2 && timestamp1 !== timestamp2) { | 
					
						
							|  |  |  |         return timestamp2 - timestamp1; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var title1 = m1.getTitle().toLowerCase(); | 
					
						
							|  |  |  |       var title2 = m2.getTitle().toLowerCase(); | 
					
						
							|  |  |  |       return this.collator.compare(title1, title2); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     addActive: function(model) { | 
					
						
							|  |  |  |       if (model.get('active_at')) { | 
					
						
							|  |  |  |         this.add(model); | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         this.remove(model); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     updateUnreadCount: function() { | 
					
						
							|  |  |  |       var newUnreadCount = _.reduce( | 
					
						
							|  |  |  |         this.map(function(m) { | 
					
						
							|  |  |  |           return m.get('unreadCount'); | 
					
						
							|  |  |  |         }), | 
					
						
							|  |  |  |         function(item, memo) { | 
					
						
							|  |  |  |           return item + memo; | 
					
						
							|  |  |  |         }, | 
					
						
							|  |  |  |         0 | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |       storage.put('unreadCount', newUnreadCount); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (newUnreadCount > 0) { | 
					
						
							|  |  |  |         window.setBadgeCount(newUnreadCount); | 
					
						
							|  |  |  |         window.document.title = | 
					
						
							|  |  |  |           window.config.title + ' (' + newUnreadCount + ')'; | 
					
						
							|  |  |  |       } else { | 
					
						
							|  |  |  |         window.setBadgeCount(0); | 
					
						
							|  |  |  |         window.document.title = window.config.title; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       window.updateTrayIcon(newUnreadCount); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     startPruning: function() { | 
					
						
							|  |  |  |       var halfHour = 30 * 60 * 1000; | 
					
						
							|  |  |  |       this.interval = setInterval( | 
					
						
							|  |  |  |         function() { | 
					
						
							|  |  |  |           this.forEach(function(conversation) { | 
					
						
							|  |  |  |             conversation.trigger('prune'); | 
					
						
							|  |  |  |           }); | 
					
						
							|  |  |  |         }.bind(this), | 
					
						
							|  |  |  |         halfHour | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }))(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   window.getInboxCollection = function() { | 
					
						
							|  |  |  |     return inboxCollection; | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   window.ConversationController = { | 
					
						
							|  |  |  |     get: function(id) { | 
					
						
							|  |  |  |       if (!this._initialFetchComplete) { | 
					
						
							|  |  |  |         throw new Error( | 
					
						
							|  |  |  |           'ConversationController.get() needs complete initial fetch' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return conversations.get(id); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     // Needed for some model setup which happens during the initial fetch() call below
 | 
					
						
							|  |  |  |     getUnsafe: function(id) { | 
					
						
							|  |  |  |       return conversations.get(id); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     dangerouslyCreateAndAdd: function(attributes) { | 
					
						
							|  |  |  |       return conversations.add(attributes); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     getOrCreate: function(id, type) { | 
					
						
							|  |  |  |       if (typeof id !== 'string') { | 
					
						
							|  |  |  |         throw new TypeError("'id' must be a string"); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (type !== 'private' && type !== 'group') { | 
					
						
							|  |  |  |         throw new TypeError( | 
					
						
							|  |  |  |           `'type' must be 'private' or 'group'; got: '${type}'` | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       if (!this._initialFetchComplete) { | 
					
						
							|  |  |  |         throw new Error( | 
					
						
							|  |  |  |           'ConversationController.get() needs complete initial fetch' | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       var conversation = conversations.get(id); | 
					
						
							|  |  |  |       if (conversation) { | 
					
						
							|  |  |  |         return conversation; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       conversation = conversations.add({ | 
					
						
							|  |  |  |         id: id, | 
					
						
							|  |  |  |         type: type, | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       conversation.initialPromise = new Promise(function(resolve, reject) { | 
					
						
							|  |  |  |         if (!conversation.isValid()) { | 
					
						
							|  |  |  |           var validationError = conversation.validationError || {}; | 
					
						
							|  |  |  |           console.log( | 
					
						
							|  |  |  |             'Contact is not valid. Not saving, but adding to collection:', | 
					
						
							|  |  |  |             conversation.idForLogging(), | 
					
						
							|  |  |  |             validationError.stack | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return resolve(conversation); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         var deferred = conversation.save(); | 
					
						
							|  |  |  |         if (!deferred) { | 
					
						
							|  |  |  |           console.log('Conversation save failed! ', id, type); | 
					
						
							|  |  |  |           return reject(new Error('getOrCreate: Conversation save failed')); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         deferred.then(function() { | 
					
						
							|  |  |  |           resolve(conversation); | 
					
						
							|  |  |  |         }, reject); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return conversation; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     getOrCreateAndWait: function(id, type) { | 
					
						
							|  |  |  |       return this._initialPromise.then( | 
					
						
							|  |  |  |         function() { | 
					
						
							|  |  |  |           var conversation = this.getOrCreate(id, type); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           if (conversation) { | 
					
						
							|  |  |  |             return conversation.initialPromise.then(function() { | 
					
						
							|  |  |  |               return conversation; | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |           return Promise.reject( | 
					
						
							|  |  |  |             new Error('getOrCreateAndWait: did not get conversation') | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         }.bind(this) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     getAllGroupsInvolvingId: function(id) { | 
					
						
							|  |  |  |       var groups = new Whisper.GroupCollection(); | 
					
						
							|  |  |  |       return groups.fetchGroups(id).then(function() { | 
					
						
							|  |  |  |         return groups.map(function(group) { | 
					
						
							|  |  |  |           return conversations.add(group); | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     loadPromise: function() { | 
					
						
							|  |  |  |       return this._initialPromise; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     reset: function() { | 
					
						
							|  |  |  |       this._initialPromise = Promise.resolve(); | 
					
						
							|  |  |  |       conversations.reset([]); | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     load: function() { | 
					
						
							|  |  |  |       console.log('ConversationController: starting initial fetch'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       this._initialPromise = new Promise( | 
					
						
							|  |  |  |         function(resolve, reject) { | 
					
						
							|  |  |  |           conversations.fetch().then( | 
					
						
							|  |  |  |             function() { | 
					
						
							|  |  |  |               console.log('ConversationController: done with initial fetch'); | 
					
						
							|  |  |  |               this._initialFetchComplete = true; | 
					
						
							|  |  |  |               resolve(); | 
					
						
							|  |  |  |             }.bind(this), | 
					
						
							|  |  |  |             function(error) { | 
					
						
							|  |  |  |               console.log( | 
					
						
							|  |  |  |                 'ConversationController: initial fetch failed', | 
					
						
							|  |  |  |                 error && error.stack ? error.stack : error | 
					
						
							|  |  |  |               ); | 
					
						
							|  |  |  |               reject(error); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           ); | 
					
						
							|  |  |  |         }.bind(this) | 
					
						
							|  |  |  |       ); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       return this._initialPromise; | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |   }; | 
					
						
							|  |  |  | })(); |