feat(selection): add selection of read, unread, starred, etc

Summary:
Can select all, deselect-all, read, unread, starred, unstarred.

Yes, it's not REALLY select "all", but it uses the items in the current
`retainedRange`. This is actually similar to what gmail does (only selects
on the first page of a 100).

Test Plan: new test

Reviewers: juan, bengotow

Reviewed By: bengotow

Differential Revision: https://phab.nylas.com/D2241
This commit is contained in:
Evan Morikawa 2015-11-09 10:03:55 -05:00
parent 32ffc7123a
commit 119da453e1
5 changed files with 47 additions and 2 deletions

View file

@ -23,6 +23,12 @@ class ThreadListStore extends NylasStore
@listenTo AccountStore, @_onAccountChanged
@listenTo FocusedMailViewStore, @_onMailViewChanged
atom.commands.add "body",
'thread-list:select-read' : @_onSelectRead
'thread-list:select-unread' : @_onSelectUnread
'thread-list:select-starred' : @_onSelectStarred
'thread-list:select-unstarred': @_onSelectUnstarred
# 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
@ -81,6 +87,22 @@ class ThreadListStore extends NylasStore
Actions.setFocus(collection: 'thread', item: null)
_onSelectRead: =>
items = @_view.itemsCurrentlyInViewMatching (item) -> not item.unread
@_view.selection.set(items)
_onSelectUnread: =>
items = @_view.itemsCurrentlyInViewMatching (item) -> item.unread
@_view.selection.set(items)
_onSelectStarred: =>
items = @_view.itemsCurrentlyInViewMatching (item) -> item.starred
@_view.selection.set(items)
_onSelectUnstarred: =>
items = @_view.itemsCurrentlyInViewMatching (item) -> not item.starred
@_view.selection.set(items)
# Inbound Events
_onMailViewChanged: ->

View file

@ -13,8 +13,8 @@
'g l' : 'navigation:go-to-label'
### Threadlist selection ###
'* a': 'thread-list:select-all'
'* n': 'thread-list:deselect-all'
'* a': 'multiselect-list:select-all'
'* n': 'multiselect-list:deselect-all'
'* r': 'thread-list:select-read'
'* u': 'thread-list:select-unread'
'* s': 'thread-list:select-starred'

View file

@ -33,6 +33,14 @@ describe "ModelView", ->
beforeEach ->
@view = new TestModelView()
describe "itemsCurrentlyInViewMatching", ->
it "returns matching items", ->
@view.stubFillPage(0)
items = @view.itemsCurrentlyInViewMatching (item) ->
item.id == "A55"
expect(items.length).toBe 1
expect(items[0].id).toBe "A55"
describe "setRetainedRange", ->
it "should perform basic bounds checks to avoid fetching non-existent pages", ->
@view.setRetainedRange({start: -100, end: 15000})

View file

@ -83,6 +83,9 @@ class MultiselectList extends React.Component
'core:list-page-up': => @_onScrollByPage(-1)
'core:list-page-down': => @_onScrollByPage(1)
'application:pop-sheet': => @_onDeselect()
'multiselect-list:select-all': @_onSelectAll
'core:select-all': @_onSelectAll
'multiselect-list:deselect-all': => @_onDeselect()
render: =>
# IMPORTANT: DO NOT pass inline functions as props. _.isEqual thinks these
@ -152,6 +155,11 @@ class MultiselectList extends React.Component
return unless @state.handler
@state.handler.onSelect()
_onSelectAll: =>
return unless @state.handler
items = @state.dataView.itemsCurrentlyInViewMatching -> true
@state.dataView.selection.set(items)
_onDeselect: =>
return unless @_visible() and @state.dataView
@state.dataView.selection.clear()

View file

@ -73,6 +73,13 @@ class ModelView
pagesRetained: ->
[Math.floor(@_retainedRange.start / @_pageSize)..Math.floor(@_retainedRange.end / @_pageSize)]
itemsCurrentlyInViewMatching: (matchFn) ->
matchedItems = []
for index, page of @_pages
for item in (page.items ? [])
matchedItems.push item if matchFn(item)
return matchedItems
setRetainedRange: ({start, end}) ->
{start, end} = @padRetainedRange({start, end})
start = Math.max(0, Math.min(@count(), start))