Implement go to next unread

This commit is contained in:
Maurice Parker 2020-07-19 15:24:59 -05:00
parent de10e81e31
commit 68a569ec0b
4 changed files with 65 additions and 20 deletions

View File

@ -55,7 +55,10 @@ final class SceneModel: ObservableObject {
/// Goes to the next unread item found in Sidebar and Timeline order, top to bottom
func goToNextUnread() {
if !timelineModel.goToNextUnread() {
sidebarModel.goToNextUnread()
timelineModel.goToNextUnread()
}
}
// MARK: Article Management API

View File

@ -77,8 +77,22 @@ struct SidebarItem: Identifiable {
self.nameForDisplay = feed.nameForDisplay
}
/// Add a sidebar item to the child list
mutating func addChild(_ sidebarItem: SidebarItem) {
children.append(sidebarItem)
}
/// Recursively visits each sidebar item. Return true when done visiting.
@discardableResult
func visit(_ block: (SidebarItem) -> Bool) -> Bool {
let stop = block(self)
if !stop {
for child in children {
if child.visit(block) {
break
}
}
}
return stop
}
}

View File

@ -43,14 +43,11 @@ class SidebarModel: ObservableObject, UndoableCommandRunner {
// MARK: API
func goToNextUnread() {
guard let lastSelectedFeed = selectedFeeds.last,
let currentSidebarItem = sidebarItems.first(where: { $0.feed?.feedID == lastSelectedFeed.feedID }) else {
return
}
guard let startFeed = selectedFeeds.first ?? sidebarItems.first?.children.first?.feed else { return }
if !goToNextUnread(startingAt: currentSidebarItem) {
if let firstSidebarItem = sidebarItems.first {
goToNextUnread(startingAt: firstSidebarItem)
if !goToNextUnread(startingAt: startFeed) {
if let firstFeed = sidebarItems.first?.children.first?.feed {
goToNextUnread(startingAt: firstFeed)
}
}
}
@ -193,15 +190,30 @@ private extension SidebarModel {
}
@discardableResult
func goToNextUnread(startingAt: SidebarItem) -> Bool {
guard let startIndex = sidebarItems.firstIndex(where: { $0.id == startingAt.id }) else { return false }
for i in startIndex..<sidebarItems.count {
if sidebarItems[i].unreadCount > 0, let feedID = sidebarItems[i].feed?.feedID {
select(feedID)
return true
func goToNextUnread(startingAt: Feed) -> Bool {
var foundStartFeed = false
var nextSidebarItem: SidebarItem? = nil
for section in sidebarItems {
if nextSidebarItem == nil {
section.visit { sidebarItem in
if !foundStartFeed && sidebarItem.feed?.feedID == startingAt.feedID {
foundStartFeed = true
return false
}
if foundStartFeed && sidebarItem.unreadCount > 0 {
nextSidebarItem = sidebarItem
return true
}
return false
}
}
}
if let nextFeedID = nextSidebarItem?.feed?.feedID {
select(nextFeedID)
return true
}
return false
}

View File

@ -315,12 +315,23 @@ class TimelineModel: ObservableObject, UndoableCommandRunner {
openIndicatedArticleInBrowser(article)
}
func canGoToNextUnread() -> Bool {
return false
}
func goToNextUnread() {
@discardableResult
func goToNextUnread() -> Bool {
var startIndex: Int
if let firstArticle = selectedArticles.first, let index = timelineItems.firstIndex(where: { $0.article == firstArticle }) {
startIndex = index
} else {
startIndex = 0
}
for i in startIndex..<timelineItems.count {
if !timelineItems[i].article.status.read {
select(timelineItems[i].article.articleID)
return true
}
}
return false
}
func articleFor(_ articleID: String) -> Article? {
@ -382,6 +393,11 @@ private extension TimelineModel {
runCommand(markReadCommand)
}
func select(_ articleID: String) {
selectedArticleIDs = Set([articleID])
selectedArticleID = articleID
}
// MARK: Timeline Management
func resetReadFilter() {