Replace Mark Older as Read with Mark Above and Mark Below.

This commit is contained in:
Maurice Parker 2020-03-08 16:15:17 -07:00
parent fc447121d6
commit d94e090094
4 changed files with 71 additions and 59 deletions

View File

@ -452,9 +452,15 @@
<action selector="markAllAsRead:" target="Ady-hI-5gd" id="154-2D-ONk"/> <action selector="markAllAsRead:" target="Ady-hI-5gd" id="154-2D-ONk"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem title="Mark Older as Read" keyEquivalent="K" id="p1o-EG-Uo8"> <menuItem title="Mark Above as Read" keyEquivalent="k" id="p1o-EG-Uo8">
<modifierMask key="keyEquivalentModifierMask" control="YES" command="YES"/>
<connections> <connections>
<action selector="markOlderArticlesAsRead:" target="Ady-hI-5gd" id="gzq-X5-0aC"/> <action selector="markAboveArticlesAsRead:" target="Ady-hI-5gd" id="BJY-oR-uvr"/>
</connections>
</menuItem>
<menuItem title="Mark Below as Read" keyEquivalent="K" id="8lZ-XI-I4y">
<connections>
<action selector="markBelowArticlesAsRead:" target="Ady-hI-5gd" id="Jnm-LF-mrf"/>
</connections> </connections>
</menuItem> </menuItem>
<menuItem isSeparatorItem="YES" id="gB0-WX-2Gd"/> <menuItem isSeparatorItem="YES" id="gB0-WX-2Gd"/>

View File

@ -198,8 +198,12 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
return validateToggleStarred(item) return validateToggleStarred(item)
} }
if item.action == #selector(markOlderArticlesAsRead(_:)) { if item.action == #selector(markAboveArticlesAsRead(_:)) {
return canMarkOlderArticlesAsRead() return canMarkAboveArticlesAsRead()
}
if item.action == #selector(markBelowArticlesAsRead(_:)) {
return canMarkBelowArticlesAsRead()
} }
if item.action == #selector(toggleArticleExtractor(_:)) { if item.action == #selector(toggleArticleExtractor(_:)) {
@ -360,8 +364,12 @@ class MainWindowController : NSWindowController, NSUserInterfaceValidations {
splitViewController!.toggleSidebar(sender) splitViewController!.toggleSidebar(sender)
} }
@IBAction func markOlderArticlesAsRead(_ sender: Any?) { @IBAction func markAboveArticlesAsRead(_ sender: Any?) {
currentTimelineViewController?.markOlderArticlesRead() currentTimelineViewController?.markAboveArticlesRead()
}
@IBAction func markBelowArticlesAsRead(_ sender: Any?) {
currentTimelineViewController?.markBelowArticlesRead()
} }
@IBAction func navigateToTimeline(_ sender: Any?) { @IBAction func navigateToTimeline(_ sender: Any?) {
@ -808,9 +816,12 @@ private extension MainWindowController {
return true return true
} }
func canMarkOlderArticlesAsRead() -> Bool { func canMarkAboveArticlesAsRead() -> Bool {
return currentTimelineViewController?.canMarkAboveArticlesAsRead() ?? false
}
return currentTimelineViewController?.canMarkOlderArticlesAsRead() ?? false func canMarkBelowArticlesAsRead() -> Bool {
return currentTimelineViewController?.canMarkBelowArticlesAsRead() ?? false
} }
func canShowShareMenu() -> Bool { func canShowShareMenu() -> Bool {

View File

@ -33,39 +33,31 @@ extension TimelineViewController {
extension TimelineViewController { extension TimelineViewController {
@objc func markArticlesReadFromContextualMenu(_ sender: Any?) { @objc func markArticlesReadFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
guard let articles = articles(from: sender) else {
return
}
markArticles(articles, read: true) markArticles(articles, read: true)
} }
@objc func markArticlesUnreadFromContextualMenu(_ sender: Any?) { @objc func markArticlesUnreadFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
guard let articles = articles(from: sender) else {
return
}
markArticles(articles, read: false) markArticles(articles, read: false)
} }
@objc func markOlderArticlesReadFromContextualMenu(_ sender: Any?) { @objc func markAboveArticlesReadFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
guard let articles = articles(from: sender) else { markAboveArticlesRead(articles)
return
} }
markOlderArticlesRead(articles)
@objc func markBelowArticlesReadFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
markBelowArticlesRead(articles)
} }
@objc func markArticlesStarredFromContextualMenu(_ sender: Any?) { @objc func markArticlesStarredFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { return }
guard let articles = articles(from: sender) else {
return
}
markArticles(articles, starred: true) markArticles(articles, starred: true)
} }
@objc func markArticlesUnstarredFromContextualMenu(_ sender: Any?) { @objc func markArticlesUnstarredFromContextualMenu(_ sender: Any?) {
guard let articles = articles(from: sender) else { guard let articles = articles(from: sender) else {
return return
} }
@ -111,17 +103,14 @@ extension TimelineViewController {
private extension TimelineViewController { private extension TimelineViewController {
func markArticles(_ articles: [Article], read: Bool) { func markArticles(_ articles: [Article], read: Bool) {
markArticles(articles, statusKey: .read, flag: read) markArticles(articles, statusKey: .read, flag: read)
} }
func markArticles(_ articles: [Article], starred: Bool) { func markArticles(_ articles: [Article], starred: Bool) {
markArticles(articles, statusKey: .starred, flag: starred) markArticles(articles, statusKey: .starred, flag: starred)
} }
func markArticles(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool) { func markArticles(_ articles: [Article], statusKey: ArticleStatus.Key, flag: Bool) {
guard let undoManager = undoManager, let markStatusCommand = MarkStatusCommand(initialArticles: articles, statusKey: statusKey, flag: flag, undoManager: undoManager) else { guard let undoManager = undoManager, let markStatusCommand = MarkStatusCommand(initialArticles: articles, statusKey: statusKey, flag: flag, undoManager: undoManager) else {
return return
} }
@ -130,24 +119,20 @@ private extension TimelineViewController {
} }
func unreadArticles(from articles: [Article]) -> [Article]? { func unreadArticles(from articles: [Article]) -> [Article]? {
let filteredArticles = articles.filter { !$0.status.read } let filteredArticles = articles.filter { !$0.status.read }
return filteredArticles.isEmpty ? nil : filteredArticles return filteredArticles.isEmpty ? nil : filteredArticles
} }
func readArticles(from articles: [Article]) -> [Article]? { func readArticles(from articles: [Article]) -> [Article]? {
let filteredArticles = articles.filter { $0.status.read } let filteredArticles = articles.filter { $0.status.read }
return filteredArticles.isEmpty ? nil : filteredArticles return filteredArticles.isEmpty ? nil : filteredArticles
} }
func articles(from sender: Any?) -> [Article]? { func articles(from sender: Any?) -> [Article]? {
return (sender as? NSMenuItem)?.representedObject as? [Article] return (sender as? NSMenuItem)?.representedObject as? [Article]
} }
func menu(for articles: [Article]) -> NSMenu? { func menu(for articles: [Article]) -> NSMenu? {
let menu = NSMenu(title: "") let menu = NSMenu(title: "")
if articles.anyArticleIsUnread() { if articles.anyArticleIsUnread() {
@ -162,8 +147,11 @@ private extension TimelineViewController {
if articles.anyArticleIsStarred() { if articles.anyArticleIsStarred() {
menu.addItem(markUnstarredMenuItem(articles)) menu.addItem(markUnstarredMenuItem(articles))
} }
if articles.count > 0 { if let first = articles.first, self.articles.articlesAbove(article: first).canMarkAllAsRead() {
menu.addItem(markOlderReadMenuItem(articles)) menu.addItem(markAboveReadMenuItem(articles))
}
if let last = articles.last, self.articles.articlesBelow(article: last).canMarkAllAsRead() {
menu.addItem(markBelowReadMenuItem(articles))
} }
menu.addSeparatorIfNeeded() menu.addSeparatorIfNeeded()
@ -239,8 +227,12 @@ private extension TimelineViewController {
return menuItem(NSLocalizedString("Mark as Unstarred", comment: "Command"), #selector(markArticlesUnstarredFromContextualMenu(_:)), articles) return menuItem(NSLocalizedString("Mark as Unstarred", comment: "Command"), #selector(markArticlesUnstarredFromContextualMenu(_:)), articles)
} }
func markOlderReadMenuItem(_ articles: [Article]) -> NSMenuItem { func markAboveReadMenuItem(_ articles: [Article]) -> NSMenuItem {
return menuItem(NSLocalizedString("Mark Older as Read", comment: "Command"), #selector(markOlderArticlesReadFromContextualMenu(_:)), articles) return menuItem(NSLocalizedString("Mark Above as Read", comment: "Command"), #selector(markAboveArticlesReadFromContextualMenu(_:)), articles)
}
func markBelowReadMenuItem(_ articles: [Article]) -> NSMenuItem {
return menuItem(NSLocalizedString("Mark Below as Read", comment: "Command"), #selector(markBelowArticlesReadFromContextualMenu(_:)), articles)
} }
func selectFeedInSidebarMenuItem(_ feed: WebFeed) -> NSMenuItem { func selectFeedInSidebarMenuItem(_ feed: WebFeed) -> NSMenuItem {

View File

@ -435,35 +435,38 @@ final class TimelineViewController: NSViewController, UndoableCommandRunner, Unr
return .canDoNothing return .canDoNothing
} }
func markOlderArticlesRead() { func markAboveArticlesRead() {
markOlderArticlesRead(selectedArticles) markAboveArticlesRead(selectedArticles)
} }
func canMarkOlderArticlesAsRead() -> Bool { func markBelowArticlesRead() {
return !selectedArticles.isEmpty markBelowArticlesRead(selectedArticles)
} }
func markOlderArticlesRead(_ selectedArticles: [Article]) { func canMarkAboveArticlesAsRead() -> Bool {
// Mark articles older than the selectedArticles(s) as read. guard let first = selectedArticles.first else { return false }
return articles.articlesAbove(article: first).canMarkAllAsRead()
}
var cutoffDate: Date? = nil func canMarkBelowArticlesAsRead() -> Bool {
for article in selectedArticles { guard let last = selectedArticles.last else { return false }
if cutoffDate == nil { return articles.articlesBelow(article: last).canMarkAllAsRead()
cutoffDate = article.logicalDatePublished
} }
else if cutoffDate! > article.logicalDatePublished {
cutoffDate = article.logicalDatePublished func markAboveArticlesRead(_ selectedArticles: [Article]) {
} guard let first = selectedArticles.first else { return }
} let articlesToMark = articles.articlesAbove(article: first)
if cutoffDate == nil { guard !articlesToMark.isEmpty else { return }
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articlesToMark, markingRead: true, undoManager: undoManager) else {
return return
} }
runCommand(markReadCommand)
let articlesToMark = articles.filter { $0.logicalDatePublished < cutoffDate! }
if articlesToMark.isEmpty {
return
} }
func markBelowArticlesRead(_ selectedArticles: [Article]) {
guard let last = selectedArticles.last else { return }
let articlesToMark = articles.articlesBelow(article: last)
guard !articlesToMark.isEmpty else { return }
guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articlesToMark, markingRead: true, undoManager: undoManager) else { guard let undoManager = undoManager, let markReadCommand = MarkStatusCommand(initialArticles: articlesToMark, markingRead: true, undoManager: undoManager) else {
return return
} }