Add select previous unread keyboard shortcut
This commit is contained in:
parent
6d24ea642a
commit
18d442d901
|
@ -23,6 +23,7 @@ class RootSplitViewController: UISplitViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func goToPreviousUnread(_ sender: Any?) {
|
@objc func goToPreviousUnread(_ sender: Any?) {
|
||||||
|
coordinator.selectPrevUnread()
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc func nextUnread(_ sender: Any?) {
|
@objc func nextUnread(_ sender: Any?) {
|
||||||
|
|
|
@ -717,6 +717,22 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func selectPrevUnread() {
|
||||||
|
|
||||||
|
// This should never happen, but I don't want to risk throwing us
|
||||||
|
// into an infinate loop searching for an unread that isn't there.
|
||||||
|
if appDelegate.unreadCount < 1 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if selectPrevUnreadArticleInTimeline() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
selectPrevUnreadFeedFetcher()
|
||||||
|
selectPrevUnreadArticleInTimeline()
|
||||||
|
}
|
||||||
|
|
||||||
func selectNextUnread() {
|
func selectNextUnread() {
|
||||||
|
|
||||||
// This should never happen, but I don't want to risk throwing us
|
// This should never happen, but I don't want to risk throwing us
|
||||||
|
@ -1048,11 +1064,113 @@ private extension SceneCoordinator {
|
||||||
self.showAvatars = false
|
self.showAvatars = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Select Prev Unread
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func selectPrevUnreadArticleInTimeline() -> Bool {
|
||||||
|
let startingRow: Int = {
|
||||||
|
if let indexPath = currentArticleIndexPath {
|
||||||
|
return indexPath.row - 1
|
||||||
|
} else {
|
||||||
|
return articles.count - 1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
return selectPrevArticleInTimeline(startingRow: startingRow)
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectPrevArticleInTimeline(startingRow: Int) -> Bool {
|
||||||
|
|
||||||
|
guard startingRow >= 0 else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for i in (0...startingRow).reversed() {
|
||||||
|
let article = articles[i]
|
||||||
|
if !article.status.read {
|
||||||
|
selectArticle(IndexPath(row: i, section: 0))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func selectPrevUnreadFeedFetcher() {
|
||||||
|
|
||||||
|
let indexPath: IndexPath = {
|
||||||
|
if currentFeedIndexPath == nil {
|
||||||
|
return IndexPath(row: 0, section: 0)
|
||||||
|
} else {
|
||||||
|
return currentFeedIndexPath!
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Increment or wrap around the IndexPath
|
||||||
|
let nextIndexPath: IndexPath = {
|
||||||
|
if indexPath.row - 1 < 0 {
|
||||||
|
if indexPath.section - 1 < 0 {
|
||||||
|
return IndexPath(row: shadowTable[shadowTable.count - 1].count - 1, section: shadowTable.count - 1)
|
||||||
|
} else {
|
||||||
|
return IndexPath(row: shadowTable[indexPath.section - 1].count - 1, section: indexPath.section - 1)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return IndexPath(row: indexPath.row - 1, section: indexPath.section)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if selectPrevUnreadFeedFetcher(startingWith: nextIndexPath) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let maxIndexPath = IndexPath(row: shadowTable[shadowTable.count - 1].count - 1, section: shadowTable.count - 1)
|
||||||
|
selectPrevUnreadFeedFetcher(startingWith: maxIndexPath)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@discardableResult
|
||||||
|
func selectPrevUnreadFeedFetcher(startingWith indexPath: IndexPath) -> Bool {
|
||||||
|
|
||||||
|
for i in (0...indexPath.section).reversed() {
|
||||||
|
|
||||||
|
let startingRow: Int = {
|
||||||
|
if indexPath.section == i {
|
||||||
|
return indexPath.row
|
||||||
|
} else {
|
||||||
|
return shadowTable[i].count - 1
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for j in (0...startingRow).reversed() {
|
||||||
|
|
||||||
|
let prevIndexPath = IndexPath(row: j, section: i)
|
||||||
|
guard let node = nodeFor(prevIndexPath), let unreadCountProvider = node.representedObject as? UnreadCountProvider else {
|
||||||
|
assertionFailure()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if expandedNodes.contains(node) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if unreadCountProvider.unreadCount > 0 {
|
||||||
|
selectFeed(prevIndexPath)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Select Next Unread
|
// MARK: Select Next Unread
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
func selectFirstUnreadArticleInTimeline() -> Bool {
|
func selectFirstUnreadArticleInTimeline() -> Bool {
|
||||||
return selectArticleInTimeline(startingRow: 0)
|
return selectNextArticleInTimeline(startingRow: 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@discardableResult
|
@discardableResult
|
||||||
|
@ -1065,10 +1183,10 @@ private extension SceneCoordinator {
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
return selectArticleInTimeline(startingRow: startingRow)
|
return selectNextArticleInTimeline(startingRow: startingRow)
|
||||||
}
|
}
|
||||||
|
|
||||||
func selectArticleInTimeline(startingRow: Int) -> Bool {
|
func selectNextArticleInTimeline(startingRow: Int) -> Bool {
|
||||||
|
|
||||||
guard startingRow < articles.count else {
|
guard startingRow < articles.count else {
|
||||||
return false
|
return false
|
||||||
|
@ -1088,10 +1206,13 @@ private extension SceneCoordinator {
|
||||||
|
|
||||||
func selectNextUnreadFeedFetcher() {
|
func selectNextUnreadFeedFetcher() {
|
||||||
|
|
||||||
guard let indexPath = currentFeedIndexPath else {
|
let indexPath: IndexPath = {
|
||||||
assertionFailure()
|
if currentFeedIndexPath == nil {
|
||||||
return
|
return IndexPath(row: -1, section: 0)
|
||||||
|
} else {
|
||||||
|
return currentFeedIndexPath!
|
||||||
}
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
// Increment or wrap around the IndexPath
|
// Increment or wrap around the IndexPath
|
||||||
let nextIndexPath: IndexPath = {
|
let nextIndexPath: IndexPath = {
|
||||||
|
@ -1118,7 +1239,15 @@ private extension SceneCoordinator {
|
||||||
|
|
||||||
for i in indexPath.section..<shadowTable.count {
|
for i in indexPath.section..<shadowTable.count {
|
||||||
|
|
||||||
for j in indexPath.row..<shadowTable[indexPath.section].count {
|
let startingRow: Int = {
|
||||||
|
if indexPath.section == i {
|
||||||
|
return indexPath.row
|
||||||
|
} else {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
for j in startingRow..<shadowTable[indexPath.section].count {
|
||||||
|
|
||||||
let nextIndexPath = IndexPath(row: j, section: i)
|
let nextIndexPath = IndexPath(row: j, section: i)
|
||||||
guard let node = nodeFor(nextIndexPath), let unreadCountProvider = node.representedObject as? UnreadCountProvider else {
|
guard let node = nodeFor(nextIndexPath), let unreadCountProvider = node.representedObject as? UnreadCountProvider else {
|
||||||
|
|
Loading…
Reference in New Issue