Merge pull request #2540 from danielpunkass/jalkut-skip-mode

Support a new secret user default…
This commit is contained in:
Maurice Parker 2020-11-01 16:54:15 -06:00 committed by GitHub
commit b504c88948
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 67 additions and 45 deletions

View File

@ -323,13 +323,16 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
NSCursor.setHiddenUntilMouseMoves(true) NSCursor.setHiddenUntilMouseMoves(true)
// TODO: handle search mode // TODO: handle search mode
if timelineViewController.canGoToNextUnread() { if timelineViewController.canGoToNextUnread(wrappingToTop: false) {
goToNextUnreadInTimeline() goToNextUnreadInTimeline(wrappingToTop: false)
} }
else if sidebarViewController.canGoToNextUnread() { else if sidebarViewController.canGoToNextUnread(wrappingToTop: true) {
sidebarViewController.goToNextUnread() sidebarViewController.goToNextUnread(wrappingToTop: true)
if timelineViewController.canGoToNextUnread() {
goToNextUnreadInTimeline() // If we ended up on the same timelineViewController, we may need to wrap
// around to the top of its contents.
if timelineViewController.canGoToNextUnread(wrappingToTop: true) {
goToNextUnreadInTimeline(wrappingToTop: true)
} }
} }
} }
@ -995,13 +998,13 @@ private extension MainWindowController {
// MARK: - Command Validation // MARK: - Command Validation
func canGoToNextUnread() -> Bool { func canGoToNextUnread(wrappingToTop wrapping: Bool = false) -> Bool {
guard let timelineViewController = currentTimelineViewController, let sidebarViewController = sidebarViewController else { guard let timelineViewController = currentTimelineViewController, let sidebarViewController = sidebarViewController else {
return false return false
} }
// TODO: handle search mode // TODO: handle search mode
return timelineViewController.canGoToNextUnread() || sidebarViewController.canGoToNextUnread() return timelineViewController.canGoToNextUnread(wrappingToTop: wrapping) || sidebarViewController.canGoToNextUnread(wrappingToTop: wrapping)
} }
func canMarkAllAsRead() -> Bool { func canMarkAllAsRead() -> Bool {
@ -1188,14 +1191,14 @@ private extension MainWindowController {
// MARK: - Misc. // MARK: - Misc.
func goToNextUnreadInTimeline() { func goToNextUnreadInTimeline(wrappingToTop wrapping: Bool) {
guard let timelineViewController = currentTimelineViewController else { guard let timelineViewController = currentTimelineViewController else {
return return
} }
if timelineViewController.canGoToNextUnread() { if timelineViewController.canGoToNextUnread(wrappingToTop: wrapping) {
timelineViewController.goToNextUnread() timelineViewController.goToNextUnread(wrappingToTop: wrapping)
makeTimelineViewFirstResponder() makeTimelineViewFirstResponder()
} }
} }

View File

@ -294,15 +294,15 @@ protocol SidebarDelegate: class {
// MARK: - Navigation // MARK: - Navigation
func canGoToNextUnread() -> Bool { func canGoToNextUnread(wrappingToTop wrapping: Bool = false) -> Bool {
if let _ = nextSelectableRowWithUnreadArticle() { if let _ = nextSelectableRowWithUnreadArticle(wrappingToTop: wrapping) {
return true return true
} }
return false return false
} }
func goToNextUnread() { func goToNextUnread(wrappingToTop wrapping: Bool = false) {
guard let row = nextSelectableRowWithUnreadArticle() else { guard let row = nextSelectableRowWithUnreadArticle(wrappingToTop: wrapping) else {
assertionFailure("goToNextUnread called before checking if there is a next unread.") assertionFailure("goToNextUnread called before checking if there is a next unread.")
return return
} }
@ -685,26 +685,42 @@ private extension SidebarViewController {
return false return false
} }
func nextSelectableRowWithUnreadArticle() -> Int? { func rowIsExpandedFolder(_ row: Int) -> Bool {
// Skip group items, because they should never be selected. if let node = nodeForRow(row), outlineView.isItemExpanded(node) {
return true
let selectedRow = outlineView.selectedRow
let numberOfRows = outlineView.numberOfRows
var row = selectedRow + 1
while (row < numberOfRows) {
if rowHasAtLeastOneUnreadArticle(row) && !rowIsGroupItem(row) {
return row
}
row += 1
} }
return false
row = 0 }
while (row <= selectedRow) {
if rowHasAtLeastOneUnreadArticle(row) && !rowIsGroupItem(row) { func shouldSkipRow(_ row: Int) -> Bool {
let skipExpandedFolders = UserDefaults.standard.bool(forKey: "JalkutRespectFolderExpansionOnNextUnread")
// Skip group items, because they should never be selected.
// Skip expanded folders only if Jalkut's pref is enabled.
if rowIsGroupItem(row) || (skipExpandedFolders && rowIsExpandedFolder(row)) {
return true
}
return false
}
func nextSelectableRowWithUnreadArticle(wrappingToTop wrapping: Bool = false) -> Int? {
let numberOfRows = outlineView.numberOfRows
let startRow = outlineView.selectedRow + 1
let orderedRows: [Int]
if startRow == numberOfRows {
// Last item is selected, so start at the beginning if we allow wrapping
orderedRows = wrapping ? Array(0..<numberOfRows) : []
} else {
// Start at the selection and wrap around to the beginning
orderedRows = Array(startRow..<numberOfRows) + (wrapping ? Array(0..<startRow) : [])
}
for row in orderedRows {
// Skip group items, because they should never be selected.
if rowHasAtLeastOneUnreadArticle(row) && !shouldSkipRow(row) {
return row return row
} }
row += 1
} }
return nil return nil

View File

@ -549,7 +549,7 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
tableView.scrollTo(row: ix) tableView.scrollTo(row: ix)
} }
func goToNextUnread() { func goToNextUnread(wrappingToTop wrapping: Bool = false) {
guard let ix = indexOfNextUnreadArticle() else { guard let ix = indexOfNextUnreadArticle() else {
return return
} }
@ -558,15 +558,15 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
tableView.scrollTo(row: ix) tableView.scrollTo(row: ix)
} }
func canGoToNextUnread() -> Bool { func canGoToNextUnread(wrappingToTop wrapping: Bool = false) -> Bool {
guard let _ = indexOfNextUnreadArticle() else { guard let _ = indexOfNextUnreadArticle(wrappingToTop: wrapping) else {
return false return false
} }
return true return true
} }
func indexOfNextUnreadArticle() -> Int? { func indexOfNextUnreadArticle(wrappingToTop wrapping: Bool = false) -> Int? {
return articles.rowOfNextUnreadArticle(tableView.selectedRow) return articles.rowOfNextUnreadArticle(tableView.selectedRow, wrappingToTop: wrapping)
} }
func focus() { func focus() {

View File

@ -20,18 +20,21 @@ extension Array where Element == Article {
return self[row] return self[row]
} }
func rowOfNextUnreadArticle(_ selectedRow: Int) -> Int? { func orderedRowIndexes(fromIndex startIndex: Int, wrappingToTop wrapping: Bool) -> [Int] {
if startIndex >= self.count {
// Wrap around to the top if specified
return wrapping ? Array<Int>(0..<self.count) : []
} else {
// Start at the selection and wrap around to the beginning
return Array<Int>(startIndex..<self.count) + (wrapping ? Array<Int>(0..<startIndex) : [])
}
}
func rowOfNextUnreadArticle(_ selectedRow: Int, wrappingToTop wrapping: Bool) -> Int? {
if isEmpty { if isEmpty {
return nil return nil
} }
var rowIndex = selectedRow for rowIndex in orderedRowIndexes(fromIndex: selectedRow + 1, wrappingToTop: wrapping) {
while(true) {
rowIndex = rowIndex + 1
if rowIndex >= count {
break
}
let article = articleAtRow(rowIndex)! let article = articleAtRow(rowIndex)!
if !article.status.read { if !article.status.read {
return rowIndex return rowIndex