Mailspring/internal_packages/thread-list/lib/thread-list-store.coffee
Evan Morikawa f88b0f3708 feat(archive): shows trash for non-archive accounts
Summary:
Fixes T3570
Fixes T3737

Rename ArchiveThreadHelper to RemoveThreadHelper

Rename of `getRemovalTask`

Remove unarchive from `RemoveThreadHelper`. Pass in mailviewfilter

Rename actions

Rename archive action

renmaing

support trash and archive folders in RemoveThreadHelper

Move everything over to trash

add tests

Hide trash and archive

Test Plan: new tests

Reviewers: dillon, bengotow

Reviewed By: dillon, bengotow

Maniphest Tasks: T3570, T3737

Differential Revision: https://phab.nylas.com/D2089
2015-09-30 19:51:48 -07:00

254 lines
7.9 KiB
CoffeeScript

_ = require 'underscore'
NylasStore = require 'nylas-store'
{Thread,
Message,
Actions,
SearchView,
DatabaseView,
DatabaseStore,
AccountStore,
WorkspaceStore,
ChangeUnreadTask,
ChangeStarredTask,
FocusedContentStore,
RemoveThreadHelper,
TaskQueueStatusStore,
FocusedMailViewStore} = require 'nylas-exports'
# Public: A mutable text container with undo/redo support and the ability
# to annotate logical regions in the text.
class ThreadListStore extends NylasStore
constructor: ->
@_resetInstanceVars()
@listenTo Actions.removeSelection, @_onRemoveSelection
@listenTo Actions.removeCurrentlyFocusedThread, @_onRemoveAndAuto
@listenTo Actions.removeAndNext, @_onRemoveAndNext
@listenTo Actions.removeAndPrevious, @_onRemoveAndPrev
@listenTo Actions.moveThread, @_onMoveThread
@listenTo Actions.moveThreads, @_onMoveThreads
@listenTo Actions.toggleStarSelection, @_onToggleStarSelection
@listenTo Actions.toggleStarFocused, @_onToggleStarFocused
@listenTo Actions.toggleUnreadSelection, @_onToggleUnreadSelection
@listenTo DatabaseStore, @_onDataChanged
@listenTo AccountStore, @_onAccountChanged
@listenTo FocusedMailViewStore, @_onMailViewChanged
# We can't create a @view on construction because the CategoryStore
# has hot yet been populated from the database with the list of
# categories and their corresponding ids. Once that is ready, the
# CategoryStore will trigger, which will update the
# FocusedMailViewStore, which will cause us to create a new
# @view.
_resetInstanceVars: ->
@_lastQuery = null
view: ->
@_view
setView: (view) ->
@_viewUnlisten() if @_viewUnlisten
@_view = view
@_viewUnlisten = view.listen ->
@trigger(@)
,@
@trigger(@)
createView: ->
mailViewFilter = FocusedMailViewStore.mailView()
account = AccountStore.current()
return unless account and mailViewFilter
if mailViewFilter.searchQuery
@setView(new SearchView(mailViewFilter.searchQuery, account.id))
else
matchers = []
matchers.push Thread.attributes.accountId.equal(account.id)
matchers = matchers.concat(mailViewFilter.matchers())
view = new DatabaseView Thread, {matchers}, (ids) =>
DatabaseStore.findAll(Message)
.where(Message.attributes.threadId.in(ids))
.where(Message.attributes.accountId.equal(account.id))
.then (messages) ->
messagesByThread = {}
for id in ids
messagesByThread[id] = []
for message in messages
messagesByThread[message.threadId].push message
messagesByThread
if WorkspaceStore.layoutMode() is 'split'
# Set up a one-time listener to focus an item in the new view
unlisten = view.listen ->
if view.loaded()
Actions.setFocus(collection: 'thread', item: view.get(0))
unlisten()
@setView(view)
Actions.setFocus(collection: 'thread', item: null)
# Inbound Events
_onMailViewChanged: ->
@createView()
_onAccountChanged: ->
accountId = AccountStore.current()?.id
accountMatcher = (m) ->
m.attribute() is Thread.attributes.accountId and m.value() is accountId
return if @_view and _.find(@_view.matchers, accountMatcher)
@createView()
_onDataChanged: (change) ->
return unless @_view
if change.objectClass is Thread.name
@_view.invalidate({change: change, shallow: true})
if change.objectClass is Message.name
# Important: Until we optimize this so that it detects the set change
# and avoids a query, this should be debounced since it's very unimportant
_.defer =>
threadIds = _.uniq _.map change.objects, (m) -> m.threadId
@_view.invalidateMetadataFor(threadIds)
_onToggleStarSelection: ->
threads = @_view.selection.items()
focusedId = FocusedContentStore.focusedId('thread')
keyboardId = FocusedContentStore.keyboardCursorId('thread')
oneAlreadyStarred = false
for thread in threads
if thread.starred
oneAlreadyStarred = true
starred = not oneAlreadyStarred
task = new ChangeStarredTask({threads, starred})
Actions.queueTask(task)
_onToggleStarFocused: ->
focused = FocusedContentStore.focused('thread')
cursor = FocusedContentStore.keyboardCursor('thread')
if focused
task = new ChangeStarredTask(thread: focused, starred: !focused.starred)
else if cursor
task = new ChangeStarredTask(thread: cursor, starred: !cursor.starred)
if task
Actions.queueTask(task)
_onToggleUnreadSelection: ->
threads = @_view.selection.items()
allUnread = threads.every (t) ->
t.unread is true
unread = not allUnread
task = new ChangeUnreadTask {threads, unread}
Actions.queueTask task
_onRemoveAndAuto: ->
@_removeAndShiftBy('auto')
_onRemoveAndPrev: ->
@_removeAndShiftBy(-1)
_onRemoveAndNext: ->
@_removeAndShiftBy(1)
_removeAndShiftBy: (offset) ->
mailViewFilter = FocusedMailViewStore.mailView()
return unless mailViewFilter.canApplyToThreads()
focused = FocusedContentStore.focused('thread')
return unless focused
task = RemoveThreadHelper.getRemovalTask([focused], mailViewFilter)
@_moveAndShiftBy(offset, task)
_onRemoveSelection: ->
mailViewFilter = FocusedMailViewStore.mailView()
return unless mailViewFilter.canApplyToThreads()
selectedThreads = @_view.selection.items()
return unless selectedThreads.length > 0
task = RemoveThreadHelper.getRemovalTask(selectedThreads, mailViewFilter)
@_onMoveThreads(selectedThreads, task)
_onMoveThread: (thread, task) ->
@_moveAndShiftBy('auto', task)
_onMoveThreads: (threads, task) ->
threadIds = threads.map (thread) -> thread.id
focusedId = FocusedContentStore.focusedId('thread')
keyboardId = FocusedContentStore.keyboardCursorId('thread')
if focusedId in threadIds
changeFocused = true
if keyboardId in threadIds
changeKeyboardCursor = true
if changeFocused or changeKeyboardCursor
newFocusIndex = Number.MAX_VALUE
for thread in threads
newFocusIndex = Math.min(newFocusIndex, @_view.indexOfId(thread.id))
TaskQueueStatusStore.waitForPerformLocal(task).then =>
layoutMode = WorkspaceStore.layoutMode()
if changeFocused
item = @_view.get(newFocusIndex)
Actions.setFocus(collection: 'thread', item: item)
if changeKeyboardCursor
item = @_view.get(newFocusIndex)
Actions.setCursorPosition(collection: 'thread', item: item)
Actions.setFocus(collection: 'thread', item: item) if layoutMode is 'split'
Actions.queueTask(task)
@_view.selection.clear()
_moveAndShiftBy: (offset, task) ->
layoutMode = WorkspaceStore.layoutMode()
focused = FocusedContentStore.focused('thread')
explicitOffset = if offset is "auto" then false else true
return unless focused
# Determine the current index
index = @_view.indexOfId(focused.id)
return if index is -1
# Determine the next index we want to move to
if offset is 'auto'
if @_view.get(index - 1)?.unread
offset = -1
else
offset = 1
index = Math.min(Math.max(index + offset, 0), @_view.count() - 2)
nextKeyboard = nextFocus = @_view.get(index)
# Remove the current thread from selection
@_view.selection.remove(focused)
# If the user is in list mode and removed without specifically saying
# "remove and next" or "remove and prev", return to the thread list
# instead of focusing on the next message.
if layoutMode is 'list' and not explicitOffset
nextFocus = null
# Remove the current thread
TaskQueueStatusStore.waitForPerformLocal(task).then =>
Actions.setFocus(collection: 'thread', item: nextFocus)
Actions.setCursorPosition(collection: 'thread', item: nextKeyboard)
Actions.queueTask(task)
module.exports = new ThreadListStore()