2015-09-17 06:13:17 +00:00
|
|
|
/*global $, Whisper, Backbone, textsecure, extension*/
|
|
|
|
|
|
|
|
// This script should only be included in background.html
|
2018-04-27 21:25:04 +00:00
|
|
|
(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;
|
2015-09-17 06:13:17 +00:00
|
|
|
},
|
2018-04-27 21:25:04 +00:00
|
|
|
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);
|
2015-09-17 06:13:17 +00:00
|
|
|
}
|
2017-09-07 01:18:46 +00:00
|
|
|
|
2018-04-27 21:25:04 +00:00
|
|
|
var deferred = conversation.save();
|
|
|
|
if (!deferred) {
|
|
|
|
console.log('Conversation save failed! ', id, type);
|
|
|
|
return reject(new Error('getOrCreate: Conversation save failed'));
|
|
|
|
}
|
2017-09-01 16:10:41 +00:00
|
|
|
|
2018-04-27 21:25:04 +00:00
|
|
|
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;
|
2017-09-01 16:10:41 +00:00
|
|
|
});
|
2018-04-27 21:25:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
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)
|
|
|
|
);
|
2017-08-30 16:35:04 +00:00
|
|
|
|
2018-04-27 21:25:04 +00:00
|
|
|
return this._initialPromise;
|
|
|
|
},
|
|
|
|
};
|
2015-09-17 06:13:17 +00:00
|
|
|
})();
|