Merge pull request #2066 from stuartbreckenridge/issue-2018
Mark As Read, Mark Below As Read, Mark Above as Read now present an action sheet
This commit is contained in:
commit
8523f3222f
|
@ -937,7 +937,7 @@ private extension MasterFeedViewController {
|
||||||
guard let node = dataSource.itemIdentifier(for: indexPath),
|
guard let node = dataSource.itemIdentifier(for: indexPath),
|
||||||
coordinator.unreadCountFor(node) > 0,
|
coordinator.unreadCountFor(node) > 0,
|
||||||
let feed = node.representedObject as? WebFeed,
|
let feed = node.representedObject as? WebFeed,
|
||||||
let articles = try? feed.fetchArticles() else {
|
let articles = try? feed.fetchArticles(), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,8 +947,9 @@ private extension MasterFeedViewController {
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, cancelCompletion: cancel) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView, cancelCompletion: cancel) { [weak self] in
|
||||||
self?.coordinator.markAllAsRead(Array(articles))
|
self?.coordinator.markAllAsRead(Array(articles))
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
|
@ -1026,7 +1027,7 @@ private extension MasterFeedViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
let articles = Array(fetchedArticles)
|
let articles = Array(fetchedArticles)
|
||||||
return markAllAsReadAction(articles: articles, nameForDisplay: articleFetcher.nameForDisplay)
|
return markAllAsReadAction(articles: articles, nameForDisplay: articleFetcher.nameForDisplay, indexPath: indexPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAllAsReadAction(account: Account) -> UIAction? {
|
func markAllAsReadAction(account: Account) -> UIAction? {
|
||||||
|
@ -1038,16 +1039,16 @@ private extension MasterFeedViewController {
|
||||||
return markAllAsReadAction(articles: articles, nameForDisplay: account.nameForDisplay)
|
return markAllAsReadAction(articles: articles, nameForDisplay: account.nameForDisplay)
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAllAsReadAction(articles: [Article], nameForDisplay: String) -> UIAction? {
|
func markAllAsReadAction(articles: [Article], nameForDisplay: String, indexPath: IndexPath? = nil) -> UIAction? {
|
||||||
guard articles.canMarkAllAsRead() else {
|
guard articles.canMarkAllAsRead(), let indexPath = indexPath, let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
|
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
|
||||||
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, nameForDisplay) as String
|
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, nameForDisplay) as String
|
||||||
|
|
||||||
let action = UIAction(title: title, image: AppAssets.markAllAsReadImage) { [weak self] action in
|
let action = UIAction(title: title, image: AppAssets.markAllAsReadImage) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
|
||||||
self?.coordinator.markAllAsRead(articles)
|
self?.coordinator.markAllAsRead(articles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,13 +9,20 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
|
protocol MarkAsReadAlertControllerSourceType {}
|
||||||
|
extension CGRect: MarkAsReadAlertControllerSourceType {}
|
||||||
|
extension UIView: MarkAsReadAlertControllerSourceType {}
|
||||||
|
extension UIBarButtonItem: MarkAsReadAlertControllerSourceType {}
|
||||||
|
|
||||||
|
|
||||||
struct MarkAsReadAlertController {
|
struct MarkAsReadAlertController {
|
||||||
|
|
||||||
static func confirm(_ controller: UIViewController?,
|
static func confirm<T>(_ controller: UIViewController?,
|
||||||
coordinator: SceneCoordinator?,
|
coordinator: SceneCoordinator?,
|
||||||
confirmTitle: String,
|
confirmTitle: String,
|
||||||
cancelCompletion: (() -> Void)? = nil,
|
sourceType: T,
|
||||||
completion: @escaping () -> Void) {
|
cancelCompletion: (() -> Void)? = nil,
|
||||||
|
completion: @escaping () -> Void) where T: MarkAsReadAlertControllerSourceType {
|
||||||
|
|
||||||
guard let controller = controller, let coordinator = coordinator else {
|
guard let controller = controller, let coordinator = coordinator else {
|
||||||
completion()
|
completion()
|
||||||
|
@ -23,7 +30,7 @@ struct MarkAsReadAlertController {
|
||||||
}
|
}
|
||||||
|
|
||||||
if AppDefaults.confirmMarkAllAsRead {
|
if AppDefaults.confirmMarkAllAsRead {
|
||||||
let alertController = MarkAsReadAlertController.alert(coordinator: coordinator, confirmTitle: confirmTitle, cancelCompletion: cancelCompletion) { _ in
|
let alertController = MarkAsReadAlertController.alert(coordinator: coordinator, confirmTitle: confirmTitle, cancelCompletion: cancelCompletion, sourceType: sourceType) { _ in
|
||||||
completion()
|
completion()
|
||||||
}
|
}
|
||||||
controller.present(alertController, animated: true)
|
controller.present(alertController, animated: true)
|
||||||
|
@ -32,10 +39,12 @@ struct MarkAsReadAlertController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static func alert(coordinator: SceneCoordinator,
|
private static func alert<T>(coordinator: SceneCoordinator,
|
||||||
confirmTitle: String,
|
confirmTitle: String,
|
||||||
cancelCompletion: (() -> Void)?,
|
cancelCompletion: (() -> Void)?,
|
||||||
completion: @escaping (UIAlertAction) -> Void) -> UIAlertController {
|
sourceType: T,
|
||||||
|
completion: @escaping (UIAlertAction) -> Void) -> UIAlertController where T: MarkAsReadAlertControllerSourceType {
|
||||||
|
|
||||||
|
|
||||||
let title = NSLocalizedString("Mark As Read", comment: "Mark As Read")
|
let title = NSLocalizedString("Mark As Read", comment: "Mark As Read")
|
||||||
let message = NSLocalizedString("You can turn this confirmation off in settings.",
|
let message = NSLocalizedString("You can turn this confirmation off in settings.",
|
||||||
|
@ -43,7 +52,7 @@ struct MarkAsReadAlertController {
|
||||||
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
let cancelTitle = NSLocalizedString("Cancel", comment: "Cancel")
|
||||||
let settingsTitle = NSLocalizedString("Open Settings", comment: "Open Settings")
|
let settingsTitle = NSLocalizedString("Open Settings", comment: "Open Settings")
|
||||||
|
|
||||||
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
let alertController = UIAlertController(title: title, message: message, preferredStyle: .actionSheet)
|
||||||
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) { _ in
|
let cancelAction = UIAlertAction(title: cancelTitle, style: .cancel) { _ in
|
||||||
cancelCompletion?()
|
cancelCompletion?()
|
||||||
}
|
}
|
||||||
|
@ -55,6 +64,18 @@ struct MarkAsReadAlertController {
|
||||||
alertController.addAction(markAction)
|
alertController.addAction(markAction)
|
||||||
alertController.addAction(settingsAction)
|
alertController.addAction(settingsAction)
|
||||||
alertController.addAction(cancelAction)
|
alertController.addAction(cancelAction)
|
||||||
|
|
||||||
|
if let barButtonItem = sourceType as? UIBarButtonItem {
|
||||||
|
alertController.popoverPresentationController?.barButtonItem = barButtonItem
|
||||||
|
}
|
||||||
|
|
||||||
|
if let rect = sourceType as? CGRect {
|
||||||
|
alertController.popoverPresentationController?.sourceRect = rect
|
||||||
|
}
|
||||||
|
|
||||||
|
if let view = sourceType as? UIView {
|
||||||
|
alertController.popoverPresentationController?.sourceView = view
|
||||||
|
}
|
||||||
|
|
||||||
return alertController
|
return alertController
|
||||||
}
|
}
|
||||||
|
|
|
@ -116,7 +116,12 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||||
|
|
||||||
@IBAction func markAllAsRead(_ sender: Any) {
|
@IBAction func markAllAsRead(_ sender: Any) {
|
||||||
let title = NSLocalizedString("Mark All as Read", comment: "Mark All as Read")
|
let title = NSLocalizedString("Mark All as Read", comment: "Mark All as Read")
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: coordinator, confirmTitle: title) { [weak self] in
|
|
||||||
|
guard let barButtonItem = sender as? UIBarButtonItem else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
MarkAsReadAlertController.confirm(self, coordinator: coordinator, confirmTitle: title, sourceType: barButtonItem) { [weak self] in
|
||||||
self?.coordinator.markAllAsReadInTimeline()
|
self?.coordinator.markAllAsReadInTimeline()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -260,11 +265,11 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||||
popoverController.sourceRect = CGRect(x: view.frame.size.width/2, y: view.frame.size.height/2, width: 1, height: 1)
|
popoverController.sourceRect = CGRect(x: view.frame.size.width/2, y: view.frame.size.height/2, width: 1, height: 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let action = self.markAboveAsReadAlertAction(article, completion: completion) {
|
if let action = self.markAboveAsReadAlertAction(article, indexPath: indexPath, completion: completion) {
|
||||||
alert.addAction(action)
|
alert.addAction(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let action = self.markBelowAsReadAlertAction(article, completion: completion) {
|
if let action = self.markBelowAsReadAlertAction(article, indexPath: indexPath, completion: completion) {
|
||||||
alert.addAction(action)
|
alert.addAction(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -272,7 +277,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||||
alert.addAction(action)
|
alert.addAction(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let action = self.markAllInFeedAsReadAlertAction(article, completion: completion) {
|
if let action = self.markAllInFeedAsReadAlertAction(article, indexPath: indexPath, completion: completion) {
|
||||||
alert.addAction(action)
|
alert.addAction(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,11 +322,11 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||||
|
|
||||||
actions.append(self.toggleArticleStarStatusAction(article))
|
actions.append(self.toggleArticleStarStatusAction(article))
|
||||||
|
|
||||||
if let action = self.markAboveAsReadAction(article) {
|
if let action = self.markAboveAsReadAction(article, indexPath: indexPath) {
|
||||||
actions.append(action)
|
actions.append(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let action = self.markBelowAsReadAction(article) {
|
if let action = self.markBelowAsReadAction(article, indexPath: indexPath) {
|
||||||
actions.append(action)
|
actions.append(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -329,7 +334,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
|
||||||
actions.append(action)
|
actions.append(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let action = self.markAllInFeedAsReadAction(article) {
|
if let action = self.markAllInFeedAsReadAction(article, indexPath: indexPath) {
|
||||||
actions.append(action)
|
actions.append(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -696,38 +701,38 @@ private extension MasterTimelineViewController {
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAboveAsReadAction(_ article: Article) -> UIAction? {
|
func markAboveAsReadAction(_ article: Article, indexPath: IndexPath) -> UIAction? {
|
||||||
guard coordinator.canMarkAboveAsRead(for: article) else {
|
guard coordinator.canMarkAboveAsRead(for: article), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = NSLocalizedString("Mark Above as Read", comment: "Mark Above as Read")
|
let title = NSLocalizedString("Mark Above as Read", comment: "Mark Above as Read")
|
||||||
let image = AppAssets.markAboveAsReadImage
|
let image = AppAssets.markAboveAsReadImage
|
||||||
let action = UIAction(title: title, image: image) { [weak self] action in
|
let action = UIAction(title: title, image: image) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
|
||||||
self?.coordinator.markAboveAsRead(article)
|
self?.coordinator.markAboveAsRead(article)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func markBelowAsReadAction(_ article: Article) -> UIAction? {
|
func markBelowAsReadAction(_ article: Article, indexPath: IndexPath) -> UIAction? {
|
||||||
guard coordinator.canMarkBelowAsRead(for: article) else {
|
guard coordinator.canMarkBelowAsRead(for: article), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let title = NSLocalizedString("Mark Below as Read", comment: "Mark Below as Read")
|
let title = NSLocalizedString("Mark Below as Read", comment: "Mark Below as Read")
|
||||||
let image = AppAssets.markBelowAsReadImage
|
let image = AppAssets.markBelowAsReadImage
|
||||||
let action = UIAction(title: title, image: image) { [weak self] action in
|
let action = UIAction(title: title, image: image) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
|
||||||
self?.coordinator.markBelowAsRead(article)
|
self?.coordinator.markBelowAsRead(article)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAboveAsReadAlertAction(_ article: Article, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
func markAboveAsReadAlertAction(_ article: Article, indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||||
guard coordinator.canMarkAboveAsRead(for: article) else {
|
guard coordinator.canMarkAboveAsRead(for: article), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -737,7 +742,7 @@ private extension MasterTimelineViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, cancelCompletion: cancel) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView, cancelCompletion: cancel) { [weak self] in
|
||||||
self?.coordinator.markAboveAsRead(article)
|
self?.coordinator.markAboveAsRead(article)
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
|
@ -745,8 +750,8 @@ private extension MasterTimelineViewController {
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func markBelowAsReadAlertAction(_ article: Article, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
func markBelowAsReadAlertAction(_ article: Article, indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||||
guard coordinator.canMarkBelowAsRead(for: article) else {
|
guard coordinator.canMarkBelowAsRead(for: article), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -756,7 +761,7 @@ private extension MasterTimelineViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, cancelCompletion: cancel) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView, cancelCompletion: cancel) { [weak self] in
|
||||||
self?.coordinator.markBelowAsRead(article)
|
self?.coordinator.markBelowAsRead(article)
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
|
@ -787,36 +792,37 @@ private extension MasterTimelineViewController {
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAllInFeedAsReadAction(_ article: Article) -> UIAction? {
|
func markAllInFeedAsReadAction(_ article: Article, indexPath: IndexPath) -> UIAction? {
|
||||||
guard let webFeed = article.webFeed else { return nil }
|
guard let webFeed = article.webFeed else { return nil }
|
||||||
guard let fetchedArticles = try? webFeed.fetchArticles() else {
|
guard let fetchedArticles = try? webFeed.fetchArticles() else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let articles = Array(fetchedArticles)
|
let articles = Array(fetchedArticles)
|
||||||
guard articles.canMarkAllAsRead() else {
|
guard articles.canMarkAllAsRead(), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
|
let localizedMenuText = NSLocalizedString("Mark All as Read in “%@”", comment: "Command")
|
||||||
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, webFeed.nameForDisplay) as String
|
let title = NSString.localizedStringWithFormat(localizedMenuText as NSString, webFeed.nameForDisplay) as String
|
||||||
|
|
||||||
let action = UIAction(title: title, image: AppAssets.markAllAsReadImage) { [weak self] action in
|
let action = UIAction(title: title, image: AppAssets.markAllAsReadImage) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView) { [weak self] in
|
||||||
self?.coordinator.markAllAsRead(articles)
|
self?.coordinator.markAllAsRead(articles)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return action
|
return action
|
||||||
}
|
}
|
||||||
|
|
||||||
func markAllInFeedAsReadAlertAction(_ article: Article, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
func markAllInFeedAsReadAlertAction(_ article: Article, indexPath: IndexPath, completion: @escaping (Bool) -> Void) -> UIAlertAction? {
|
||||||
guard let webFeed = article.webFeed else { return nil }
|
guard let webFeed = article.webFeed else { return nil }
|
||||||
guard let fetchedArticles = try? webFeed.fetchArticles() else {
|
guard let fetchedArticles = try? webFeed.fetchArticles() else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
let articles = Array(fetchedArticles)
|
let articles = Array(fetchedArticles)
|
||||||
guard articles.canMarkAllAsRead() else {
|
guard articles.canMarkAllAsRead(), let contentView = self.tableView.cellForRow(at: indexPath)?.contentView else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -827,7 +833,7 @@ private extension MasterTimelineViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
let action = UIAlertAction(title: title, style: .default) { [weak self] action in
|
||||||
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, cancelCompletion: cancel) { [weak self] in
|
MarkAsReadAlertController.confirm(self, coordinator: self?.coordinator, confirmTitle: title, sourceType: contentView, cancelCompletion: cancel) { [weak self] in
|
||||||
self?.coordinator.markAllAsRead(articles)
|
self?.coordinator.markAllAsRead(articles)
|
||||||
completion(true)
|
completion(true)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue