Make First Unread scroll to first unread in timeline.
Update Mark As Read and other unread dependent UI respond to unread count changing.
This commit is contained in:
parent
e54056ceac
commit
e1b031e6db
@ -99,7 +99,7 @@
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</toolbarItems>
|
||||
<navigationItem key="navigationItem" id="mOI-FS-AaM"/>
|
||||
<navigationItem key="navigationItem" largeTitleDisplayMode="never" id="mOI-FS-AaM"/>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="actionBarButtonItem" destination="9Ut-5B-JKP" id="9bO-kz-cTz"/>
|
||||
@ -149,16 +149,17 @@
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
<barButtonItem style="plain" systemItem="flexibleSpace" id="93y-8j-WBh"/>
|
||||
<barButtonItem enabled="NO" title="First Unread" id="2v2-jD-C9k">
|
||||
<barButtonItem title="First Unread" id="2v2-jD-C9k">
|
||||
<connections>
|
||||
<action selector="nextUnread:" destination="Kyk-vK-QRX" id="lwt-VU-zdW"/>
|
||||
<action selector="firstUnread:" destination="Kyk-vK-QRX" id="d5y-x5-Qht"/>
|
||||
</connections>
|
||||
</barButtonItem>
|
||||
</toolbarItems>
|
||||
<navigationItem key="navigationItem" title="Timeline" largeTitleDisplayMode="never" id="wcC-1L-ug4"/>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="nextUnreadButton" destination="2v2-jD-C9k" id="9rf-5I-18f"/>
|
||||
<outlet property="firstUnreadButton" destination="2v2-jD-C9k" id="8NP-Uc-3Fn"/>
|
||||
<outlet property="markAllAsReadButton" destination="fTv-eX-72r" id="12S-lN-Sxa"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="nzm-Gf-Xce" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
@ -244,6 +245,9 @@
|
||||
</barButtonItem>
|
||||
</navigationItem>
|
||||
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
|
||||
<connections>
|
||||
<outlet property="markAllAsReadButton" destination="ddj-Ya-Wol" id="jjr-OK-4zl"/>
|
||||
</connections>
|
||||
</tableViewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
|
@ -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<Article> else {
|
||||
return
|
||||
}
|
||||
if articles.count == 1 && articles.first?.articleID == navState?.currentArticle?.articleID {
|
||||
reloadUI()
|
||||
updateUI()
|
||||
}
|
||||
}
|
||||
|
||||
@objc func articleSelectionDidChange(_ note: Notification) {
|
||||
markAsRead()
|
||||
reloadUI()
|
||||
updateUI()
|
||||
reloadHTML()
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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<Article> 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) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user