fix(counts): Centralize handling of unread count / draft count

Fixes T2155 and T1765
This commit is contained in:
Ben Gotow 2015-06-26 16:02:08 -07:00
parent c6eeddd8e7
commit 4621f432b0
11 changed files with 141 additions and 64 deletions

View file

@ -48,6 +48,7 @@ Exports =
# Stores
DraftStore: require '../src/flux/stores/draft-store'
DraftCountStore: require '../src/flux/stores/draft-count-store'
DraftStoreExtension: require '../src/flux/stores/draft-store-extension'
MessageStore: require '../src/flux/stores/message-store'
ContactStore: require '../src/flux/stores/contact-store'
@ -60,6 +61,7 @@ Exports =
FileUploadStore: require '../src/flux/stores/file-upload-store'
FileDownloadStore: require '../src/flux/stores/file-download-store'
FocusedContactsStore: require '../src/flux/stores/focused-contacts-store'
UnreadCountStore: require '../src/flux/stores/unread-count-store'
# Errors
APIError: APIError

View file

@ -3,6 +3,8 @@ _ = require 'underscore'
{DatabaseStore,
NamespaceStore,
WorkspaceStore,
UnreadCountStore,
DraftCountStore,
Actions,
Tag,
Message,
@ -12,13 +14,11 @@ _ = require 'underscore'
AccountSidebarStore = Reflux.createStore
init: ->
@_inboxCount = null
@_tags = []
@_setStoreDefaults()
@_registerListeners()
@_populate()
@_populateInboxCount()
########### PUBLIC #####################################################
@ -40,6 +40,8 @@ AccountSidebarStore = Reflux.createStore
@listenTo DatabaseStore, @_onDataChanged
@listenTo NamespaceStore, @_onNamespaceChanged
@listenTo WorkspaceStore, @_onWorkspaceChanged
@listenTo UnreadCountStore, @_onCountChanged
@listenTo DraftCountStore, @_onCountChanged
@listenTo FocusedTagStore, @_onFocusChange
_populate: ->
@ -50,19 +52,6 @@ AccountSidebarStore = Reflux.createStore
@_tags = tags
@_build()
_populateInboxCount: ->
namespace = NamespaceStore.current()
return unless namespace
DatabaseStore.count(Thread, [
Thread.attributes.namespaceId.equal(namespace.id),
Thread.attributes.unread.equal(true),
Thread.attributes.tags.contains('inbox')
]).then (count) =>
if count isnt @_inboxCount
@_inboxCount = count
@_build()
_build: ->
tags = @_tags
@ -75,6 +64,10 @@ AccountSidebarStore = Reflux.createStore
# We ignore the trash tag because you can't trash anything
tags = _.reject tags, (tag) -> tag.id is "trash"
# Clone the tag objects so that components holding on to tags
# don't have identical object references with new data.
tags = _.map tags, (tag) -> new Tag(tag)
mainTagIDs = ['inbox', 'starred', 'drafts', 'sent', 'archive']
mainTags = _.filter tags, (tag) -> _.contains(mainTagIDs, tag.id)
userTags = _.reject tags, (tag) -> _.contains(mainTagIDs, tag.id)
@ -83,8 +76,9 @@ AccountSidebarStore = Reflux.createStore
mainTags = _.sortBy mainTags, (tag) -> mainTagIDs.indexOf(tag.id)
mainTags.push new Tag(name: 'All Mail', id: '*')
# Add the counts
inboxTag = _.find tags, (tag) -> tag.id is 'inbox'
inboxTag?.unreadCount = @_inboxCount
inboxTag?.unreadCount = UnreadCountStore.count()
# Sort user tags by name
userTags = _.sortBy(userTags, 'name')
@ -114,23 +108,19 @@ AccountSidebarStore = Reflux.createStore
_onNamespaceChanged: ->
@_refetchFromAPI()
@_populateInboxCount()
@_populate()
_onWorkspaceChanged: ->
@_populate()
_onCountChanged: ->
@_build()
_onFocusChange: ->
@trigger(@)
_onDataChanged: (change) ->
@populateInboxCountDebounced ?= _.debounce =>
@_populateInboxCount()
, 5000
if change.objectClass is Tag.name
@_populate()
if change.objectClass is Thread.name
@populateInboxCountDebounced()
module.exports = AccountSidebarStore

View file

@ -41,14 +41,14 @@ class AccountSidebar extends React.Component
</section>
_itemComponents: (section) =>
if section.type is 'tag'
itemClass = SidebarTagItem
else if section.type is 'sheet'
itemClass = SidebarSheetItem
else
throw new Error("Unsure how to render item type #{section.type}")
section.items?.map (item) =>
if section.type is 'tag'
itemClass = SidebarTagItem
else if section.type is 'sheet'
itemClass = item.sidebarComponent ? SidebarSheetItem
else
throw new Error("Unsure how to render item type #{section.type}")
<itemClass
key={item.id ? item.type}
item={item}

View file

@ -6,7 +6,7 @@ React = require 'react'
class StarButton extends React.Component
@displayName: "StarButton"
@propTypes:
thread: React.PropTypes.object.isRequired
thread: React.PropTypes.object
render: =>
selected = @props.thread? and @props.thread.isStarred()

View file

@ -0,0 +1,44 @@
React = require 'react'
_ = require 'underscore'
classNames = require 'classnames'
{Actions, Utils, WorkspaceStore, DraftCountStore} = require 'nylas-exports'
{RetinaImg} = require 'nylas-component-kit'
class DraftListSidebarItem extends React.Component
@displayName: 'DraftListSidebarItem'
constructor: (@props) ->
@state = @getStateFromStores()
componentDidMount: =>
@unsubscribe = DraftCountStore.listen(@_onCountChanged)
componentWillUnmount: =>
@unsubscribe()
getStateFromStores: =>
count: DraftCountStore.count()
_onCountChanged: =>
@setState(@getStateFromStores())
render: =>
classSet = classNames
'item': true
'selected': @props.select
unread = []
if @state.count > 0
unread = <div className="unread item-count-box">{@state.count}</div>
<div className={classSet} onClick={@_onClick}>
<RetinaImg name={'drafts.png'} mode={RetinaImg.Mode.ContentIsMask} />
<span className="name"> {@props.item.name}</span>
{unread}
</div>
_onClick: (event) =>
event.preventDefault()
Actions.selectRootSheet(@props.item)
module.exports = DraftListSidebarItem

View file

@ -6,11 +6,15 @@ React = require "react"
ThreadSelectionBar = require './thread-selection-bar'
ThreadList = require './thread-list'
DraftListSidebarItem = require './draft-list-sidebar-item'
DraftSelectionBar = require './draft-selection-bar'
DraftList = require './draft-list'
module.exports =
activate: (@state={}) ->
WorkspaceStore.defineSheet 'Drafts', {root: true, name: 'Local Drafts', sidebarComponent: DraftListSidebarItem},
list: ['RootSidebar', 'DraftList']
ComponentRegistry.register ThreadList,
location: WorkspaceStore.Location.ThreadList

View file

@ -1,8 +0,0 @@
module.exports =
activate: ->
@store = require "./unread-badge-store"
deactivate: ->
serialize: ->

View file

@ -1,13 +0,0 @@
{
"name": "unread-badge",
"version": "0.1.0",
"main": "./lib/main",
"description": "Updates the Mac's app icon to display unread count",
"license": "Proprietary",
"private": true,
"engines": {
"atom": "*"
},
"dependencies": {
}
}

View file

@ -0,0 +1,44 @@
Reflux = require 'reflux'
_ = require 'underscore'
NamespaceStore = require './namespace-store'
DatabaseStore = require './database-store'
DraftStore = require './draft-store'
Actions = require '../actions'
Message = require '../models/message'
###
Public: The DraftCountStore exposes a simple API for getting the number of
drafts in the user's account. If you plugin needs the number of drafts,
it's more efficient to observe the DraftCountStore than retrieve the value
yourself from the database.
###
DraftCountStore = Reflux.createStore
init: ->
@listenTo NamespaceStore, @_onNamespaceChanged
@listenTo DraftStore, @_onDraftChanged
@_count = null
_.defer => @_fetchCount()
# Public: Returns the number of drafts in the user's mailbox
count: ->
@_count
_onNamespaceChanged: ->
@_onDraftChanged()
_onDraftChanged: ->
@_fetchCountDebounced ?= _.debounce(@_fetchCount, 250)
@_fetchCountDebounced()
_fetchCount: ->
namespace = NamespaceStore.current()
return unless namespace
DatabaseStore.count(Message, [
Message.attributes.draft.equal(true)
]).then (count) =>
return if @_count is count
@_count = count
@trigger()
module.exports = DraftCountStore

View file

@ -1,17 +1,29 @@
Reflux = require 'reflux'
_ = require 'underscore'
{DatabaseStore, NamespaceStore, Actions, Thread} = require 'nylas-exports'
remote = require 'remote'
app = remote.require 'app'
NamespaceStore = require './namespace-store'
DatabaseStore = require './database-store'
Actions = require '../actions'
Thread = require '../models/thread'
AppUnreadCount = null
module.exports =
AppUnreadBadgeStore = Reflux.createStore
###
Public: The UnreadCountStore exposes a simple API for getting the number of
unread threads in the user's inbox. If you plugin needs the current unread count,
it's more efficient to observe the UnreadCountStore than retrieve the value
yourself from the database.
###
UnreadCountStore = Reflux.createStore
init: ->
@listenTo NamespaceStore, @_onNamespaceChanged
@listenTo DatabaseStore, @_onDataChanged
@_fetchCount()
@_count = null
_.defer => @_fetchCount()
# Public: Returns the number of unread threads in the user's mailbox
count: ->
@_count
_onNamespaceChanged: ->
@_onDataChanged()
@ -31,9 +43,9 @@ AppUnreadBadgeStore = Reflux.createStore
Thread.attributes.namespaceId.equal(namespace.id),
Thread.attributes.unread.equal(true),
Thread.attributes.tags.contains('inbox')
]).then (count) ->
return if AppUnreadCount is count
AppUnreadCount = count
]).then (count) =>
return if @_count is count
@_count = count
if count > 999
app.dock?.setBadge?("999+")
@ -41,3 +53,7 @@ AppUnreadBadgeStore = Reflux.createStore
app.dock?.setBadge?("#{count}")
else
app.dock?.setBadge?("")
@trigger()
module.exports = UnreadCountStore

View file

@ -48,11 +48,8 @@ class WorkspaceStore
@defineSheet 'Threads', {root: true},
list: ['RootSidebar', 'ThreadList']
split: ['RootSidebar', 'ThreadList', 'MessageList', 'MessageListSidebar']
@defineSheet 'Drafts', {root: true, name: 'Local Drafts'},
list: ['RootSidebar', 'DraftList']
@defineSheet 'Thread', {},
list: ['MessageList', 'MessageListSidebar']
@_onSelectRootSheet(Sheet.Threads)
else
@defineSheet 'Global'
@ -146,6 +143,7 @@ class WorkspaceStore
icon: options.icon
name: options.name
root: options.root
sidebarComponent: options.sidebarComponent
Toolbar:
Left: {id: "Sheet:#{id}:Toolbar:Left"}