Implement mark as unread window for accounts that need it. Issue #1407

This commit is contained in:
Maurice Parker 2020-02-18 13:49:29 -08:00
parent 8acd6a039a
commit 0e72811429
7 changed files with 51 additions and 18 deletions

View File

@ -14,25 +14,28 @@ import Foundation
user interface as much as possible. For example some sync services don't allow
feeds to be in the root folder of the account.
*/
public struct AccountBehaviors: OptionSet {
public typealias AccountBehaviors = [AccountBehavior]
public enum AccountBehavior: Equatable {
/**
Account doesn't support copies of a feed that are in a folder to be made to the root folder.
*/
public static let disallowFeedCopyInRootFolder = AccountBehaviors(rawValue: 1)
case disallowFeedCopyInRootFolder
/**
Account doesn't support feeds in the root folder.
*/
public static let disallowFeedInRootFolder = AccountBehaviors(rawValue: 2)
case disallowFeedInRootFolder
/**
Account doesn't support OPML imports
*/
public static let disallowOPMLImports = AccountBehaviors(rawValue: 4)
case disallowOPMLImports
public let rawValue: Int
public init(rawValue: Int) {
self.rawValue = rawValue
}
/**
Account doesn't allow mark as read after a period of days
*/
case disallowMarkAsUnreadAfterPeriod(Int)
}

View File

@ -25,7 +25,7 @@ final class FeedlyAccountDelegate: AccountDelegate {
// TODO: Kiel, if you decide not to support OPML import you will have to disallow it in the behaviors
// See https://developer.feedly.com/v3/opml/
var behaviors: AccountBehaviors = [.disallowFeedInRootFolder]
var behaviors: AccountBehaviors = [.disallowFeedInRootFolder, .disallowMarkAsUnreadAfterPeriod(31)]
let isOPMLImportSupported = false

View File

@ -63,6 +63,25 @@ extension Article {
var logicalDatePublished: Date {
return datePublished ?? dateModified ?? status.dateArrived
}
var isAvailableToMarkUnread: Bool {
guard let markUnreadWindow = account?.behaviors.compactMap( { behavior -> Int? in
switch behavior {
case .disallowMarkAsUnreadAfterPeriod(let days):
return days
default:
return nil
}
}).first else {
return true
}
if logicalDatePublished.byAdding(days: markUnreadWindow) > Date() {
return true
} else {
return false
}
}
func iconImage() -> IconImage? {
if let authors = authors, authors.count == 1, let author = authors.first {

View File

@ -157,9 +157,11 @@ class ArticleViewController: UIViewController {
if article.status.read {
readBarButtonItem.image = AppAssets.circleOpenImage
readBarButtonItem.isEnabled = article.isAvailableToMarkUnread
readBarButtonItem.accLabelText = NSLocalizedString("Mark Article Unread", comment: "Mark Article Unread")
} else {
readBarButtonItem.image = AppAssets.circleClosedImage
readBarButtonItem.isEnabled = true
readBarButtonItem.accLabelText = NSLocalizedString("Selected - Mark Article Unread", comment: "Selected - Mark Article Unread")
}

View File

@ -264,7 +264,9 @@ extension WebViewController: UIContextMenuInteractionDelegate {
if let action = self.nextArticleAction() {
actions.append(action)
}
actions.append(self.toggleReadAction())
if let action = self.toggleReadAction() {
actions.append(action)
}
actions.append(self.toggleStarredAction())
if let action = self.nextUnreadArticleAction() {
actions.append(action)
@ -642,10 +644,11 @@ private extension WebViewController {
}
}
func toggleReadAction() -> UIAction {
let read = article?.status.read ?? false
let title = read ? NSLocalizedString("Mark as Unread", comment: "Mark as Unread") : NSLocalizedString("Mark as Read", comment: "Mark as Read")
let readImage = read ? AppAssets.circleClosedImage : AppAssets.circleOpenImage
func toggleReadAction() -> UIAction? {
guard let article = article, !article.status.read || article.isAvailableToMarkUnread else { return nil }
let title = article.status.read ? NSLocalizedString("Mark as Unread", comment: "Mark as Unread") : NSLocalizedString("Mark as Read", comment: "Mark as Read")
let readImage = article.status.read ? AppAssets.circleClosedImage : AppAssets.circleOpenImage
return UIAction(title: title, image: readImage) { [weak self] action in
self?.coordinator.toggleReadForCurrentArticle()
}

View File

@ -217,7 +217,8 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
override func tableView(_ tableView: UITableView, leadingSwipeActionsConfigurationForRowAt indexPath: IndexPath) -> UISwipeActionsConfiguration? {
guard let article = dataSource.itemIdentifier(for: indexPath) else { return nil }
guard !article.status.read || article.isAvailableToMarkUnread else { return nil }
// Set up the read action
let readTitle = article.status.read ?
NSLocalizedString("Unread", comment: "Unread") :
@ -314,7 +315,10 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
guard let self = self else { return nil }
var actions = [UIAction]()
actions.append(self.toggleArticleReadStatusAction(article))
if let action = self.toggleArticleReadStatusAction(article) {
actions.append(action)
}
actions.append(self.toggleArticleStarStatusAction(article))
if let action = self.markAboveAsReadAction(article) {
@ -672,8 +676,9 @@ private extension MasterTimelineViewController {
return nil
}
func toggleArticleReadStatusAction(_ article: Article) -> UIAction {
func toggleArticleReadStatusAction(_ article: Article) -> UIAction? {
guard !article.status.read || article.isAvailableToMarkUnread else { return nil }
let title = article.status.read ?
NSLocalizedString("Mark as Unread", comment: "Mark as Unread") :
NSLocalizedString("Mark as Read", comment: "Mark as Read")

View File

@ -1008,6 +1008,7 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
}
func toggleRead(_ article: Article) {
guard !article.status.read || article.isAvailableToMarkUnread else { return }
markArticlesWithUndo([article], statusKey: .read, flag: !article.status.read)
}