mirror of
https://github.com/Foundry376/Mailspring.git
synced 2025-09-11 15:14:31 +08:00
feat(starred): Replace FocusedContentStore with FocusedMailViewStore, allows for starred
Summary: This diff fixes T3389 and makes it possible to define mail views which are not based on a category and focus them in the app. I think that we need to create a new index on the starred attribute to make sure the query runs fast. More tests WIP Test Plan: Run tests, more coming soon! Reviewers: dillon, evan Reviewed By: evan Maniphest Tasks: T3389 Differential Revision: https://phab.nylas.com/D1979
This commit is contained in:
parent
ee41722891
commit
1339ef19d3
21 changed files with 360 additions and 230 deletions
|
@ -62,6 +62,7 @@ class NylasExports
|
||||||
@require "Calendar", 'flux/models/calendar'
|
@require "Calendar", 'flux/models/calendar'
|
||||||
@require "Metadata", 'flux/models/metadata'
|
@require "Metadata", 'flux/models/metadata'
|
||||||
@require "DatabaseObjectRegistry", "database-object-registry"
|
@require "DatabaseObjectRegistry", "database-object-registry"
|
||||||
|
@require "MailViewFilter", 'mail-view-filter'
|
||||||
|
|
||||||
# Exported so 3rd party packages can subclass Model
|
# Exported so 3rd party packages can subclass Model
|
||||||
@load "Model", 'flux/models/model'
|
@load "Model", 'flux/models/model'
|
||||||
|
@ -110,7 +111,7 @@ class NylasExports
|
||||||
@require "FileDownloadStore", 'flux/stores/file-download-store'
|
@require "FileDownloadStore", 'flux/stores/file-download-store'
|
||||||
@require "DraftStoreExtension", 'flux/stores/draft-store-extension'
|
@require "DraftStoreExtension", 'flux/stores/draft-store-extension'
|
||||||
@require "FocusedContentStore", 'flux/stores/focused-content-store'
|
@require "FocusedContentStore", 'flux/stores/focused-content-store'
|
||||||
@require "FocusedCategoryStore", 'flux/stores/focused-category-store'
|
@require "FocusedMailViewStore", 'flux/stores/focused-mail-view-store'
|
||||||
@require "FocusedContactsStore", 'flux/stores/focused-contacts-store'
|
@require "FocusedContactsStore", 'flux/stores/focused-contacts-store'
|
||||||
@require "MessageBodyProcessor", 'flux/stores/message-body-processor'
|
@require "MessageBodyProcessor", 'flux/stores/message-body-processor'
|
||||||
@require "MessageStoreExtension", 'flux/stores/message-store-extension'
|
@require "MessageStoreExtension", 'flux/stores/message-store-extension'
|
||||||
|
|
|
@ -5,14 +5,18 @@ classNames = require 'classnames'
|
||||||
UnreadCountStore,
|
UnreadCountStore,
|
||||||
WorkspaceStore,
|
WorkspaceStore,
|
||||||
AccountStore,
|
AccountStore,
|
||||||
FocusedCategoryStore,
|
FocusedMailViewStore,
|
||||||
ChangeLabelsTask,
|
ChangeLabelsTask,
|
||||||
ChangeFolderTask,
|
ChangeFolderTask,
|
||||||
CategoryStore} = require 'nylas-exports'
|
CategoryStore} = require 'nylas-exports'
|
||||||
{RetinaImg, DropZone} = require 'nylas-component-kit'
|
{RetinaImg, DropZone} = require 'nylas-component-kit'
|
||||||
|
|
||||||
class AccountSidebarCategoryItem extends React.Component
|
class AccountSidebarMailViewItem extends React.Component
|
||||||
@displayName: 'AccountSidebarCategoryItem'
|
@displayName: 'AccountSidebarMailViewItem'
|
||||||
|
|
||||||
|
@propTypes:
|
||||||
|
select: React.PropTypes.bool
|
||||||
|
mailView: React.PropTypes.object.isRequired
|
||||||
|
|
||||||
constructor: (@props) ->
|
constructor: (@props) ->
|
||||||
@state =
|
@state =
|
||||||
|
@ -32,7 +36,7 @@ class AccountSidebarCategoryItem extends React.Component
|
||||||
|
|
||||||
render: =>
|
render: =>
|
||||||
unread = []
|
unread = []
|
||||||
if @props.item.name is "inbox" and @state.unreadCount > 0
|
if @props.mailView.category?.name is "inbox" and @state.unreadCount > 0
|
||||||
unread = <div className="unread item-count-box">{@state.unreadCount}</div>
|
unread = <div className="unread item-count-box">{@state.unreadCount}</div>
|
||||||
|
|
||||||
containerClass = classNames
|
containerClass = classNames
|
||||||
|
@ -42,28 +46,22 @@ class AccountSidebarCategoryItem extends React.Component
|
||||||
|
|
||||||
<DropZone className={containerClass}
|
<DropZone className={containerClass}
|
||||||
onClick={@_onClick}
|
onClick={@_onClick}
|
||||||
id={@props.item.id}
|
id={@props.mailView.id}
|
||||||
shouldAcceptDrop={@_shouldAcceptDrop}
|
shouldAcceptDrop={@_shouldAcceptDrop}
|
||||||
onDragStateChange={ ({isDropping}) => @setState({isDropping}) }
|
onDragStateChange={ ({isDropping}) => @setState({isDropping}) }
|
||||||
onDrop={@_onDrop}>
|
onDrop={@_onDrop}>
|
||||||
{unread}
|
{unread}
|
||||||
|
|
||||||
<div className="icon">{@_renderIcon()}</div>
|
<div className="icon">{@_renderIcon()}</div>
|
||||||
<div className="name">{@props.item.displayName}</div>
|
<div className="name">{@props.mailView.name}</div>
|
||||||
</DropZone>
|
</DropZone>
|
||||||
|
|
||||||
_renderIcon: ->
|
_renderIcon: ->
|
||||||
if @props.sectionType is "category" and AccountStore.current()
|
<RetinaImg name={@props.mailView.iconName} fallback={'folder.png'} mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
if AccountStore.current().usesLabels()
|
|
||||||
<RetinaImg name={"tag.png"} mode={RetinaImg.Mode.ContentIsMask} />
|
|
||||||
else
|
|
||||||
<RetinaImg name={"folder.png"} mode={RetinaImg.Mode.ContentIsMask} />
|
|
||||||
else if @props.sectionType is "mailboxes"
|
|
||||||
<RetinaImg name={"#{@props.item.name}.png"} fallback={'folder.png'} mode={RetinaImg.Mode.ContentIsMask} />
|
|
||||||
|
|
||||||
_shouldAcceptDrop: (e) =>
|
_shouldAcceptDrop: (e) =>
|
||||||
return false if @props.item.name in CategoryStore.LockedCategoryNames
|
return false if @props.mailView.isEqual(FocusedMailViewStore.mailView())
|
||||||
return false if @props.item.name is FocusedCategoryStore.categoryName()
|
return false unless @props.mailView.canApplyToThreads()
|
||||||
'nylas-thread-ids' in e.dataTransfer.types
|
'nylas-thread-ids' in e.dataTransfer.types
|
||||||
|
|
||||||
_onDrop: (e) =>
|
_onDrop: (e) =>
|
||||||
|
@ -71,28 +69,14 @@ class AccountSidebarCategoryItem extends React.Component
|
||||||
try
|
try
|
||||||
ids = JSON.parse(jsonString)
|
ids = JSON.parse(jsonString)
|
||||||
catch err
|
catch err
|
||||||
console.error("AccountSidebarCategoryItem onDrop: JSON parse #{err}")
|
console.error("AccountSidebarMailViewItem onDrop: JSON parse #{err}")
|
||||||
return unless ids
|
return unless ids
|
||||||
|
|
||||||
if AccountStore.current().usesLabels()
|
@props.mailView.applyToThreads(ids)
|
||||||
currentLabel = FocusedCategoryStore.category()
|
|
||||||
if currentLabel and not (currentLabel in CategoryStore.LockedCategoryNames)
|
|
||||||
labelsToRemove = [currentLabel]
|
|
||||||
|
|
||||||
task = new ChangeLabelsTask
|
|
||||||
threads: ids,
|
|
||||||
labelsToAdd: [@props.item],
|
|
||||||
labelsToRemove: labelsToRemove
|
|
||||||
else
|
|
||||||
task = new ChangeFolderTask
|
|
||||||
folder: @props.item,
|
|
||||||
threads: ids
|
|
||||||
|
|
||||||
Actions.queueTask(task)
|
|
||||||
|
|
||||||
_onClick: (event) =>
|
_onClick: (event) =>
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
Actions.selectRootSheet(WorkspaceStore.Sheet.Threads)
|
Actions.selectRootSheet(WorkspaceStore.Sheet.Threads)
|
||||||
Actions.focusCategory(@props.item)
|
Actions.focusMailView(@props.mailView)
|
||||||
|
|
||||||
module.exports = AccountSidebarCategoryItem
|
module.exports = AccountSidebarMailViewItem
|
|
@ -10,7 +10,8 @@ _ = require 'underscore'
|
||||||
Label,
|
Label,
|
||||||
Folder,
|
Folder,
|
||||||
Message,
|
Message,
|
||||||
FocusedCategoryStore,
|
MailViewFilter,
|
||||||
|
FocusedMailViewStore,
|
||||||
NylasAPI,
|
NylasAPI,
|
||||||
Thread} = require 'nylas-exports'
|
Thread} = require 'nylas-exports'
|
||||||
|
|
||||||
|
@ -27,7 +28,7 @@ class AccountSidebarStore extends NylasStore
|
||||||
|
|
||||||
selected: ->
|
selected: ->
|
||||||
if WorkspaceStore.rootSheet() is WorkspaceStore.Sheet.Threads
|
if WorkspaceStore.rootSheet() is WorkspaceStore.Sheet.Threads
|
||||||
FocusedCategoryStore.category()
|
FocusedMailViewStore.mailView()
|
||||||
else
|
else
|
||||||
WorkspaceStore.rootSheet()
|
WorkspaceStore.rootSheet()
|
||||||
|
|
||||||
|
@ -37,13 +38,17 @@ class AccountSidebarStore extends NylasStore
|
||||||
@listenTo CategoryStore, @_refreshSections
|
@listenTo CategoryStore, @_refreshSections
|
||||||
@listenTo WorkspaceStore, @_refreshSections
|
@listenTo WorkspaceStore, @_refreshSections
|
||||||
@listenTo DraftCountStore, @_refreshSections
|
@listenTo DraftCountStore, @_refreshSections
|
||||||
@listenTo FocusedCategoryStore, => @trigger()
|
@listenTo FocusedMailViewStore, => @trigger()
|
||||||
|
|
||||||
_refreshSections: =>
|
_refreshSections: =>
|
||||||
account = AccountStore.current()
|
account = AccountStore.current()
|
||||||
return unless account
|
return unless account
|
||||||
|
|
||||||
|
viewFilterForCategory = (cat) ->
|
||||||
|
return MailViewFilter.forCategory(cat)
|
||||||
|
|
||||||
userCategories = CategoryStore.getUserCategories()
|
userCategories = CategoryStore.getUserCategories()
|
||||||
|
userCategoryViews = _.map(userCategories, viewFilterForCategory)
|
||||||
|
|
||||||
# Our drafts are displayed via the `DraftListSidebarItem` which
|
# Our drafts are displayed via the `DraftListSidebarItem` which
|
||||||
# is loading into the `Drafts` Sheet.
|
# is loading into the `Drafts` Sheet.
|
||||||
|
@ -51,7 +56,11 @@ class AccountSidebarStore extends NylasStore
|
||||||
standardCategories = _.reject standardCategories, (category) =>
|
standardCategories = _.reject standardCategories, (category) =>
|
||||||
category.name is "drafts"
|
category.name is "drafts"
|
||||||
|
|
||||||
standardCategories.push(WorkspaceStore.Sheet["Drafts"])
|
standardViews = _.map(standardCategories, viewFilterForCategory)
|
||||||
|
standardViews.push(WorkspaceStore.Sheet["Drafts"])
|
||||||
|
|
||||||
|
starredView = MailViewFilter.forStarred()
|
||||||
|
standardViews.splice(1, 0, starredView)
|
||||||
|
|
||||||
# Find root views, add the Views section
|
# Find root views, add the Views section
|
||||||
# featureSheets = _.filter WorkspaceStore.Sheet, (sheet) ->
|
# featureSheets = _.filter WorkspaceStore.Sheet, (sheet) ->
|
||||||
|
@ -62,9 +71,15 @@ class AccountSidebarStore extends NylasStore
|
||||||
@_sections = []
|
@_sections = []
|
||||||
# if featureSheets.length > 0
|
# if featureSheets.length > 0
|
||||||
# @_sections.push { label: '', items: featureSheets, type: 'sheet' }
|
# @_sections.push { label: '', items: featureSheets, type: 'sheet' }
|
||||||
@_sections.push { label: 'Mailboxes', items: standardCategories, type: 'mailboxes' }
|
@_sections.push
|
||||||
|
label: 'Mailboxes'
|
||||||
|
items: standardViews
|
||||||
|
type: 'mailboxes'
|
||||||
# @_sections.push { label: 'Views', items: extraSheets, type: 'sheet' }
|
# @_sections.push { label: 'Views', items: extraSheets, type: 'sheet' }
|
||||||
@_sections.push { label: CategoryStore.categoryLabel(), items: userCategories, type: 'category' }
|
@_sections.push
|
||||||
|
label: CategoryStore.categoryLabel()
|
||||||
|
items: userCategoryViews
|
||||||
|
type: 'category'
|
||||||
|
|
||||||
@trigger()
|
@trigger()
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
React = require 'react'
|
React = require 'react'
|
||||||
{Actions, Category} = require("nylas-exports")
|
{Actions, MailViewFilter} = require("nylas-exports")
|
||||||
{ScrollRegion} = require("nylas-component-kit")
|
{ScrollRegion} = require("nylas-component-kit")
|
||||||
SidebarDividerItem = require("./account-sidebar-divider-item")
|
SidebarDividerItem = require("./account-sidebar-divider-item")
|
||||||
SidebarSheetItem = require("./account-sidebar-sheet-item")
|
SidebarSheetItem = require("./account-sidebar-sheet-item")
|
||||||
AccountSidebarStore = require ("./account-sidebar-store")
|
AccountSidebarStore = require ("./account-sidebar-store")
|
||||||
AccountSidebarCategoryItem = require("./account-sidebar-category-item")
|
AccountSidebarMailViewItem = require("./account-sidebar-mail-view-item")
|
||||||
|
|
||||||
class AccountSidebar extends React.Component
|
class AccountSidebar extends React.Component
|
||||||
@displayName: 'AccountSidebar'
|
@displayName: 'AccountSidebar'
|
||||||
|
@ -44,18 +44,22 @@ class AccountSidebar extends React.Component
|
||||||
_itemComponents: (section) =>
|
_itemComponents: (section) =>
|
||||||
section.items?.map (item) =>
|
section.items?.map (item) =>
|
||||||
return unless item
|
return unless item
|
||||||
if item instanceof Category
|
if item instanceof MailViewFilter
|
||||||
itemClass = AccountSidebarCategoryItem
|
<AccountSidebarMailViewItem
|
||||||
else if item.sidebarComponent
|
key={item.id ? item.type}
|
||||||
itemClass = item.sidebarComponent
|
mailView={item}
|
||||||
|
select={ item.isEqual(@state.selected) }/>
|
||||||
else
|
else
|
||||||
itemClass = SidebarSheetItem
|
if item.sidebarComponent
|
||||||
|
itemClass = item.sidebarComponent
|
||||||
|
else
|
||||||
|
itemClass = SidebarSheetItem
|
||||||
|
|
||||||
<itemClass
|
<itemClass
|
||||||
key={item.id ? item.type}
|
key={item.id ? item.type}
|
||||||
item={item}
|
item={item}
|
||||||
sectionType={section.type}
|
sectionType={section.type}
|
||||||
select={item.id is @state.selected?.id }/>
|
select={item.id is @state.selected?.id }/>
|
||||||
|
|
||||||
_onStoreChange: =>
|
_onStoreChange: =>
|
||||||
@setState @_getStateFromStores()
|
@setState @_getStateFromStores()
|
||||||
|
|
|
@ -85,6 +85,7 @@
|
||||||
top:1px;
|
top:1px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-top: @padding-small-vertical;
|
padding-top: @padding-small-vertical;
|
||||||
|
padding-bottom:@padding-small-vertical;
|
||||||
line-height: @line-height-small;
|
line-height: @line-height-small;
|
||||||
}
|
}
|
||||||
&.selected {
|
&.selected {
|
||||||
|
|
|
@ -2,6 +2,9 @@ React = require 'react'
|
||||||
{Actions} = require("nylas-exports")
|
{Actions} = require("nylas-exports")
|
||||||
moment = require 'moment'
|
moment = require 'moment'
|
||||||
|
|
||||||
|
# TODO: This file is out of date!
|
||||||
|
return
|
||||||
|
|
||||||
class CalendarBarItem extends React.Component
|
class CalendarBarItem extends React.Component
|
||||||
render: =>
|
render: =>
|
||||||
style =
|
style =
|
||||||
|
@ -28,7 +31,7 @@ class CalendarBarItem extends React.Component
|
||||||
|
|
||||||
_onClick: (event) =>
|
_onClick: (event) =>
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
Actions.focusCategory(@props.tag)
|
Actions.focusMailView(@props.tag)
|
||||||
|
|
||||||
|
|
||||||
module.exports = CalendarBarItem
|
module.exports = CalendarBarItem
|
||||||
|
|
|
@ -10,7 +10,7 @@ React = require 'react'
|
||||||
WorkspaceStore,
|
WorkspaceStore,
|
||||||
ChangeLabelsTask,
|
ChangeLabelsTask,
|
||||||
ChangeFolderTask,
|
ChangeFolderTask,
|
||||||
FocusedCategoryStore} = require 'nylas-exports'
|
FocusedMailViewStore} = require 'nylas-exports'
|
||||||
|
|
||||||
{Menu,
|
{Menu,
|
||||||
Popover,
|
Popover,
|
||||||
|
@ -252,7 +252,7 @@ class CategoryPicker extends React.Component
|
||||||
|
|
||||||
_isUserFacing: (allInInbox, category) =>
|
_isUserFacing: (allInInbox, category) =>
|
||||||
hiddenCategories = []
|
hiddenCategories = []
|
||||||
currentCategoryId = FocusedCategoryStore.categoryId()
|
currentCategoryId = FocusedMailViewStore.mailView().categoryId()
|
||||||
if @_account?.usesLabels()
|
if @_account?.usesLabels()
|
||||||
hiddenCategories = ["all", "spam", "trash", "drafts", "sent"]
|
hiddenCategories = ["all", "spam", "trash", "drafts", "sent"]
|
||||||
if allInInbox
|
if allInInbox
|
||||||
|
|
|
@ -19,16 +19,16 @@ class ThreadListIcon extends React.Component
|
||||||
return 'thread-icon-star'
|
return 'thread-icon-star'
|
||||||
|
|
||||||
if @props.thread.unread
|
if @props.thread.unread
|
||||||
return 'thread-icon-unread'
|
return 'thread-icon-unread thread-icon-star-on-hover'
|
||||||
|
|
||||||
msgs = @_nonDraftMessages()
|
msgs = @_nonDraftMessages()
|
||||||
last = msgs[msgs.length - 1]
|
last = msgs[msgs.length - 1]
|
||||||
|
|
||||||
if msgs.length > 1 and last.from[0]?.isMe()
|
if msgs.length > 1 and last.from[0]?.isMe()
|
||||||
if Utils.isForwardedMessage(last)
|
if Utils.isForwardedMessage(last)
|
||||||
return 'thread-icon-forwarded'
|
return 'thread-icon-forwarded thread-icon-star-on-hover'
|
||||||
else
|
else
|
||||||
return 'thread-icon-replied'
|
return 'thread-icon-replied thread-icon-star-on-hover'
|
||||||
|
|
||||||
return 'thread-icon-star-on-hover'
|
return 'thread-icon-star-on-hover'
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ NylasStore = require 'nylas-store'
|
||||||
FocusedContentStore,
|
FocusedContentStore,
|
||||||
ArchiveThreadHelper,
|
ArchiveThreadHelper,
|
||||||
TaskQueueStatusStore,
|
TaskQueueStatusStore,
|
||||||
FocusedCategoryStore} = require 'nylas-exports'
|
FocusedMailViewStore} = require 'nylas-exports'
|
||||||
|
|
||||||
# Public: A mutable text container with undo/redo support and the ability
|
# Public: A mutable text container with undo/redo support and the ability
|
||||||
# to annotate logical regions in the text.
|
# to annotate logical regions in the text.
|
||||||
|
@ -37,7 +37,7 @@ class ThreadListStore extends NylasStore
|
||||||
|
|
||||||
@listenTo DatabaseStore, @_onDataChanged
|
@listenTo DatabaseStore, @_onDataChanged
|
||||||
@listenTo AccountStore, @_onAccountChanged
|
@listenTo AccountStore, @_onAccountChanged
|
||||||
@listenTo FocusedCategoryStore, @_onCategoryChanged
|
@listenTo FocusedMailViewStore, @_onMailViewChanged
|
||||||
|
|
||||||
atom.config.observe 'core.workspace.mode', => @_autofocusForLayoutMode()
|
atom.config.observe 'core.workspace.mode', => @_autofocusForLayoutMode()
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ class ThreadListStore extends NylasStore
|
||||||
# has hot yet been populated from the database with the list of
|
# has hot yet been populated from the database with the list of
|
||||||
# categories and their corresponding ids. Once that is ready, the
|
# categories and their corresponding ids. Once that is ready, the
|
||||||
# CategoryStore will trigger, which will update the
|
# CategoryStore will trigger, which will update the
|
||||||
# FocusedCategoryStore, which will cause us to create a new
|
# FocusedMailViewStore, which will cause us to create a new
|
||||||
# @view.
|
# @view.
|
||||||
|
|
||||||
_resetInstanceVars: ->
|
_resetInstanceVars: ->
|
||||||
|
@ -67,23 +67,18 @@ class ThreadListStore extends NylasStore
|
||||||
@trigger(@)
|
@trigger(@)
|
||||||
|
|
||||||
createView: ->
|
createView: ->
|
||||||
categoryId = FocusedCategoryStore.categoryId()
|
mailViewFilter = FocusedMailViewStore.mailView()
|
||||||
account = AccountStore.current()
|
account = AccountStore.current()
|
||||||
return unless account
|
return unless account
|
||||||
|
|
||||||
if @_searchQuery
|
if @_searchQuery
|
||||||
@setView(new SearchView(@_searchQuery, account.id))
|
@setView(new SearchView(@_searchQuery, account.id))
|
||||||
|
|
||||||
else if account.id and categoryId
|
else if account.id and mailViewFilter
|
||||||
matchers = []
|
matchers = []
|
||||||
matchers.push Thread.attributes.accountId.equal(account.id)
|
matchers.push Thread.attributes.accountId.equal(account.id)
|
||||||
|
matchers = matchers.concat(mailViewFilter.matchers())
|
||||||
|
|
||||||
if account.usesLabels()
|
|
||||||
matchers.push Thread.attributes.labels.contains(categoryId)
|
|
||||||
else if account.usesFolders()
|
|
||||||
matchers.push Thread.attributes.folders.contains(categoryId)
|
|
||||||
else
|
|
||||||
throw new Error("Invalid organizationUnit")
|
|
||||||
view = new DatabaseView Thread, {matchers}, (ids) =>
|
view = new DatabaseView Thread, {matchers}, (ids) =>
|
||||||
DatabaseStore.findAll(Message)
|
DatabaseStore.findAll(Message)
|
||||||
.where(Message.attributes.threadId.in(ids))
|
.where(Message.attributes.threadId.in(ids))
|
||||||
|
@ -101,7 +96,7 @@ class ThreadListStore extends NylasStore
|
||||||
|
|
||||||
# Inbound Events
|
# Inbound Events
|
||||||
|
|
||||||
_onCategoryChanged: ->
|
_onMailViewChanged: ->
|
||||||
@createView()
|
@createView()
|
||||||
|
|
||||||
_onAccountChanged: ->
|
_onAccountChanged: ->
|
||||||
|
|
|
@ -10,7 +10,7 @@ classNames = require 'classnames'
|
||||||
WorkspaceStore,
|
WorkspaceStore,
|
||||||
AccountStore,
|
AccountStore,
|
||||||
CategoryStore,
|
CategoryStore,
|
||||||
FocusedCategoryStore} = require 'nylas-exports'
|
FocusedMailViewStore} = require 'nylas-exports'
|
||||||
|
|
||||||
ThreadListParticipants = require './thread-list-participants'
|
ThreadListParticipants = require './thread-list-participants'
|
||||||
ThreadListQuickActions = require './thread-list-quick-actions'
|
ThreadListQuickActions = require './thread-list-quick-actions'
|
||||||
|
@ -91,7 +91,7 @@ class ThreadList extends React.Component
|
||||||
if hasAttachments
|
if hasAttachments
|
||||||
attachment = <div className="thread-icon thread-icon-attachment"></div>
|
attachment = <div className="thread-icon thread-icon-attachment"></div>
|
||||||
|
|
||||||
currentCategoryId = FocusedCategoryStore.categoryId()
|
currentCategoryId = FocusedMailViewStore.mailView()?.categoryId()
|
||||||
allCategoryId = CategoryStore.getStandardCategory('all')?.id
|
allCategoryId = CategoryStore.getStandardCategory('all')?.id
|
||||||
ignoredIds = [currentCategoryId, allCategoryId]
|
ignoredIds = [currentCategoryId, allCategoryId]
|
||||||
|
|
||||||
|
@ -116,7 +116,7 @@ class ThreadList extends React.Component
|
||||||
c5 = new ListTabular.Column
|
c5 = new ListTabular.Column
|
||||||
name: "HoverActions"
|
name: "HoverActions"
|
||||||
resolver: (thread) =>
|
resolver: (thread) =>
|
||||||
currentCategoryId = FocusedCategoryStore.categoryId()
|
currentCategoryId = FocusedMailViewStore.mailView()?.categoryId()
|
||||||
<ThreadListQuickActions thread={thread} categoryId={currentCategoryId}/>
|
<ThreadListQuickActions thread={thread} categoryId={currentCategoryId}/>
|
||||||
|
|
||||||
@wideColumns = [c1, c2, c3, c4, c5]
|
@wideColumns = [c1, c2, c3, c4, c5]
|
||||||
|
|
|
@ -261,12 +261,11 @@
|
||||||
|
|
||||||
// stars
|
// stars
|
||||||
|
|
||||||
.thread-list .list-item:hover .thread-icon-star-on-hover:hover {
|
.thread-list .thread-icon-star:hover {
|
||||||
background-image:url(../static/images/thread-list/icon-star-action-hover-@2x.png);
|
background-image:url(../static/images/thread-list/icon-star-action-hover-@2x.png);
|
||||||
background-size: 16px;
|
background-size: 16px;
|
||||||
}
|
}
|
||||||
.thread-icon-star-on-hover:hover,
|
.thread-list .thread-icon-star-on-hover:hover {
|
||||||
.thread-list .list-item:hover .thread-icon-star-on-hover {
|
|
||||||
background-image:url(../static/images/thread-list/icon-star-hover-@2x.png);
|
background-image:url(../static/images/thread-list/icon-star-hover-@2x.png);
|
||||||
background-size: 16px;
|
background-size: 16px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
_ = require 'underscore'
|
_ = require 'underscore'
|
||||||
{Thread,
|
{Thread,
|
||||||
Actions,
|
Actions,
|
||||||
|
MailViewFilter,
|
||||||
AccountStore,
|
AccountStore,
|
||||||
CategoryStore,
|
CategoryStore,
|
||||||
DatabaseStore} = require 'nylas-exports'
|
DatabaseStore} = require 'nylas-exports'
|
||||||
|
@ -44,7 +45,9 @@ module.exports =
|
||||||
atom.displayWindow()
|
atom.displayWindow()
|
||||||
if AccountStore.current().id isnt thread.accountId
|
if AccountStore.current().id isnt thread.accountId
|
||||||
Actions.selectAccountId(thread.accountId)
|
Actions.selectAccountId(thread.accountId)
|
||||||
Actions.focusCategory(thread.categoryNamed('inbox'))
|
|
||||||
|
MailViewFilter filter = MailViewFilter.forCategory(thread.categoryNamed('inbox'))
|
||||||
|
Actions.focusMailView(filter)
|
||||||
Actions.setFocus(collection: 'thread', item: thread)
|
Actions.setFocus(collection: 'thread', item: thread)
|
||||||
|
|
||||||
_notifyMessages: ->
|
_notifyMessages: ->
|
||||||
|
|
|
@ -1,87 +0,0 @@
|
||||||
_ = require 'underscore'
|
|
||||||
|
|
||||||
Label = require '../../src/flux/models/label'
|
|
||||||
Folder = require '../../src/flux/models/folder'
|
|
||||||
|
|
||||||
CategoryStore = require '../../src/flux/stores/category-store'
|
|
||||||
AccountStore = require '../../src/flux/stores/account-store'
|
|
||||||
FocusedCategoryStore = require '../../src/flux/stores/focused-category-store'
|
|
||||||
|
|
||||||
describe "FocusedCategoryStore", ->
|
|
||||||
beforeEach ->
|
|
||||||
spyOn(FocusedCategoryStore, 'trigger')
|
|
||||||
FocusedCategoryStore._category = null
|
|
||||||
|
|
||||||
afterEach ->
|
|
||||||
atom.testOrganizationUnit = null
|
|
||||||
|
|
||||||
testStore = ->
|
|
||||||
describe "_onCategoryStoreChanged", ->
|
|
||||||
it "should set the current category to Inbox when it is unset", ->
|
|
||||||
FocusedCategoryStore._category = null
|
|
||||||
FocusedCategoryStore._onCategoryStoreChanged()
|
|
||||||
expect(FocusedCategoryStore.category().id).toEqual(@inboxCategory.id)
|
|
||||||
|
|
||||||
it "should set the current category to Inbox when the current category no longer exists in the CategoryStore", ->
|
|
||||||
otherAccountInbox = @inboxCategory.clone()
|
|
||||||
otherAccountInbox.serverId = 'other-id'
|
|
||||||
FocusedCategoryStore._category = otherAccountInbox
|
|
||||||
FocusedCategoryStore._onCategoryStoreChanged()
|
|
||||||
expect(FocusedCategoryStore.category().id).toEqual(@inboxCategory.id)
|
|
||||||
|
|
||||||
describe "_onSearchQueryCommitted", ->
|
|
||||||
it "should clear the focused category and trigger when a search query is committed", ->
|
|
||||||
FocusedCategoryStore._onFocusCategory(@userCategory)
|
|
||||||
FocusedCategoryStore._onSearchQueryCommitted('bla')
|
|
||||||
expect(FocusedCategoryStore.trigger).toHaveBeenCalled()
|
|
||||||
expect(FocusedCategoryStore.category()).toBe(null)
|
|
||||||
expect(FocusedCategoryStore.categoryName()).toBe(null)
|
|
||||||
|
|
||||||
it "should restore the category that was previously focused and trigger when a search query is cleared", ->
|
|
||||||
FocusedCategoryStore._onFocusCategory(@userCategory)
|
|
||||||
FocusedCategoryStore._onSearchQueryCommitted('bla')
|
|
||||||
expect(FocusedCategoryStore.category()).toEqual(null)
|
|
||||||
expect(FocusedCategoryStore.categoryName()).toEqual(null)
|
|
||||||
FocusedCategoryStore._onSearchQueryCommitted('')
|
|
||||||
expect(FocusedCategoryStore.trigger).toHaveBeenCalled()
|
|
||||||
expect(FocusedCategoryStore.category().id).toEqual(@userCategory.id)
|
|
||||||
expect(FocusedCategoryStore.categoryName()).toEqual(null)
|
|
||||||
|
|
||||||
describe "_onFocusCategory", ->
|
|
||||||
it "should focus the category and trigger when Actions.focusCategory is called", ->
|
|
||||||
FocusedCategoryStore._onFocusCategory(@userCategory)
|
|
||||||
expect(FocusedCategoryStore.trigger).toHaveBeenCalled()
|
|
||||||
expect(FocusedCategoryStore.categoryName()).toBe(null)
|
|
||||||
expect(FocusedCategoryStore.category().id).toEqual(@userCategory.id)
|
|
||||||
|
|
||||||
it "should do nothing if the category is already focused", ->
|
|
||||||
FocusedCategoryStore._onFocusCategory(@inboxCategory)
|
|
||||||
spyOn(FocusedCategoryStore, '_setCategory')
|
|
||||||
FocusedCategoryStore._onFocusCategory(@inboxCategory)
|
|
||||||
expect(FocusedCategoryStore._setCategory).not.toHaveBeenCalled()
|
|
||||||
|
|
||||||
describe 'when using labels', ->
|
|
||||||
beforeEach ->
|
|
||||||
atom.testOrganizationUnit = 'label'
|
|
||||||
|
|
||||||
@inboxCategory = new Label(id: 'id-123', name: 'inbox', displayName: "INBOX")
|
|
||||||
@userCategory = new Label(id: 'id-456', name: null, displayName: "MyCategory")
|
|
||||||
|
|
||||||
spyOn(CategoryStore, "getStandardCategory").andReturn @inboxCategory
|
|
||||||
spyOn(CategoryStore, "byId").andCallFake (id) =>
|
|
||||||
return @inboxCategory if id is @inboxCategory.id
|
|
||||||
return @userCategory if id is @userCategory.id
|
|
||||||
return null
|
|
||||||
|
|
||||||
testStore()
|
|
||||||
|
|
||||||
describe 'when using folders', ->
|
|
||||||
beforeEach ->
|
|
||||||
atom.testOrganizationUnit = 'folder'
|
|
||||||
|
|
||||||
@inboxCategory = new Folder(id: 'id-123', name: 'inbox', displayName: "INBOX")
|
|
||||||
@userCategory = new Folder(id: 'id-456', name: null, displayName: "MyCategory")
|
|
||||||
|
|
||||||
spyOn(CategoryStore, "getStandardCategory").andReturn @inboxCategory
|
|
||||||
|
|
||||||
testStore()
|
|
89
spec-nylas/stores/focused-mail-view-store-spec.coffee
Normal file
89
spec-nylas/stores/focused-mail-view-store-spec.coffee
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
_ = require 'underscore'
|
||||||
|
|
||||||
|
Label = require '../../src/flux/models/label'
|
||||||
|
Folder = require '../../src/flux/models/folder'
|
||||||
|
MailViewFilter = require '../../src/mail-view-filter'
|
||||||
|
|
||||||
|
CategoryStore = require '../../src/flux/stores/category-store'
|
||||||
|
AccountStore = require '../../src/flux/stores/account-store'
|
||||||
|
FocusedMailViewStore = require '../../src/flux/stores/focused-mail-view-store'
|
||||||
|
|
||||||
|
describe "FocusedMailViewStore", ->
|
||||||
|
beforeEach ->
|
||||||
|
spyOn(FocusedMailViewStore, 'trigger')
|
||||||
|
FocusedMailViewStore._mailView = null
|
||||||
|
|
||||||
|
afterEach ->
|
||||||
|
atom.testOrganizationUnit = null
|
||||||
|
|
||||||
|
testStore = ->
|
||||||
|
describe "_onCategoryStoreChanged", ->
|
||||||
|
it "should set the current category to Inbox when it is unset", ->
|
||||||
|
FocusedMailViewStore._mailView = null
|
||||||
|
FocusedMailViewStore._onCategoryStoreChanged()
|
||||||
|
expect(FocusedMailViewStore.mailView()).not.toBe(null)
|
||||||
|
expect(FocusedMailViewStore.mailView().categoryId()).toEqual(@inboxCategory.id)
|
||||||
|
|
||||||
|
it "should set the current category to Inbox when the current category no longer exists in the CategoryStore", ->
|
||||||
|
otherAccountInbox = @inboxCategory.clone()
|
||||||
|
otherAccountInbox.serverId = 'other-id'
|
||||||
|
FocusedMailViewStore._mailView = MailViewFilter.forCategory(otherAccountInbox)
|
||||||
|
FocusedMailViewStore._onCategoryStoreChanged()
|
||||||
|
expect(FocusedMailViewStore.mailView().categoryId()).toEqual(@inboxCategory.id)
|
||||||
|
|
||||||
|
describe "_onSearchQueryCommitted", ->
|
||||||
|
it "should clear the focused category and trigger when a search query is committed", ->
|
||||||
|
FocusedMailViewStore._onFocusMailView(@userFilter)
|
||||||
|
FocusedMailViewStore._onSearchQueryCommitted('bla')
|
||||||
|
expect(FocusedMailViewStore.trigger).toHaveBeenCalled()
|
||||||
|
expect(FocusedMailViewStore.mailView()).toBe(null)
|
||||||
|
|
||||||
|
it "should restore the category that was previously focused and trigger when a search query is cleared", ->
|
||||||
|
FocusedMailViewStore._onFocusMailView(@userFilter)
|
||||||
|
FocusedMailViewStore._onSearchQueryCommitted('bla')
|
||||||
|
expect(FocusedMailViewStore.mailView()).toEqual(null)
|
||||||
|
FocusedMailViewStore._onSearchQueryCommitted('')
|
||||||
|
expect(FocusedMailViewStore.trigger).toHaveBeenCalled()
|
||||||
|
expect(FocusedMailViewStore.mailView().categoryId()).toEqual(@userCategory.id)
|
||||||
|
|
||||||
|
describe "_onFocusMailView", ->
|
||||||
|
it "should focus the category and trigger when Actions.focusCategory is called", ->
|
||||||
|
FocusedMailViewStore._onFocusMailView(@userFilter)
|
||||||
|
expect(FocusedMailViewStore.trigger).toHaveBeenCalled()
|
||||||
|
expect(FocusedMailViewStore.mailView().categoryId()).toEqual(@userCategory.id)
|
||||||
|
|
||||||
|
it "should do nothing if the category is already focused", ->
|
||||||
|
FocusedMailViewStore._onFocusMailView(@inboxFilter)
|
||||||
|
spyOn(FocusedMailViewStore, '_setMailView')
|
||||||
|
FocusedMailViewStore._onFocusMailView(@inboxFilter)
|
||||||
|
expect(FocusedMailViewStore._setMailView).not.toHaveBeenCalled()
|
||||||
|
|
||||||
|
describe 'when using labels', ->
|
||||||
|
beforeEach ->
|
||||||
|
atom.testOrganizationUnit = 'label'
|
||||||
|
|
||||||
|
@inboxCategory = new Label(id: 'id-123', name: 'inbox', displayName: "INBOX")
|
||||||
|
@inboxFilter = MailViewFilter.forCategory(@inboxCategory)
|
||||||
|
@userCategory = new Label(id: 'id-456', name: null, displayName: "MyCategory")
|
||||||
|
@userFilter = MailViewFilter.forCategory(@userCategory)
|
||||||
|
|
||||||
|
spyOn(CategoryStore, "getStandardCategory").andReturn @inboxCategory
|
||||||
|
spyOn(CategoryStore, "byId").andCallFake (id) =>
|
||||||
|
return @inboxCategory if id is @inboxCategory.id
|
||||||
|
return @userCategory if id is @userCategory.id
|
||||||
|
return null
|
||||||
|
|
||||||
|
testStore()
|
||||||
|
|
||||||
|
describe 'when using folders', ->
|
||||||
|
beforeEach ->
|
||||||
|
atom.testOrganizationUnit = 'folder'
|
||||||
|
|
||||||
|
@inboxCategory = new Folder(id: 'id-123', name: 'inbox', displayName: "INBOX")
|
||||||
|
@inboxFilter = MailViewFilter.forCategory(@inboxCategory)
|
||||||
|
@userCategory = new Folder(id: 'id-456', name: null, displayName: "MyCategory")
|
||||||
|
@userFilter = MailViewFilter.forCategory(@userCategory)
|
||||||
|
|
||||||
|
spyOn(CategoryStore, "getStandardCategory").andReturn @inboxCategory
|
||||||
|
|
||||||
|
testStore()
|
|
@ -214,10 +214,10 @@ class Actions
|
||||||
*Scope: Window*
|
*Scope: Window*
|
||||||
|
|
||||||
```
|
```
|
||||||
Actions.focusCategory(<Category>)
|
Actions.focusMailView(<Category>)
|
||||||
```
|
```
|
||||||
###
|
###
|
||||||
@focusCategory: ActionScopeWindow
|
@focusMailView: ActionScopeWindow
|
||||||
|
|
||||||
###
|
###
|
||||||
Public: If the message with the provided id is currently beign displayed in the
|
Public: If the message with the provided id is currently beign displayed in the
|
||||||
|
|
|
@ -36,6 +36,7 @@ class CategoryStore extends NylasStore
|
||||||
"drafts"
|
"drafts"
|
||||||
"all"
|
"all"
|
||||||
"archive"
|
"archive"
|
||||||
|
"starred"
|
||||||
]
|
]
|
||||||
|
|
||||||
AllMailName: "all"
|
AllMailName: "all"
|
||||||
|
@ -97,7 +98,7 @@ class CategoryStore extends NylasStore
|
||||||
#
|
#
|
||||||
getUserCategories: ->
|
getUserCategories: ->
|
||||||
userCategories = _.reject _.values(@_categoryCache), (cat) =>
|
userCategories = _.reject _.values(@_categoryCache), (cat) =>
|
||||||
cat.name in @StandardCategoryNames
|
cat.name in @StandardCategoryNames or cat.name in @HiddenCategoryNames
|
||||||
userCategories = _.sortBy(userCategories, 'displayName')
|
userCategories = _.sortBy(userCategories, 'displayName')
|
||||||
return _.compact(userCategories)
|
return _.compact(userCategories)
|
||||||
|
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
NylasStore = require 'nylas-store'
|
|
||||||
CategoryStore = require './category-store'
|
|
||||||
AccountStore = require './account-store'
|
|
||||||
Actions = require '../actions'
|
|
||||||
|
|
||||||
class FocusedCategoryStore extends NylasStore
|
|
||||||
constructor: ->
|
|
||||||
@listenTo CategoryStore, @_onCategoryStoreChanged
|
|
||||||
@listenTo Actions.focusCategory, @_onFocusCategory
|
|
||||||
@listenTo Actions.searchQueryCommitted, @_onSearchQueryCommitted
|
|
||||||
@_onCategoryStoreChanged()
|
|
||||||
|
|
||||||
# Inbound Events
|
|
||||||
_onCategoryStoreChanged: ->
|
|
||||||
if @_category?.id
|
|
||||||
category = CategoryStore.byId(@_category.id)
|
|
||||||
category ?= @_defaultCategory()
|
|
||||||
@_setCategory(category)
|
|
||||||
|
|
||||||
_onFocusCategory: (category) ->
|
|
||||||
return if @_category?.id is category?.id
|
|
||||||
|
|
||||||
if @_category is null and category
|
|
||||||
Actions.searchQueryCommitted('')
|
|
||||||
|
|
||||||
@_setCategory(category)
|
|
||||||
|
|
||||||
_onSearchQueryCommitted: (query="") ->
|
|
||||||
if typeof(query) != "string"
|
|
||||||
query = query[0].all
|
|
||||||
if query.trim().length > 0 and @_category
|
|
||||||
@_categoryBeforeSearch = @_category
|
|
||||||
@_setCategory(null)
|
|
||||||
else if query.trim().length is 0
|
|
||||||
if @_categoryBeforeSearch
|
|
||||||
@_setCategory(@_categoryBeforeSearch)
|
|
||||||
else
|
|
||||||
@_setCategory(@_defaultCategory())
|
|
||||||
|
|
||||||
_defaultCategory: ->
|
|
||||||
CategoryStore.getStandardCategory('inbox')
|
|
||||||
|
|
||||||
_setCategory: (category) ->
|
|
||||||
return if @_category?.id is category?.id
|
|
||||||
@_category = category
|
|
||||||
@trigger()
|
|
||||||
|
|
||||||
# Public Methods
|
|
||||||
|
|
||||||
category: -> @_category ? null
|
|
||||||
|
|
||||||
categoryId: -> @_category?.id ? null
|
|
||||||
|
|
||||||
categoryName: -> @_category?.name ? null
|
|
||||||
|
|
||||||
module.exports = new FocusedCategoryStore()
|
|
54
src/flux/stores/focused-mail-view-store.coffee
Normal file
54
src/flux/stores/focused-mail-view-store.coffee
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
NylasStore = require 'nylas-store'
|
||||||
|
MailViewFilter = require '../../mail-view-filter'
|
||||||
|
CategoryStore = require './category-store'
|
||||||
|
AccountStore = require './account-store'
|
||||||
|
Actions = require '../actions'
|
||||||
|
|
||||||
|
class FocusedMailViewStore extends NylasStore
|
||||||
|
constructor: ->
|
||||||
|
@listenTo CategoryStore, @_onCategoryStoreChanged
|
||||||
|
@listenTo Actions.focusMailView, @_onFocusMailView
|
||||||
|
@listenTo Actions.searchQueryCommitted, @_onSearchQueryCommitted
|
||||||
|
@_onCategoryStoreChanged()
|
||||||
|
|
||||||
|
# Inbound Events
|
||||||
|
_onCategoryStoreChanged: ->
|
||||||
|
if not @_mailView
|
||||||
|
@_setMailView(@_defaultMailView())
|
||||||
|
else
|
||||||
|
if not CategoryStore.byId(@_mailView.categoryId())
|
||||||
|
@_setMailView(@_defaultMailView())
|
||||||
|
|
||||||
|
_onFocusMailView: (filter) ->
|
||||||
|
return if filter.isEqual(@_mailView)
|
||||||
|
if @_mailView is null and filter
|
||||||
|
Actions.searchQueryCommitted('')
|
||||||
|
@_setMailView(filter)
|
||||||
|
|
||||||
|
_onSearchQueryCommitted: (query="") ->
|
||||||
|
if typeof(query) != "string"
|
||||||
|
query = query[0].all
|
||||||
|
if query.trim().length > 0 and @_mailView
|
||||||
|
@_mailViewBeforeSearch = @_mailView
|
||||||
|
@_setMailView(null)
|
||||||
|
else if query.trim().length is 0
|
||||||
|
if @_mailViewBeforeSearch
|
||||||
|
@_setMailView(@_mailViewBeforeSearch)
|
||||||
|
else
|
||||||
|
@_setMailView(@_defaultMailView())
|
||||||
|
|
||||||
|
_defaultMailView: ->
|
||||||
|
category = CategoryStore.getStandardCategory('inbox')
|
||||||
|
return null unless category
|
||||||
|
MailViewFilter.forCategory(category)
|
||||||
|
|
||||||
|
_setMailView: (filter) ->
|
||||||
|
return if filter?.isEqual(@_mailView)
|
||||||
|
@_mailView = filter
|
||||||
|
@trigger()
|
||||||
|
|
||||||
|
# Public Methods
|
||||||
|
|
||||||
|
mailView: -> @_mailView ? null
|
||||||
|
|
||||||
|
module.exports = new FocusedMailViewStore()
|
|
@ -1,5 +1,5 @@
|
||||||
CategoryStore = require '../stores/category-store'
|
CategoryStore = require '../stores/category-store'
|
||||||
FocusedCategoryStore = require '../stores/focused-category-store'
|
FocusedMailViewStore = require '../stores/focused-mail-view-store'
|
||||||
|
|
||||||
ChangeLabelsTask = require './change-labels-task'
|
ChangeLabelsTask = require './change-labels-task'
|
||||||
ChangeFolderTask = require './change-folder-task'
|
ChangeFolderTask = require './change-folder-task'
|
||||||
|
@ -48,7 +48,8 @@ class ArchiveThreadHelper
|
||||||
threads: threads
|
threads: threads
|
||||||
|
|
||||||
else if account.usesLabels()
|
else if account.usesLabels()
|
||||||
currentLabel = FocusedCategoryStore.category()
|
viewCategoryId = FocusedMailViewStore.mailView().categoryId()
|
||||||
|
currentLabel = CategoryStore.byId(viewCategoryId)
|
||||||
currentLabel ?= CategoryStore.getStandardCategory("inbox")
|
currentLabel ?= CategoryStore.getStandardCategory("inbox")
|
||||||
|
|
||||||
params = {threads}
|
params = {threads}
|
||||||
|
|
123
src/mail-view-filter.coffee
Normal file
123
src/mail-view-filter.coffee
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
_ = require 'underscore'
|
||||||
|
|
||||||
|
AccountStore = require './flux/stores/account-store'
|
||||||
|
CategoryStore = require './flux/stores/category-store'
|
||||||
|
Thread = require './flux/models/thread'
|
||||||
|
Actions = require './flux/actions'
|
||||||
|
|
||||||
|
# This is a class cluster. Subclasses are not for external use!
|
||||||
|
# https://developer.apple.com/library/ios/documentation/General/Conceptual/CocoaEncyclopedia/ClassClusters/ClassClusters.html
|
||||||
|
|
||||||
|
class MailViewFilter
|
||||||
|
|
||||||
|
# Factory Methods
|
||||||
|
|
||||||
|
@forCategory: (category) ->
|
||||||
|
new CategoryMailViewFilter(category)
|
||||||
|
|
||||||
|
@forStarred: ->
|
||||||
|
new StarredMailViewFilter()
|
||||||
|
|
||||||
|
# Instance Methods
|
||||||
|
|
||||||
|
constructor: ->
|
||||||
|
|
||||||
|
isEqual: (other) ->
|
||||||
|
return false unless other and @constructor.name is other.constructor.name
|
||||||
|
return false if other.name isnt @name
|
||||||
|
|
||||||
|
matchers = @matchers()
|
||||||
|
otherMatchers = other.matchers()
|
||||||
|
return false if otherMatchers.length isnt matchers.length
|
||||||
|
|
||||||
|
for idx in [0...matchers.length]
|
||||||
|
if matchers[idx].value() isnt otherMatchers[idx].value()
|
||||||
|
return false
|
||||||
|
|
||||||
|
true
|
||||||
|
|
||||||
|
categoryId: ->
|
||||||
|
throw new Error("categoryId: Not implemented in base class.")
|
||||||
|
|
||||||
|
matchers: ->
|
||||||
|
throw new Error("matchers: Not implemented in base class.")
|
||||||
|
|
||||||
|
canApplyToThreads: ->
|
||||||
|
throw new Error("canApplyToThreads: Not implemented in base class.")
|
||||||
|
|
||||||
|
applyToThreads: (threadsOrIds) ->
|
||||||
|
throw new Error("applyToThreads: Not implemented in base class.")
|
||||||
|
|
||||||
|
|
||||||
|
class StarredMailViewFilter extends MailViewFilter
|
||||||
|
constructor: ->
|
||||||
|
@name = "Starred"
|
||||||
|
@iconName = "starred.png"
|
||||||
|
@
|
||||||
|
|
||||||
|
matchers: ->
|
||||||
|
[Thread.attributes.starred.equal(true)]
|
||||||
|
|
||||||
|
categoryId: ->
|
||||||
|
null
|
||||||
|
|
||||||
|
canApplyToThreads: ->
|
||||||
|
true
|
||||||
|
|
||||||
|
applyToThreads: (threadsOrIds) ->
|
||||||
|
ChangeStarredTask = require './flux/tasks/change-starred-task'
|
||||||
|
task = new ChangeStarredTask({threads:threadsOrIds, starred: true})
|
||||||
|
Actions.queueTask(task)
|
||||||
|
|
||||||
|
|
||||||
|
class CategoryMailViewFilter extends MailViewFilter
|
||||||
|
constructor: (cat) ->
|
||||||
|
@name = cat.displayName
|
||||||
|
@category = cat
|
||||||
|
|
||||||
|
if cat.name
|
||||||
|
@iconName = "#{cat.name}.png"
|
||||||
|
else if AccountStore.current().usesLabels()
|
||||||
|
@iconName = "tag.png"
|
||||||
|
else
|
||||||
|
@iconName = "folder.png"
|
||||||
|
|
||||||
|
@
|
||||||
|
|
||||||
|
matchers: ->
|
||||||
|
account = AccountStore.current()
|
||||||
|
matchers = []
|
||||||
|
if account.usesLabels()
|
||||||
|
matchers.push Thread.attributes.labels.contains(@category.id)
|
||||||
|
else if account.usesFolders()
|
||||||
|
matchers.push Thread.attributes.folders.contains(@category.id)
|
||||||
|
matchers
|
||||||
|
|
||||||
|
categoryId: ->
|
||||||
|
@category.id
|
||||||
|
|
||||||
|
canApplyToThreads: ->
|
||||||
|
not (@category.name in CategoryStore.LockedCategoryNames)
|
||||||
|
|
||||||
|
applyToThreads: (threadsOrIds) ->
|
||||||
|
if AccountStore.current().usesLabels()
|
||||||
|
FocusedMailViewStore = require './flux/stores/focused-mail-view-store'
|
||||||
|
currentLabel = FocusedMailViewStore.mailView().category
|
||||||
|
if currentLabel and not (currentLabel in CategoryStore.LockedCategoryNames)
|
||||||
|
labelsToRemove = [currentLabel]
|
||||||
|
|
||||||
|
ChangeLabelsTask = require './flux/tasks/change-labels-task'
|
||||||
|
task = new ChangeLabelsTask
|
||||||
|
threads: threadsOrIds
|
||||||
|
labelsToAdd: [@category]
|
||||||
|
labelsToRemove: labelsToRemove
|
||||||
|
else
|
||||||
|
ChangeFolderTask = require './flux/tasks/change-folder-task'
|
||||||
|
task = new ChangeFolderTask
|
||||||
|
threads: threadsOrIds
|
||||||
|
folder: @category
|
||||||
|
|
||||||
|
Actions.queueTask(task)
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = MailViewFilter
|
|
@ -34,7 +34,7 @@ class WindowTitle extends React.Component
|
||||||
<div className="window-title">{@state.title}</div>
|
<div className="window-title">{@state.title}</div>
|
||||||
|
|
||||||
CategoryStore = null
|
CategoryStore = null
|
||||||
FocusedCategoryStore = null
|
FocusedMailViewStore = null
|
||||||
class ToolbarBack extends React.Component
|
class ToolbarBack extends React.Component
|
||||||
@displayName: 'ToolbarBack'
|
@displayName: 'ToolbarBack'
|
||||||
|
|
||||||
|
@ -42,13 +42,13 @@ class ToolbarBack extends React.Component
|
||||||
# This is because loading these stores has database side effects.
|
# This is because loading these stores has database side effects.
|
||||||
constructor: (@props) ->
|
constructor: (@props) ->
|
||||||
CategoryStore ?= require './flux/stores/category-store'
|
CategoryStore ?= require './flux/stores/category-store'
|
||||||
FocusedCategoryStore ?= require './flux/stores/focused-category-store'
|
FocusedMailViewStore ?= require './flux/stores/focused-mail-view-store'
|
||||||
@state =
|
@state =
|
||||||
categoryName: FocusedCategoryStore.categoryName()
|
categoryName: FocusedMailViewStore.mailView().name
|
||||||
|
|
||||||
componentDidMount: =>
|
componentDidMount: =>
|
||||||
@_unsubscriber = FocusedCategoryStore.listen =>
|
@_unsubscriber = FocusedMailViewStore.listen =>
|
||||||
@setState(categoryName: FocusedCategoryStore.categoryName())
|
@setState(categoryName: FocusedMailViewStore.mailView().name)
|
||||||
|
|
||||||
componentWillUnmount: =>
|
componentWillUnmount: =>
|
||||||
@_unsubscriber() if @_unsubscriber
|
@_unsubscriber() if @_unsubscriber
|
||||||
|
|
Loading…
Add table
Reference in a new issue