mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-11-12 12:40:08 +08:00
3d69ebbabb
Notifications now check to see the thread they are supposed to open exists. Also, clean up FocusedContentStore._onFocus so that it doesn't have the side effect of dispatching another action and messay logic. Instead, added Actions.ensureCategoryFocused, to focus any category, and which should be used separately from focusing content (notifications now use this action for "opening" the thread) Also, convert FocusedPerspectiveStore to ES6
207 lines
6.1 KiB
JavaScript
207 lines
6.1 KiB
JavaScript
import _ from 'underscore'
|
|
import {
|
|
Thread,
|
|
Actions,
|
|
SoundRegistry,
|
|
NativeNotifications,
|
|
DatabaseStore,
|
|
} from 'nylas-exports';
|
|
|
|
export class Notifier {
|
|
constructor() {
|
|
this.unlisteners = [];
|
|
this.unlisteners.push(Actions.didPassivelyReceiveNewModels.listen(this._onNewMailReceived, this));
|
|
this.activationTime = Date.now();
|
|
this.unnotifiedQueue = [];
|
|
this.hasScheduledNotify = false;
|
|
|
|
this.activeNotifications = {};
|
|
this.unlisteners.push(DatabaseStore.listen(this._onDatabaseUpdated, this));
|
|
}
|
|
|
|
unlisten() {
|
|
for (const unlisten of this.unlisteners) {
|
|
unlisten();
|
|
}
|
|
}
|
|
|
|
_onDatabaseUpdated({objectClass, objects}) {
|
|
if (objectClass === 'Thread') {
|
|
objects
|
|
.filter((thread) => !thread.unread)
|
|
.forEach((thread) => this._onThreadIsRead(thread));
|
|
}
|
|
}
|
|
|
|
_onThreadIsRead({id: threadId}) {
|
|
if (threadId in this.activeNotifications) {
|
|
this.activeNotifications[threadId].forEach((n) => n.close());
|
|
delete this.activeNotifications[threadId];
|
|
}
|
|
}
|
|
|
|
_notifyAll() {
|
|
NativeNotifications.displayNotification({
|
|
title: `${this.unnotifiedQueue.length} Unread Messages`,
|
|
tag: 'unread-update',
|
|
});
|
|
this.unnotifiedQueue = [];
|
|
}
|
|
|
|
_notifyOne({message, thread}) {
|
|
const from = (message.from[0]) ? message.from[0].displayName() : "Unknown";
|
|
const title = from;
|
|
let subtitle = null;
|
|
let body = null;
|
|
if (message.subject && message.subject.length > 0) {
|
|
subtitle = message.subject;
|
|
body = message.snippet;
|
|
} else {
|
|
subtitle = message.snippet
|
|
body = null
|
|
}
|
|
|
|
const notification = NativeNotifications.displayNotification({
|
|
title: title,
|
|
subtitle: subtitle,
|
|
body: body,
|
|
canReply: true,
|
|
tag: 'unread-update',
|
|
onActivate: ({response, activationType}) => {
|
|
if ((activationType === 'replied') && response && _.isString(response)) {
|
|
Actions.sendQuickReply({thread, message}, response);
|
|
} else {
|
|
NylasEnv.displayWindow()
|
|
}
|
|
|
|
if (!thread) {
|
|
NylasEnv.showErrorDialog(`Can't find that thread`)
|
|
return
|
|
}
|
|
Actions.ensureCategoryIsFocused('inbox', thread.accountId);
|
|
Actions.setFocus({collection: 'thread', item: thread});
|
|
},
|
|
});
|
|
|
|
if (!this.activeNotifications[thread.id]) {
|
|
this.activeNotifications[thread.id] = [notification];
|
|
} else {
|
|
this.activeNotifications[thread.id].push(notification);
|
|
}
|
|
}
|
|
|
|
_notifyMessages() {
|
|
if (this.unnotifiedQueue.length >= 5) {
|
|
this._notifyAll()
|
|
} else if (this.unnotifiedQueue.length > 0) {
|
|
this._notifyOne(this.unnotifiedQueue.shift());
|
|
}
|
|
|
|
this.hasScheduledNotify = false;
|
|
if (this.unnotifiedQueue.length > 0) {
|
|
setTimeout(() => this._notifyMessages(), 2000);
|
|
this.hasScheduledNotify = true;
|
|
}
|
|
}
|
|
|
|
// https://phab.nylas.com/D2188
|
|
_onNewMessagesMissingThreads(messages) {
|
|
setTimeout(() => {
|
|
const threads = {}
|
|
for (const {threadId} of messages) {
|
|
threads[threadId] = threads[threadId] || DatabaseStore.find(Thread, threadId);
|
|
}
|
|
Promise.props(threads).then((resolvedThreads) => {
|
|
const resolved = messages.filter((msg) => resolvedThreads[msg.threadId]);
|
|
if (resolved.length > 0) {
|
|
this._onNewMailReceived({message: resolved, thread: _.values(resolvedThreads)});
|
|
}
|
|
});
|
|
}, 10000);
|
|
}
|
|
|
|
_onNewMailReceived(incoming) {
|
|
return new Promise((resolve) => {
|
|
if (NylasEnv.config.get('core.notifications.enabled') === false) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
const incomingMessages = incoming.message || [];
|
|
const incomingThreads = incoming.thread || [];
|
|
|
|
// Filter for new messages that are not sent by the current user
|
|
const newUnread = incomingMessages.filter((msg) => {
|
|
const isUnread = msg.unread === true;
|
|
const isNew = msg.date && msg.date.valueOf() >= this.activationTime;
|
|
const isFromMe = msg.isFromMe();
|
|
return isUnread && isNew && !isFromMe;
|
|
});
|
|
|
|
if (newUnread.length === 0) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
// For each message, find it's corresponding thread. First, look to see
|
|
// if it's already in the `incoming` payload (sent via delta sync
|
|
// at the same time as the message.) If it's not, try loading it from
|
|
// the local cache.
|
|
|
|
// Note we may receive multiple unread msgs for the same thread.
|
|
// Using a map and ?= to avoid repeating work.
|
|
const threads = {}
|
|
for (const {threadId} of newUnread) {
|
|
threads[threadId] = threads[threadId] || _.findWhere(incomingThreads, {id: threadId})
|
|
threads[threadId] = threads[threadId] || DatabaseStore.find(Thread, threadId);
|
|
}
|
|
|
|
Promise.props(threads).then((resolvedThreads) => {
|
|
// Filter new unread messages to just the ones in the inbox
|
|
const newUnreadInInbox = newUnread.filter((msg) =>
|
|
resolvedThreads[msg.threadId] && resolvedThreads[msg.threadId].categoryNamed('inbox')
|
|
)
|
|
|
|
// Filter messages that we can't decide whether to display or not
|
|
// since no associated Thread object has arrived yet.
|
|
const newUnreadMissingThreads = newUnread.filter((msg) => !resolvedThreads[msg.threadId])
|
|
|
|
if (newUnreadMissingThreads.length > 0) {
|
|
this._onNewMessagesMissingThreads(newUnreadMissingThreads);
|
|
}
|
|
|
|
if (newUnreadInInbox.length === 0) {
|
|
resolve();
|
|
return;
|
|
}
|
|
|
|
for (const msg of newUnreadInInbox) {
|
|
this.unnotifiedQueue.push({message: msg, thread: resolvedThreads[msg.threadId]});
|
|
}
|
|
if (!this.hasScheduledNotify) {
|
|
if (NylasEnv.config.get("core.notifications.sounds")) {
|
|
SoundRegistry.playSound('new-mail');
|
|
}
|
|
this._notifyMessages();
|
|
}
|
|
|
|
resolve();
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
export const config = {
|
|
enabled: {
|
|
'type': 'boolean',
|
|
'default': true,
|
|
},
|
|
};
|
|
|
|
export function activate() {
|
|
this.notifier = new Notifier();
|
|
}
|
|
|
|
export function deactivate() {
|
|
this.notifier.unlisten();
|
|
}
|