mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-02-01 21:07:59 +08:00
Unsnooze to top of inbox by default, fallback to mark as unread #267
This commit is contained in:
parent
ef0fe94d71
commit
5a145c415c
11 changed files with 92 additions and 57 deletions
|
@ -1,4 +1,4 @@
|
|||
import { React, PropTypes, Actions, SendActionsStore } from 'mailspring-exports';
|
||||
import { React, PropTypes, Actions, SendActionsStore, SoundRegistry } from 'mailspring-exports';
|
||||
import { Menu, RetinaImg, ButtonDropdown, ListensToFluxStore } from 'mailspring-component-kit';
|
||||
|
||||
class SendActionButton extends React.Component {
|
||||
|
@ -26,6 +26,9 @@ class SendActionButton extends React.Component {
|
|||
_onSendWithAction = sendAction => {
|
||||
const { isValidDraft, draft } = this.props;
|
||||
if (isValidDraft()) {
|
||||
if (AppEnv.config.get('core.sending.sounds')) {
|
||||
SoundRegistry.playSound('hit-send');
|
||||
}
|
||||
Actions.sendDraft(draft.headerMessageId, sendAction.configKey);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,12 +1,9 @@
|
|||
import {
|
||||
Actions,
|
||||
FocusedContentStore,
|
||||
SyncbackDraftTask,
|
||||
SendDraftTask,
|
||||
DatabaseStore,
|
||||
AccountStore,
|
||||
TaskQueue,
|
||||
Thread,
|
||||
Contact,
|
||||
DraftFactory,
|
||||
} from 'mailspring-exports';
|
||||
import MailspringStore from 'mailspring-store';
|
||||
|
@ -36,26 +33,13 @@ class SendRemindersStore extends MailspringStore {
|
|||
}
|
||||
|
||||
_sendReminderEmail = async (thread, sentHeaderMessageId) => {
|
||||
const account = AccountStore.accountForId(thread.accountId);
|
||||
const draft = await DraftFactory.createDraft({
|
||||
from: [new Contact({ email: account.emailAddress, name: `${account.name} via Mailspring` })],
|
||||
to: [account.defaultMe()],
|
||||
cc: [],
|
||||
pristine: false,
|
||||
subject: thread.subject,
|
||||
threadId: thread.id,
|
||||
accountId: thread.accountId,
|
||||
replyToHeaderMessageId: sentHeaderMessageId,
|
||||
body: `
|
||||
<strong>Mailspring Reminder:</strong> This thread has been moved to the top of
|
||||
your inbox by Mailspring because no one has replied to your message.</p>
|
||||
<p>--The Mailspring Team</p>`,
|
||||
});
|
||||
const body = `
|
||||
<strong>Mailspring Reminder:</strong> This thread has been moved to the top of
|
||||
your inbox by Mailspring because no one has replied to your message.</p>
|
||||
<p>--The Mailspring Team</p>`;
|
||||
|
||||
const saveTask = new SyncbackDraftTask({ draft });
|
||||
Actions.queueTask(saveTask);
|
||||
await TaskQueue.waitForPerformLocal(saveTask);
|
||||
Actions.sendDraft(draft.headerMessageId);
|
||||
const draft = await DraftFactory.createDraftForResurfacing(thread, sentHeaderMessageId, body);
|
||||
Actions.queueTask(new SendDraftTask({ draft, silent: true }));
|
||||
};
|
||||
|
||||
_onDraftDeliverySucceeded = ({ headerMessageId, accountId }) => {
|
||||
|
|
|
@ -29,7 +29,7 @@ class SnoozeMailLabel extends Component {
|
|||
}
|
||||
|
||||
const metadata = thread.metadataForPluginId(PLUGIN_ID);
|
||||
if (!metadata) {
|
||||
if (!metadata || !metadata.expiration) {
|
||||
return false;
|
||||
}
|
||||
const content = (
|
||||
|
|
|
@ -8,7 +8,7 @@ import {
|
|||
Thread,
|
||||
} from 'mailspring-exports';
|
||||
|
||||
import { markUnreadIfSet, moveThreads, snoozedUntilMessage } from './snooze-utils';
|
||||
import { markUnreadOrResurfaceThreads, moveThreads, snoozedUntilMessage } from './snooze-utils';
|
||||
import { PLUGIN_ID } from './snooze-constants';
|
||||
import SnoozeActions from './snooze-actions';
|
||||
|
||||
|
@ -92,23 +92,7 @@ class SnoozeStore extends MailspringStore {
|
|||
moveThreads(threads, { snooze: false, description: 'Unsnoozed' });
|
||||
|
||||
// mark the threads unread if setting is enabled
|
||||
markUnreadIfSet(threads, 'Unsnoozed message');
|
||||
|
||||
// remove the expiration on the metadata. note this is super important,
|
||||
// otherwise we'll receive a notification from the sync worker over and
|
||||
// over again.
|
||||
Actions.queueTasks(
|
||||
threads.map(
|
||||
model =>
|
||||
new SyncbackMetadataTask({
|
||||
model,
|
||||
pluginId: PLUGIN_ID,
|
||||
value: {
|
||||
expiration: null,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
markUnreadOrResurfaceThreads(threads, 'Unsnoozed message');
|
||||
};
|
||||
|
||||
_onMetadataExpired = threads => {
|
||||
|
@ -117,7 +101,25 @@ class SnoozeStore extends MailspringStore {
|
|||
return metadata && metadata.expiration && metadata.expiration < new Date();
|
||||
});
|
||||
if (unsnooze.length > 0) {
|
||||
this._onUnsnoozeThreads(unsnooze);
|
||||
// remove the expiration on the metadata. note this is super important,
|
||||
// otherwise we'll receive a notification from the sync worker over and
|
||||
// over again.
|
||||
Actions.queueTasks(
|
||||
threads.map(
|
||||
model =>
|
||||
new SyncbackMetadataTask({
|
||||
model,
|
||||
pluginId: PLUGIN_ID,
|
||||
value: {
|
||||
expiration: null,
|
||||
},
|
||||
})
|
||||
)
|
||||
);
|
||||
|
||||
// unsnooze messages that are still in the snoozed folder. (The user may have
|
||||
// moved the thread out of the snoozed folder using another client )
|
||||
this._onUnsnoozeThreads(unsnooze.filter(t => t.categories.find(c => c.role === 'snoozed')));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import {
|
|||
CategoryStore,
|
||||
ChangeLabelsTask,
|
||||
ChangeFolderTask,
|
||||
DraftFactory,
|
||||
SendDraftTask,
|
||||
} from 'mailspring-exports';
|
||||
|
||||
export function snoozedUntilMessage(snoozeDate, now = moment()) {
|
||||
|
@ -40,6 +42,7 @@ export function moveThreads(threads, { snooze, description } = {}) {
|
|||
taskDescription: description,
|
||||
labelsToAdd: snooze ? [snoozeCat] : [inboxCat],
|
||||
labelsToRemove: snooze ? [inboxCat] : [snoozeCat],
|
||||
canBeUndone: snooze ? true : false,
|
||||
});
|
||||
}
|
||||
return new ChangeFolderTask({
|
||||
|
@ -47,20 +50,37 @@ export function moveThreads(threads, { snooze, description } = {}) {
|
|||
threads: accountThreads,
|
||||
taskDescription: description,
|
||||
folder: snooze ? snoozeCat : inboxCat,
|
||||
canBeUndone: snooze ? true : false,
|
||||
});
|
||||
});
|
||||
|
||||
Actions.queueTasks(tasks);
|
||||
}
|
||||
|
||||
export function markUnreadIfSet(threads, source) {
|
||||
if (AppEnv.config.get('core.notifications.unreadOnSnooze')) {
|
||||
export async function markUnreadOrResurfaceThreads(threads, source) {
|
||||
if (AppEnv.config.get('core.notifications.unsnoozeToTop')) {
|
||||
// send a hidden email that will mark the thread as unread and bring it
|
||||
// to the top of your inbox in any mail client
|
||||
const body = `
|
||||
<strong>Mailspring Reminder:</strong> This thread has been moved to the top of
|
||||
your inbox by Mailspring.</p>
|
||||
<p>--The Mailspring Team</p>`;
|
||||
|
||||
for (const thread of threads) {
|
||||
const draft = await DraftFactory.createDraftForResurfacing(thread, null, body);
|
||||
Actions.queueTask(new SendDraftTask({ draft, silent: true }));
|
||||
}
|
||||
} else {
|
||||
// just mark the threads as unread (unless they're all already unread)
|
||||
if (!threads.some(t => !t.unread)) {
|
||||
return;
|
||||
}
|
||||
Actions.queueTask(
|
||||
TaskFactory.taskForSettingUnread({
|
||||
unread: true,
|
||||
threads: threads,
|
||||
source: source,
|
||||
canBeUndone: true,
|
||||
canBeUndone: false,
|
||||
})
|
||||
);
|
||||
}
|
||||
|
|
|
@ -158,10 +158,10 @@ export default {
|
|||
default: true,
|
||||
title: 'Play sound when receiving new mail',
|
||||
},
|
||||
unreadOnSnooze: {
|
||||
unsnoozeToTop: {
|
||||
type: 'boolean',
|
||||
default: false,
|
||||
title: 'Mark a message unread when returning from snooze',
|
||||
default: true,
|
||||
title: 'Resurface messages to the top of the inbox when unsnoozing',
|
||||
},
|
||||
countBadge: {
|
||||
type: 'string',
|
||||
|
|
|
@ -351,7 +351,7 @@ export default class Message extends ModelWithMetadata {
|
|||
this.to.length === 1 &&
|
||||
this.from.length === 1 &&
|
||||
this.to[0].email === this.from[0].email &&
|
||||
(this.snippet || '').startsWith('Mailspring Reminder:');
|
||||
(this.from[0].name || '').endsWith('via Mailspring');
|
||||
const isDraftBeingDeleted = this.id.startsWith('deleted-');
|
||||
|
||||
return isReminder || isDraftBeingDeleted;
|
||||
|
|
|
@ -103,7 +103,7 @@ module.exports =
|
|||
setupEmitter: ->
|
||||
return if @_emitter
|
||||
@_emitter ?= new EventEmitter()
|
||||
@_emitter.setMaxListeners(50)
|
||||
@_emitter.setMaxListeners(100)
|
||||
|
||||
listen: (callback, bindContext) ->
|
||||
if not callback
|
||||
|
|
|
@ -158,6 +158,33 @@ class DraftFactory
|
|||
</div>"""
|
||||
)
|
||||
|
||||
createDraftForResurfacing: (thread, threadMessageId, body) =>
|
||||
account = AccountStore.accountForId(thread.accountId)
|
||||
if threadMessageId
|
||||
rthmsid = Promise.resolve(threadMessageId)
|
||||
else
|
||||
rthmsid = DatabaseStore
|
||||
.findBy(Message, {accountId: thread.accountId, threadId: thread.id})
|
||||
.order(Message.attributes.date.descending())
|
||||
.limit(1)
|
||||
.then((msg) =>
|
||||
return (msg && msg.headerMessageId || "")
|
||||
)
|
||||
|
||||
return rthmsid.then((replyToHeaderMessageId) =>
|
||||
@createDraft({
|
||||
from: [new Contact({ email: account.emailAddress, name: "#{account.name} via Mailspring" })],
|
||||
to: [account.defaultMe()],
|
||||
cc: [],
|
||||
pristine: false,
|
||||
subject: thread.subject,
|
||||
threadId: thread.id,
|
||||
accountId: thread.accountId,
|
||||
replyToHeaderMessageId: replyToHeaderMessageId,
|
||||
body: body
|
||||
})
|
||||
)
|
||||
|
||||
candidateDraftForUpdating: (message, behavior) =>
|
||||
if behavior not in ['prefer-existing-if-pristine', 'prefer-existing']
|
||||
return Promise.resolve(null)
|
||||
|
|
|
@ -146,6 +146,9 @@ class DraftStore extends MailspringStore {
|
|||
};
|
||||
|
||||
_onSendQuickReply = ({ thread, threadId, message, messageId }, body) => {
|
||||
if (AppEnv.config.get('core.sending.sounds')) {
|
||||
SoundRegistry.playSound('hit-send');
|
||||
}
|
||||
return Promise.props(this._modelifyContext({ thread, threadId, message, messageId }))
|
||||
.then(({ message: m, thread: t }) => {
|
||||
return DraftFactory.createDraftForReply({ message: m, thread: t, type: 'reply' });
|
||||
|
@ -346,10 +349,6 @@ class DraftStore extends MailspringStore {
|
|||
throw new Error(`Cant find send action ${sendActionKey} `);
|
||||
}
|
||||
|
||||
if (AppEnv.config.get('core.sending.sounds')) {
|
||||
SoundRegistry.playSound('hit-send');
|
||||
}
|
||||
|
||||
// get the draft session, apply any last-minute edits and get the final draft.
|
||||
// We need to call `changes.commit` here to ensure the body of the draft is
|
||||
// completely saved and the user won't see old content briefly.
|
||||
|
|
|
@ -67,7 +67,7 @@ export default class SendDraftTask extends Task {
|
|||
}
|
||||
|
||||
label() {
|
||||
return 'Sending message';
|
||||
return this.silent ? null : 'Sending message';
|
||||
}
|
||||
|
||||
validate() {
|
||||
|
|
Loading…
Reference in a new issue