diff --git a/iOS/Base.lproj/Main.storyboard b/iOS/Base.lproj/Main.storyboard
index fa5928103..638e4b65e 100644
--- a/iOS/Base.lproj/Main.storyboard
+++ b/iOS/Base.lproj/Main.storyboard
@@ -99,7 +99,7 @@
-
+
@@ -149,16 +149,17 @@
-
+
-
+
-
+
+
@@ -244,6 +245,9 @@
+
+
+
diff --git a/iOS/Detail/DetailViewController.swift b/iOS/Detail/DetailViewController.swift
index 9bcde3608..e8101eef3 100644
--- a/iOS/Detail/DetailViewController.swift
+++ b/iOS/Detail/DetailViewController.swift
@@ -26,14 +26,18 @@ class DetailViewController: UIViewController {
weak var navState: NavigationStateController?
override func viewDidLoad() {
+
super.viewDidLoad()
- self.navigationController?.navigationItem.largeTitleDisplayMode = .never
webView.navigationDelegate = self
+
markAsRead()
- reloadUI()
+ updateUI()
reloadHTML()
+
+ NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(articleSelectionDidChange(_:)), name: .ArticleSelectionDidChange, object: navState)
+
}
func markAsRead() {
@@ -42,7 +46,7 @@ class DetailViewController: UIViewController {
}
}
- func reloadUI() {
+ func updateUI() {
guard let article = navState?.currentArticle else {
nextUnreadBarButtonItem.isEnabled = false
@@ -55,7 +59,7 @@ class DetailViewController: UIViewController {
return
}
- nextUnreadBarButtonItem.isEnabled = navState?.isNextUnreadAvailable ?? false
+ nextUnreadBarButtonItem.isEnabled = navState?.isAnyUnreadAvailable ?? false
prevArticleBarButtonItem.isEnabled = navState?.isPrevArticleAvailable ?? false
nextArticleBarButtonItem.isEnabled = navState?.isNextArticleAvailable ?? false
@@ -83,18 +87,24 @@ class DetailViewController: UIViewController {
}
+ // MARK: Notifications
+
+ @objc dynamic func unreadCountDidChange(_ notification: Notification) {
+ updateUI()
+ }
+
@objc func statusesDidChange(_ note: Notification) {
guard let articles = note.userInfo?[Account.UserInfoKey.articles] as? Set else {
return
}
if articles.count == 1 && articles.first?.articleID == navState?.currentArticle?.articleID {
- reloadUI()
+ updateUI()
}
}
@objc func articleSelectionDidChange(_ note: Notification) {
markAsRead()
- reloadUI()
+ updateUI()
reloadHTML()
}
diff --git a/iOS/Master/MasterViewController.swift b/iOS/Master/MasterViewController.swift
index 0752bcaac..21447bbab 100644
--- a/iOS/Master/MasterViewController.swift
+++ b/iOS/Master/MasterViewController.swift
@@ -14,6 +14,8 @@ import RSTree
class MasterViewController: UITableViewController, UndoableCommandRunner {
+ @IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
+
var undoableCommands = [UndoableCommand]()
let navState = NavigationStateController()
@@ -29,18 +31,20 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
tableView.register(MasterTableViewSectionHeader.self, forHeaderFooterViewReuseIdentifier: "SectionHeader")
- NotificationCenter.default.addObserver(self, selector: #selector(backingStoresDidRebuild(_:)), name: .BackingStoresDidRebuild, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(feedSettingDidChange(_:)), name: .FeedSettingDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(userDidAddFeed(_:)), name: .UserDidAddFeed, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(backingStoresDidRebuild(_:)), name: .BackingStoresDidRebuild, object: navState)
NotificationCenter.default.addObserver(self, selector: #selector(masterSelectionDidChange(_:)), name: .MasterSelectionDidChange, object: navState)
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
+ updateUI()
+
}
override func viewWillAppear(_ animated: Bool) {
@@ -89,6 +93,7 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
}
configureUnreadCountForCellsForRepresentedObject(representedObject as AnyObject)
+ updateUI()
}
@@ -138,13 +143,11 @@ class MasterViewController: UITableViewController, UndoableCommandRunner {
}
@objc func masterSelectionDidChange(_ note: Notification) {
-
if let indexPath = navState.currentMasterIndexPath {
if tableView.indexPathForSelectedRow != indexPath {
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .middle)
}
}
-
}
// MARK: Table View
@@ -625,6 +628,10 @@ private extension MasterViewController {
AccountManager.shared.refreshAll()
}
+ func updateUI() {
+ markAllAsReadButton.isEnabled = navState.isAnyUnreadAvailable
+ }
+
func configureCellsForRepresentedObject(_ representedObject: AnyObject) {
applyToCellsForRepresentedObject(representedObject, configure)
diff --git a/iOS/NavigationStateController.swift b/iOS/NavigationStateController.swift
index b29853184..b13e8df32 100644
--- a/iOS/NavigationStateController.swift
+++ b/iOS/NavigationStateController.swift
@@ -114,6 +114,15 @@ class NavigationStateController {
return IndexPath(row: indexPath.row + 1, section: indexPath.section)
}
+ var firstUnreadArticleIndexPath: IndexPath? {
+ for (row, article) in articles.enumerated() {
+ if !article.status.read {
+ return IndexPath(row: row, section: 0)
+ }
+ }
+ return nil
+ }
+
var currentArticle: Article? {
if let indexPath = currentArticleIndexPath {
return articles[indexPath.row]
@@ -145,7 +154,14 @@ class NavigationStateController {
}
}
- var isNextUnreadAvailable: Bool {
+ var isTimelineUnreadAvailable: Bool {
+ if let unreadProvider = timelineFetcher as? UnreadCountProvider {
+ return unreadProvider.unreadCount > 0
+ }
+ return false
+ }
+
+ var isAnyUnreadAvailable: Bool {
return appDelegate.unreadCount > 0
}
diff --git a/iOS/Timeline/MasterTimelineViewController.swift b/iOS/Timeline/MasterTimelineViewController.swift
index 8415d85aa..7abd6e657 100644
--- a/iOS/Timeline/MasterTimelineViewController.swift
+++ b/iOS/Timeline/MasterTimelineViewController.swift
@@ -20,7 +20,8 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
return navState?.showFeedNames ?? false ? rowHeightWithFeedName : rowHeightWithoutFeedName
}
- @IBOutlet weak var nextUnreadButton: UIBarButtonItem!
+ @IBOutlet weak var markAllAsReadButton: UIBarButtonItem!
+ @IBOutlet weak var firstUnreadButton: UIBarButtonItem!
weak var navState: NavigationStateController?
var undoableCommands = [UndoableCommand]()
@@ -34,6 +35,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
super.viewDidLoad()
updateRowHeights()
+ NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(statusesDidChange(_:)), name: .StatusesDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(feedIconDidBecomeAvailable(_:)), name: .FeedIconDidBecomeAvailable, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(avatarDidBecomeAvailable(_:)), name: .AvatarDidBecomeAvailable, object: nil)
@@ -49,11 +51,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
- if let splitViewController = splitViewController {
- splitViewController.delegate = self
- changeToDisplayMode(splitViewController.displayMode)
- }
-
resetUI()
}
@@ -107,8 +104,10 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
- @IBAction func nextUnread(_ sender: Any) {
- navState?.selectNextUnread()
+ @IBAction func firstUnread(_ sender: Any) {
+ if let indexPath = navState?.firstUnreadArticleIndexPath {
+ tableView.scrollToRow(at: indexPath, at: .middle, animated: true)
+ }
}
// MARK: - Table view
@@ -193,6 +192,10 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
}
+ @objc dynamic func unreadCountDidChange(_ notification: Notification) {
+ updateUI()
+ }
+
@objc func statusesDidChange(_ note: Notification) {
guard let articles = note.userInfo?[Account.UserInfoKey.articles] as? Set else {
@@ -276,7 +279,7 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
}
- reloadUI()
+ updateUI()
}
@@ -341,14 +344,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
}
-extension MasterTimelineViewController: UISplitViewControllerDelegate {
-
- func splitViewController(_ svc: UISplitViewController, willChangeTo displayMode: UISplitViewController.DisplayMode) {
- changeToDisplayMode(displayMode)
- }
-
-}
-
// MARK: Private
private extension MasterTimelineViewController {
@@ -357,20 +352,6 @@ private extension MasterTimelineViewController {
AccountManager.shared.refreshAll()
}
- func changeToDisplayMode(_ displayMode: UISplitViewController.DisplayMode) {
-
- if UIDevice.current.userInterfaceIdiom == .pad && displayMode == .allVisible {
- nextUnreadButton.isEnabled = false
- nextUnreadButton.title = ""
- } else {
- nextUnreadButton.isEnabled = false
- nextUnreadButton.title = NSLocalizedString("First Unread", comment: "First Unread")
- }
-
- reloadUI()
-
- }
-
func resetUI() {
updateTableViewRowHeight()
@@ -380,15 +361,13 @@ private extension MasterTimelineViewController {
tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
}
- reloadUI()
+ updateUI()
}
- func reloadUI() {
- // Since there is no hidden property on a bar button item, we just hide its title
- if !(nextUnreadButton.title?.isEmpty ?? true) {
- nextUnreadButton.isEnabled = navState?.isNextUnreadAvailable ?? false
- }
+ func updateUI() {
+ markAllAsReadButton.isEnabled = navState?.isTimelineUnreadAvailable ?? false
+ firstUnreadButton.isEnabled = navState?.isTimelineUnreadAvailable ?? false
}
func configureTimelineCell(_ cell: MasterTimelineTableViewCell, article: Article) {