From b1a9a45f53045841801e4b6baa4ddfe50c798462 Mon Sep 17 00:00:00 2001 From: Maurice Parker Date: Thu, 18 Apr 2019 07:24:55 -0500 Subject: [PATCH] Added the unread count to the Account Section Header. --- NetNewsWire.xcodeproj/project.pbxproj | 4 + iOS/AppAssets.swift | 4 + .../Cell/MasterTableViewCellLayout.swift | 3 + .../Cell/MasterTableViewSectionHeader.swift | 98 +++++++++++++++++++ iOS/Master/MasterViewController.swift | 29 +++++- .../Contents.json | 20 ++++ 6 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 iOS/Master/Cell/MasterTableViewSectionHeader.swift create mode 100644 iOS/Resources/Assets.xcassets/tableSectionHeaderColor.colorset/Contents.json diff --git a/NetNewsWire.xcodeproj/project.pbxproj b/NetNewsWire.xcodeproj/project.pbxproj index dcb6416c8..a56c9ea38 100644 --- a/NetNewsWire.xcodeproj/project.pbxproj +++ b/NetNewsWire.xcodeproj/project.pbxproj @@ -13,6 +13,7 @@ 5127B23A222B4849006D641D /* DetailKeyboardShortcuts.plist in Resources */ = {isa = PBXBuildFile; fileRef = 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */; }; 512E08E62268800D00BDCFDD /* FolderTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97A11ED9F180007D329B /* FolderTreeControllerDelegate.swift */; }; 512E08E72268801200BDCFDD /* FeedTreeControllerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 849A97611ED9EB96007D329B /* FeedTreeControllerDelegate.swift */; }; + 512E09012268907400BDCFDD /* MasterTableViewSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512E08F722688F7C00BDCFDD /* MasterTableViewSectionHeader.swift */; }; 517D9075226639F500323654 /* AddAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517D906B2266392900323654 /* AddAccountViewController.swift */; }; 519B8D332143397200FA689C /* SharingServiceDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 519B8D322143397200FA689C /* SharingServiceDelegate.swift */; }; 51C451A9226377C200C03939 /* ArticlesDatabase.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8407167F2262A61100344432 /* ArticlesDatabase.framework */; }; @@ -601,6 +602,7 @@ 51126DA3225FDE2F00722696 /* RSImage-Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RSImage-Extensions.swift"; sourceTree = ""; }; 5127B236222B4849006D641D /* DetailKeyboardDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DetailKeyboardDelegate.swift; sourceTree = ""; }; 5127B237222B4849006D641D /* DetailKeyboardShortcuts.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = DetailKeyboardShortcuts.plist; sourceTree = ""; }; + 512E08F722688F7C00BDCFDD /* MasterTableViewSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTableViewSectionHeader.swift; sourceTree = ""; }; 517D906B2266392900323654 /* AddAccountViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddAccountViewController.swift; sourceTree = ""; }; 519B8D322143397200FA689C /* SharingServiceDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingServiceDelegate.swift; sourceTree = ""; }; 51C4524E226506F400C03939 /* UIStoryboard-Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard-Extensions.swift"; sourceTree = ""; }; @@ -916,6 +918,7 @@ 51C45260226508F600C03939 /* Cell */ = { isa = PBXGroup; children = ( + 512E08F722688F7C00BDCFDD /* MasterTableViewSectionHeader.swift */, 51C45262226508F600C03939 /* MasterTableViewCell.swift */, 51C45263226508F600C03939 /* MasterTableViewCellLayout.swift */, 51C45261226508F600C03939 /* MasterUnreadCountView.swift */, @@ -2170,6 +2173,7 @@ 51C452882265093600C03939 /* AddFeedViewController.swift in Sources */, 51C4527A2265091600C03939 /* SingleLineUILabelSizer.swift in Sources */, 51C4529B22650A1000C03939 /* FaviconDownloader.swift in Sources */, + 512E09012268907400BDCFDD /* MasterTableViewSectionHeader.swift in Sources */, 51C45268226508F600C03939 /* MasterUnreadCountView.swift in Sources */, 51C452B1226510E600C03939 /* InitialFeedDownloader.swift in Sources */, 51C4529F22650A1900C03939 /* AuthorAvatarDownloader.swift in Sources */, diff --git a/iOS/AppAssets.swift b/iOS/AppAssets.swift index 459c97cd3..45afe7630 100644 --- a/iOS/AppAssets.swift +++ b/iOS/AppAssets.swift @@ -65,6 +65,10 @@ struct AppAssets { return RSImage(named: "starOpenImage")! }() + static var tableSectionHeaderColor: UIColor = { + return UIColor(named: "tableSectionHeaderColor")! + }() + static var timelineStarImage: RSImage = { let image = RSImage(named: "starClosedImage")! return image.maskWithColor(color: AppAssets.starColor)! diff --git a/iOS/Master/Cell/MasterTableViewCellLayout.swift b/iOS/Master/Cell/MasterTableViewCellLayout.swift index 26418f20e..cf61a90ac 100644 --- a/iOS/Master/Cell/MasterTableViewCellLayout.swift +++ b/iOS/Master/Cell/MasterTableViewCellLayout.swift @@ -43,7 +43,10 @@ struct MasterTableViewCellLayout { var rLabel = CGRect(x: 0.0, y: 0.0, width: labelSize.width, height: labelSize.height) if shouldShowImage { rLabel.origin.x = rFavicon.maxX + MasterTableViewCellLayout.imageMarginRight + } else { + rLabel.origin.x = indent ? 20 : 0 } + rLabel = MasterTableViewCellLayout.centerVertically(rLabel, bounds) // Unread Count diff --git a/iOS/Master/Cell/MasterTableViewSectionHeader.swift b/iOS/Master/Cell/MasterTableViewSectionHeader.swift new file mode 100644 index 000000000..df91732be --- /dev/null +++ b/iOS/Master/Cell/MasterTableViewSectionHeader.swift @@ -0,0 +1,98 @@ +// +// MasterTableViewSectionHeader.swift +// NetNewsWire +// +// Created by Maurice Parker on 4/18/19. +// Copyright © 2019 Ranchero Software. All rights reserved. +// + +import UIKit + +class MasterTableViewSectionHeader: UITableViewHeaderFooterView { + + override var accessibilityLabel: String? { + set {} + get { + if unreadCount > 0 { + let unreadLabel = NSLocalizedString("unread", comment: "Unread label for accessiblity") + return "\(name) \(unreadCount) \(unreadLabel)" + } else { + return name + } + } + } + + var unreadCount: Int { + get { + return unreadCountView.unreadCount + } + set { + if unreadCountView.unreadCount != newValue { + unreadCountView.unreadCount = newValue + unreadCountView.isHidden = (newValue < 1) + setNeedsLayout() + } + } + } + + var name: String { + get { + return titleView.text ?? "" + } + set { + if titleView.text != newValue { + titleView.text = newValue + setNeedsDisplay() + setNeedsLayout() + } + } + } + + private let titleView: UILabel = { + let label = UILabel() + label.font = UIFont.boldSystemFont(ofSize: 17.0) + label.numberOfLines = 1 + label.lineBreakMode = .byTruncatingTail + label.allowsDefaultTighteningForTruncation = false + return label + }() + + private let unreadCountView = MasterUnreadCountView(frame: CGRect.zero) + + override init(reuseIdentifier: String?) { + super.init(reuseIdentifier: reuseIdentifier) + commonInit() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + override func layoutSubviews() { + super.layoutSubviews() + let layout = MasterTableViewCellLayout(cellSize: bounds.size, shouldShowImage: false, label: titleView, unreadCountView: unreadCountView, showingEditingControl: false, indent: true, shouldShowDisclosure: false) + layoutWith(layout) + } + +} + +private extension MasterTableViewSectionHeader { + + func commonInit() { + backgroundColor = AppAssets.tableSectionHeaderColor + addSubviewAtInit(unreadCountView) + addSubviewAtInit(titleView) + } + + func addSubviewAtInit(_ view: UIView) { + addSubview(view) + view.translatesAutoresizingMaskIntoConstraints = false + } + + func layoutWith(_ layout: MasterTableViewCellLayout) { + titleView.rs_setFrameIfNotEqual(layout.titleRect) + unreadCountView.rs_setFrameIfNotEqual(layout.unreadCountRect) + } + +} diff --git a/iOS/Master/MasterViewController.swift b/iOS/Master/MasterViewController.swift index 643955dbe..6ebb11744 100644 --- a/iOS/Master/MasterViewController.swift +++ b/iOS/Master/MasterViewController.swift @@ -35,6 +35,8 @@ class MasterViewController: UITableViewController, UndoableCommandRunner { navigationItem.rightBarButtonItem = editButtonItem + tableView.register(MasterTableViewSectionHeader.self, forHeaderFooterViewReuseIdentifier: "SectionHeader") + NotificationCenter.default.addObserver(self, selector: #selector(unreadCountDidChange(_:)), name: .UnreadCountDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(containerChildrenDidChange(_:)), name: .ChildrenDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(batchUpdateDidPerform(_:)), name: .BatchUpdateDidPerform, object: nil) @@ -94,10 +96,22 @@ class MasterViewController: UITableViewController, UndoableCommandRunner { } @objc func unreadCountDidChange(_ note: Notification) { + guard let representedObject = note.object else { return } + + if let account = representedObject as? Account { + if let node = treeController.rootNode.childNodeRepresentingObject(account) { + let sectionIndex = treeController.rootNode.indexOfChild(node)! + let headerView = tableView.headerView(forSection: sectionIndex) as! MasterTableViewSectionHeader + headerView.unreadCount = account.unreadCount + } + return + } + configureUnreadCountForCellsForRepresentedObject(representedObject as AnyObject) + } @objc func faviconDidBecomeAvailable(_ note: Notification) { @@ -137,11 +151,21 @@ class MasterViewController: UITableViewController, UndoableCommandRunner { return shadowTable[section].count } - override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { + override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { + guard let nameProvider = treeController.rootNode.childAtIndex(section)?.representedObject as? DisplayNameProvider else { return nil } - return nameProvider.nameForDisplay + + let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "SectionHeader") as! MasterTableViewSectionHeader + headerView.name = nameProvider.nameForDisplay + + if let account = treeController.rootNode.childAtIndex(section)?.representedObject as? Account { + headerView.unreadCount = account.unreadCount + } + + return headerView + } override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { @@ -519,7 +543,6 @@ private extension MasterViewController { shadowTable[i] = result } - } diff --git a/iOS/Resources/Assets.xcassets/tableSectionHeaderColor.colorset/Contents.json b/iOS/Resources/Assets.xcassets/tableSectionHeaderColor.colorset/Contents.json new file mode 100644 index 000000000..80a53cfdc --- /dev/null +++ b/iOS/Resources/Assets.xcassets/tableSectionHeaderColor.colorset/Contents.json @@ -0,0 +1,20 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + }, + "colors" : [ + { + "idiom" : "universal", + "color" : { + "color-space" : "srgb", + "components" : { + "red" : "246", + "alpha" : "1.000", + "blue" : "246", + "green" : "246" + } + } + } + ] +} \ No newline at end of file