/*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; }, }; })();