Replace Mark All as Read with progress indicator. Issues #1157 and #1165

This commit is contained in:
Maurice Parker
2019-10-25 13:34:59 -05:00
parent fa24e8a863
commit 6a281c7672
13 changed files with 153 additions and 398 deletions

View File

@@ -93,8 +93,6 @@
517630232336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */; };
5183CCD0226E1E880010922C /* NonIntrinsicLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */; };
5183CCDA226E31A50010922C /* NonIntrinsicImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */; };
5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */; };
5183CCDF226F1FCC0010922C /* UINavigationController+Progress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCDE226F1FCC0010922C /* UINavigationController+Progress.swift */; };
5183CCE5226F4DFA0010922C /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; };
5183CCE6226F4E110010922C /* RefreshInterval.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE4226F4DFA0010922C /* RefreshInterval.swift */; };
5183CCE8226F68D90010922C /* AccountRefreshTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */; };
@@ -194,6 +192,8 @@
51C452B42265141B00C03939 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 51C452B32265141B00C03939 /* WebKit.framework */; };
51C452B82265178500C03939 /* styleSheet.css in Resources */ = {isa = PBXBuildFile; fileRef = 51C452B72265178500C03939 /* styleSheet.css */; };
51CC9B3E231720B2000E842F /* MasterFeedDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CC9B3D231720B2000E842F /* MasterFeedDataSource.swift */; };
51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 51CE1C0823621EDA005548FC /* RefreshProgressView.xib */; };
51CE1C0B23622007005548FC /* RefreshProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51CE1C0A23622006005548FC /* RefreshProgressView.swift */; };
51D5948722668EFA00DFC836 /* MarkStatusCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 84702AA31FA27AC0006B8943 /* MarkStatusCommand.swift */; };
51D6A5BC23199C85001C27D8 /* MasterTimelineDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */; };
51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */ = {isa = PBXBuildFile; fileRef = 51D87EE02311D34700E63F03 /* ActivityType.swift */; };
@@ -1251,8 +1251,6 @@
517630222336657E00E15FFF /* ArticleViewControllerWebViewProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleViewControllerWebViewProvider.swift; sourceTree = "<group>"; };
5183CCCF226E1E880010922C /* NonIntrinsicLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicLabel.swift; sourceTree = "<group>"; };
5183CCD9226E31A50010922C /* NonIntrinsicImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NonIntrinsicImageView.swift; sourceTree = "<group>"; };
5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationProgressView.swift; sourceTree = "<group>"; };
5183CCDE226F1FCC0010922C /* UINavigationController+Progress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Progress.swift"; sourceTree = "<group>"; };
5183CCE4226F4DFA0010922C /* RefreshInterval.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshInterval.swift; sourceTree = "<group>"; };
5183CCE7226F68D90010922C /* AccountRefreshTimer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountRefreshTimer.swift; sourceTree = "<group>"; };
518651AB23555EB20078E021 /* NNW3Document.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NNW3Document.swift; sourceTree = "<group>"; };
@@ -1300,6 +1298,8 @@
51C452B32265141B00C03939 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS12.2.sdk/System/Library/Frameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; };
51C452B72265178500C03939 /* styleSheet.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; path = styleSheet.css; sourceTree = "<group>"; };
51CC9B3D231720B2000E842F /* MasterFeedDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterFeedDataSource.swift; sourceTree = "<group>"; };
51CE1C0823621EDA005548FC /* RefreshProgressView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = RefreshProgressView.xib; sourceTree = "<group>"; };
51CE1C0A23622006005548FC /* RefreshProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RefreshProgressView.swift; sourceTree = "<group>"; };
51D6A5BB23199C85001C27D8 /* MasterTimelineDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MasterTimelineDataSource.swift; sourceTree = "<group>"; };
51D87EE02311D34700E63F03 /* ActivityType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityType.swift; sourceTree = "<group>"; };
51E3EB32229AB02C00645299 /* ErrorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorHandler.swift; sourceTree = "<group>"; };
@@ -1766,15 +1766,6 @@
path = Account;
sourceTree = "<group>";
};
5183CCDB226F1EEB0010922C /* Progress */ = {
isa = PBXGroup;
children = (
5183CCDC226F1F5C0010922C /* NavigationProgressView.swift */,
5183CCDE226F1FCC0010922C /* UINavigationController+Progress.swift */,
);
path = Progress;
sourceTree = "<group>";
};
5183CCEA226F70350010922C /* Timer */ = {
isa = PBXGroup;
children = (
@@ -1854,9 +1845,10 @@
51C4525D226508F600C03939 /* MasterFeed */ = {
isa = PBXGroup;
children = (
FFD43E372340F320009E5CA3 /* UndoAvailableAlertController.swift */,
51C45264226508F600C03939 /* MasterFeedViewController.swift */,
51CC9B3D231720B2000E842F /* MasterFeedDataSource.swift */,
51CE1C0A23622006005548FC /* RefreshProgressView.swift */,
51CE1C0823621EDA005548FC /* RefreshProgressView.xib */,
51C45260226508F600C03939 /* Cell */,
);
path = MasterFeed;
@@ -1881,6 +1873,7 @@
5148F4542336DB7000F8CD8B /* MasterTimelineTitleView.swift */,
5148F44A2336DB4700F8CD8B /* MasterTimelineTitleView.xib */,
51FD413A2342BD0500880194 /* MasterTimelineUnreadCountView.swift */,
FFD43E372340F320009E5CA3 /* UndoAvailableAlertController.swift */,
51C4526F2265091600C03939 /* Cell */,
);
path = MasterTimeline;
@@ -2538,7 +2531,6 @@
51C452802265093600C03939 /* Add */,
5123DB95233EC69300282CC9 /* Inspector */,
513145F9235A55A700387FDC /* Intents */,
5183CCDB226F1EEB0010922C /* Progress */,
5183CCEB227117C70010922C /* Settings */,
519D740423243C68008BB345 /* Model Extensions */,
51C45245226506C800C03939 /* UIKit Extensions */,
@@ -3403,6 +3395,7 @@
51A1699A235E10D700EB091F /* Settings.storyboard in Resources */,
49F40DF92335B71000552BF4 /* newsfoot.js in Resources */,
51F85BEF2272520B00C787DC /* Thanks.rtf in Resources */,
51CE1C0923621EDA005548FC /* RefreshProgressView.xib in Resources */,
84C9FC9D2262A1A900D921D6 /* Assets.xcassets in Resources */,
514219582353C28900E07E2C /* main_ios.js in Resources */,
51C452B82265178500C03939 /* styleSheet.css in Resources */,
@@ -3889,7 +3882,6 @@
51AF460E232488C6001742EF /* Account-Extensions.swift in Sources */,
51FD413B2342BD0500880194 /* MasterTimelineUnreadCountView.swift in Sources */,
513146B2235A81A400387FDC /* AddFeedIntentHandler.swift in Sources */,
5183CCDD226F1F5C0010922C /* NavigationProgressView.swift in Sources */,
51D87EE12311D34700E63F03 /* ActivityType.swift in Sources */,
51C452772265091600C03939 /* MultilineUILabelSizer.swift in Sources */,
51C452A522650A2D00C03939 /* SmallIconProvider.swift in Sources */,
@@ -3915,7 +3907,6 @@
51BB7C272335A8E5008E8144 /* ArticleActivityItemSource.swift in Sources */,
51F85BF52273625800C787DC /* Bundle-Extensions.swift in Sources */,
51C452A622650A3500C03939 /* Node-Extensions.swift in Sources */,
5183CCDF226F1FCC0010922C /* UINavigationController+Progress.swift in Sources */,
51C45294226509C800C03939 /* SearchFeedDelegate.swift in Sources */,
5F323809231DF9F000706F6B /* VibrantTableViewCell.swift in Sources */,
512E09352268B25900BDCFDD /* UISplitViewController-Extensions.swift in Sources */,
@@ -3982,6 +3973,7 @@
51FFF0C4235EE8E5002762AA /* VibrantButton.swift in Sources */,
513228FC233037630033D4ED /* Reachability.swift in Sources */,
51C45259226508D300C03939 /* AppDefaults.swift in Sources */,
51CE1C0B23622007005548FC /* RefreshProgressView.swift in Sources */,
511D4419231FC02D00FB1562 /* KeyboardManager.swift in Sources */,
51A1699D235E10D700EB091F /* SettingsViewController.swift in Sources */,
51C45293226509C800C03939 /* StarredFeedDelegate.swift in Sources */,

View File

@@ -96,7 +96,6 @@ class ArticleViewController: UIViewController {
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(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
@@ -126,11 +125,6 @@ class ArticleViewController: UIViewController {
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateProgressIndicatorIfNeeded()
}
func updateUI() {
guard let article = currentArticle else {
@@ -209,10 +203,6 @@ class ArticleViewController: UIViewController {
}
}
@objc func progressDidChange(_ note: Notification) {
updateProgressIndicatorIfNeeded()
}
@objc func contentSizeCategoryDidChange(_ note: Notification) {
reloadHTML()
}
@@ -427,12 +417,6 @@ private struct ImageClickMessage: Codable {
private extension ArticleViewController {
func updateProgressIndicatorIfNeeded() {
if !(UIDevice.current.userInterfaceIdiom == .pad) {
navigationController?.updateAccountRefreshProgressIndicator()
}
}
func imageWasClicked(body: String?) {
guard let body = body,
let data = body.data(using: .utf8),

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Cqo-6I-B1A">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Cqo-6I-B1A">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15508"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -65,7 +65,6 @@
</connections>
</tableView>
<toolbarItems>
<barButtonItem title="Mark All as Read" id="BzW-aD-jIq"/>
<barButtonItem style="plain" systemItem="flexibleSpace" id="Kjl-Sb-QP1"/>
<barButtonItem systemItem="add" id="PVr-3K-nPg"/>
</toolbarItems>
@@ -114,6 +113,6 @@
</scene>
</scenes>
<resources>
<image name="gear" catalog="system" width="64" height="60"/>
<image name="gear" catalog="system" width="64" height="58"/>
</resources>
</document>

View File

@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14868" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Cqo-6I-B1A">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Cqo-6I-B1A">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14824"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15508"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
@@ -65,7 +65,6 @@
</connections>
</tableView>
<toolbarItems>
<barButtonItem title="Mark All as Read" id="BzW-aD-jIq"/>
<barButtonItem style="plain" systemItem="flexibleSpace" id="Kjl-Sb-QP1"/>
<barButtonItem systemItem="add" id="PVr-3K-nPg"/>
</toolbarItems>
@@ -114,6 +113,6 @@
</scene>
</scenes>
<resources>
<image name="gear" catalog="system" width="64" height="60"/>
<image name="gear" catalog="system" width="64" height="58"/>
</resources>
</document>

View File

@@ -190,22 +190,7 @@
<outlet property="delegate" destination="7bK-jq-Zjz" id="RA6-mI-bju"/>
</connections>
</tableView>
<toolbarItems>
<barButtonItem title="Mark All as Read" id="ddj-Ya-Wol">
<connections>
<action selector="markAllAsRead:" destination="7bK-jq-Zjz" id="jmv-SM-7XE"/>
</connections>
</barButtonItem>
<barButtonItem style="plain" systemItem="flexibleSpace" id="ePD-cM-h2y"/>
<barButtonItem systemItem="add" id="yo6-w4-SfI">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="accLabelText" value="Add Feed or Folder"/>
</userDefinedRuntimeAttributes>
<connections>
<action selector="add:" destination="7bK-jq-Zjz" id="k61-ub-SdZ"/>
</connections>
</barButtonItem>
</toolbarItems>
<toolbarItems/>
<navigationItem key="navigationItem" title="Feeds" id="Zdf-7t-Un8">
<barButtonItem key="leftBarButtonItem" title="Settings" image="gear" catalog="system" id="TlU-Pg-ATe">
<userDefinedRuntimeAttributes>
@@ -218,10 +203,6 @@
</navigationItem>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" prompted="NO"/>
<simulatedToolbarMetrics key="simulatedBottomBarMetrics"/>
<connections>
<outlet property="addNewItemButton" destination="yo6-w4-SfI" id="NbL-RH-N4J"/>
<outlet property="markAllAsReadButton" destination="ddj-Ya-Wol" id="jjr-OK-4zl"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Rux-fX-hf1" sceneMemberID="firstResponder"/>
</objects>

View File

@@ -14,8 +14,8 @@ import RSTree
class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
@IBOutlet private weak var markAllAsReadButton: UIBarButtonItem!
@IBOutlet private weak var addNewItemButton: UIBarButtonItem!
private var refreshProgressView: RefreshProgressView!
private var addNewItemButton: UIBarButtonItem!
private lazy var dataSource = makeDataSource()
var undoableCommands = [UndoableCommand]()
@@ -54,12 +54,13 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
NotificationCenter.default.addObserver(self, selector: #selector(feedSettingDidChange(_:)), name: .FeedSettingDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(feedMetadataDidChange(_:)), name: .FeedMetadataDidChange, 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(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil)
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
configureToolbar()
updateUI()
becomeFirstResponder()
@@ -73,7 +74,6 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
navigationController?.updateAccountRefreshProgressIndicator()
}
// MARK: Notifications
@@ -133,10 +133,6 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
discloseFeed(feed)
}
@objc func progressDidChange(_ note: Notification) {
navigationController?.updateAccountRefreshProgressIndicator()
}
@objc func contentSizeCategoryDidChange(_ note: Notification) {
applyChanges(animate: false)
}
@@ -344,19 +340,6 @@ class MasterFeedViewController: UITableViewController, UndoableCommandRunner {
@IBAction func settings(_ sender: UIBarButtonItem) {
coordinator.showSettings()
}
@IBAction func markAllAsRead(_ sender: Any) {
if coordinator.displayUndoAvailableTip {
let alertController = UndoAvailableAlertController.alert { [weak self] _ in
self?.coordinator.displayUndoAvailableTip = false
self?.coordinator.markAllAsRead()
}
present(alertController, animated: true)
} else {
coordinator.markAllAsRead()
}
}
@IBAction func add(_ sender: UIBarButtonItem) {
coordinator.showAdd(.feed)
@@ -573,8 +556,21 @@ extension MasterFeedViewController: MasterFeedTableViewCellDelegate {
private extension MasterFeedViewController {
func configureToolbar() {
guard let refreshProgressView = Bundle.main.loadNibNamed("RefreshProgressView", owner: self, options: nil)?[0] as? RefreshProgressView else {
return
}
self.refreshProgressView = refreshProgressView
let refreshProgressItemButton = UIBarButtonItem(customView: refreshProgressView)
let spaceItemButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
addNewItemButton = UIBarButtonItem(barButtonSystemItem: .add, target: self, action: #selector(add(_:)))
setToolbarItems([refreshProgressItemButton, spaceItemButton, addNewItemButton], animated: false)
}
func updateUI() {
markAllAsReadButton.isEnabled = coordinator.isAnyUnreadAvailable
refreshProgressView.updateRefreshLabel()
addNewItemButton.isEnabled = !AccountManager.shared.activeAccounts.isEmpty
}

View File

@@ -0,0 +1,70 @@
//
// RefeshProgressView.swift
// NetNewsWire-iOS
//
// Created by Maurice Parker on 10/24/19.
// Copyright © 2019 Ranchero Software. All rights reserved.
//
import UIKit
import Account
class RefreshProgressView: UIView {
@IBOutlet weak var progressView: UIProgressView!
@IBOutlet weak var label: UILabel!
private lazy var progressWidth = progressView.widthAnchor.constraint(equalToConstant: 100.0)
override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
commonInit()
}
func commonInit() {
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
}
func updateRefreshLabel() {
if let refreshDate = AppDefaults.lastRefresh {
let relativeDateTimeFormatter = RelativeDateTimeFormatter()
relativeDateTimeFormatter.dateTimeStyle = .named
let refreshed = relativeDateTimeFormatter.localizedString(for: refreshDate, relativeTo: Date())
let localizedRefreshText = NSLocalizedString("Refreshed %@", comment: "Refreshed")
let refreshText = NSString.localizedStringWithFormat(localizedRefreshText as NSString, refreshed) as String
label.text = refreshText
}
}
@objc func progressDidChange(_ note: Notification) {
let progress = AccountManager.shared.combinedRefreshProgress
if progress.isComplete {
progressView.progress = 1
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
self.updateRefreshLabel()
self.label.isHidden = false
self.progressView.isHidden = true
self.progressWidth.isActive = false
}
} else {
label.isHidden = true
progressView.isHidden = false
self.progressWidth.isActive = true
let percent = Float(progress.numberCompleted) / Float(progress.numberOfTasks)
progressView.progress = percent
}
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}

View File

@@ -0,0 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="15504" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait" appearance="light"/>
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15508"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner"/>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB" customClass="RefreshProgressView" customModule="NetNewsWire" customModuleProvider="target">
<rect key="frame" x="0.0" y="0.0" width="375" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<progressView hidden="YES" opaque="NO" contentMode="scaleToFill" verticalHuggingPriority="750" progress="0.5" translatesAutoresizingMaskIntoConstraints="NO" id="gKH-fc-zh7">
<rect key="frame" x="0.0" y="27.5" width="375" height="5"/>
<constraints>
<constraint firstAttribute="height" constant="5" id="OCl-qi-owb"/>
</constraints>
</progressView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="07B-Zy-FCt">
<rect key="frame" x="0.0" y="22" width="375" height="16"/>
<fontDescription key="fontDescription" style="UICTFontTextStyleFootnote"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="07B-Zy-FCt" firstAttribute="leading" secondItem="vUN-kp-3ea" secondAttribute="leading" id="6eL-GN-NIE"/>
<constraint firstItem="07B-Zy-FCt" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="QJ0-os-kZt"/>
<constraint firstAttribute="trailing" secondItem="gKH-fc-zh7" secondAttribute="trailing" id="SbS-0T-bdo"/>
<constraint firstItem="gKH-fc-zh7" firstAttribute="leading" secondItem="iN0-l3-epB" secondAttribute="leading" id="V0P-ix-fa3"/>
<constraint firstItem="vUN-kp-3ea" firstAttribute="trailing" secondItem="07B-Zy-FCt" secondAttribute="trailing" id="Zor-53-U98"/>
<constraint firstItem="gKH-fc-zh7" firstAttribute="centerY" secondItem="iN0-l3-epB" secondAttribute="centerY" id="mnf-7m-knt"/>
</constraints>
<nil key="simulatedTopBarMetrics"/>
<nil key="simulatedBottomBarMetrics"/>
<freeformSimulatedSizeMetrics key="simulatedDestinationMetrics"/>
<viewLayoutGuide key="safeArea" id="vUN-kp-3ea"/>
<connections>
<outlet property="label" destination="07B-Zy-FCt" id="UEr-Dh-NBo"/>
<outlet property="progressView" destination="gKH-fc-zh7" id="Una-CD-Zi8"/>
</connections>
<point key="canvasLocation" x="-151" y="6"/>
</view>
</objects>
</document>

View File

@@ -44,14 +44,9 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
NotificationCenter.default.addObserver(self, selector: #selector(avatarDidBecomeAvailable(_:)), name: .AvatarDidBecomeAvailable, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(faviconDidBecomeAvailable(_:)), name: .FaviconDidBecomeAvailable, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(userDefaultsDidChange(_:)), name: UserDefaults.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange), name: UIContentSizeCategory.didChangeNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(displayNameDidChange), name: .DisplayNameDidChange, object: nil)
// Setup the Refresh Control
refreshControl = UIRefreshControl()
refreshControl!.addTarget(self, action: #selector(refreshAccounts(_:)), for: .valueChanged)
// Configure the table
tableView.dataSource = dataSource
numberOfTextLines = AppDefaults.timelineNumberOfLines
@@ -66,11 +61,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
super.viewWillAppear(animated)
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
updateProgressIndicatorIfNeeded()
}
override func viewWillLayoutSubviews() {
// If you setup the Search Controller in viewWillLayoutSubviews it won't show by default on creation
searchController.delegate = self
@@ -368,10 +358,6 @@ class MasterTimelineViewController: UITableViewController, UndoableCommandRunner
reloadAllVisibleCells()
}
@objc func progressDidChange(_ note: Notification) {
updateProgressIndicatorIfNeeded()
}
@objc func displayNameDidChange(_ note: Notification) {
titleView?.label.text = coordinator.timelineName
}
@@ -455,15 +441,6 @@ extension MasterTimelineViewController: UISearchBarDelegate {
private extension MasterTimelineViewController {
@objc private func refreshAccounts(_ sender: Any) {
refreshControl?.endRefreshing()
// This is a hack to make sure that an error dialog doesn't interfere with dismissing the refreshControl.
// If the error dialog appears too closely to the call to endRefreshing, then the refreshControl never disappears.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
AccountManager.shared.refreshAll(errorHandler: ErrorHandler.present(self))
}
}
func resetUI() {
title = coordinator.timelineName
@@ -521,12 +498,6 @@ private extension MasterTimelineViewController {
}
}
func updateProgressIndicatorIfNeeded() {
if !coordinator.isThreePanelMode {
navigationController?.updateAccountRefreshProgressIndicator()
}
}
func applyChanges(animate: Bool, completion: (() -> Void)? = nil) {
var snapshot = NSDiffableDataSourceSnapshot<Int, Article>()
snapshot.appendSections([0])

View File

@@ -1,132 +0,0 @@
//
// NavigationProgressView.swift
// KYNavigationProgress
//
// Created by kyo__hei on 2015/12/29.
// Copyright (c) 2015 kyo__hei. All rights reserved.
//
// Original project: https://github.com/ykyouhei/KYNavigationProgress
import UIKit
public final class NavigationProgressView: UIView {
/* ====================================================================== */
// MARK: - Properties
/* ====================================================================== */
internal var progress: Float = 0 {
didSet {
progress = min(1, progress)
barWidthConstraint.constant = bounds.width * CGFloat(progress)
}
}
internal let bar = UIView()
@objc public dynamic var progressTintColor: UIColor? = AppAssets.primaryAccentColor {
didSet {
bar.backgroundColor = progressTintColor
}
}
@objc public dynamic var trackTintColor: UIColor? = .clear {
didSet {
backgroundColor = trackTintColor
}
}
fileprivate let barWidthConstraint: NSLayoutConstraint
override public var frame: CGRect {
didSet {
let tmpProgress = progress
progress = tmpProgress
}
}
/* ====================================================================== */
// MARK: - initializer
/* ====================================================================== */
required public init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override init(frame: CGRect) {
barWidthConstraint = NSLayoutConstraint(
item: bar,
attribute: .width,
relatedBy: .equal,
toItem: nil,
attribute: .notAnAttribute,
multiplier: 1,
constant: frame.width * CGFloat(progress))
super.init(frame: frame)
let leftConstraint = NSLayoutConstraint(
item: bar,
attribute: .left,
relatedBy: .equal,
toItem: self,
attribute: .left,
multiplier: 1,
constant: 0)
let bottomConstraint = NSLayoutConstraint(
item: bar,
attribute: .bottom,
relatedBy: .equal,
toItem: self,
attribute: .bottom,
multiplier: 1,
constant: 0)
let topConstraint = NSLayoutConstraint(
item: bar,
attribute: .top,
relatedBy: .equal,
toItem: self,
attribute: .top,
multiplier: 1,
constant: 0)
addSubview(bar)
backgroundColor = trackTintColor
bar.backgroundColor = progressTintColor
bar.translatesAutoresizingMaskIntoConstraints = false
addConstraints([
barWidthConstraint,
leftConstraint,
topConstraint,
bottomConstraint])
}
/* ====================================================================== */
// MARK: - Notification
/* ====================================================================== */
func deviceDidRotate(_ notification: Notification) {
}
/* ====================================================================== */
// MARK: - Method
/* ====================================================================== */
internal func setProgress(_ progress: Float, animated: Bool, completion: @escaping () -> Void) {
let duration: TimeInterval = animated ? 0.2 : 0
self.progress = progress
UIView.animate(withDuration: duration, animations: { self.layoutIfNeeded() }) { _ in
completion()
}
}
}

View File

@@ -1,145 +0,0 @@
//
// UINavigationController+Progress.swift
// KYNavigationProgress
//
// Created by kyo__hei on 2015/12/29.
// Copyright (c) 2015 kyo__hei. All rights reserved.
//
// Original project: https://github.com/ykyouhei/KYNavigationProgress
import UIKit
import Account
private let constraintIdentifier = "progressHeightConstraint"
public extension UINavigationController {
/* ====================================================================== */
// MARK: - Properties
/* ====================================================================== */
/**
Default is 2.0
*/
var progressHeight: CGFloat {
get { return progressView.frame.height }
set {
progressView.frame.origin.y = navigationBar.frame.height - newValue
progressView.frame.size.height = newValue
}
}
/**
The color shown for the portion of the progress bar that is not filled.
default is clear color.
*/
var trackTintColor: UIColor? {
get { return progressView.trackTintColor }
set { progressView.trackTintColor = newValue }
}
/**
The color shown for the portion of the progress bar that is filled.
default is (r: 0, g: 122, b: 225, a: 255.
*/
var progressTintColor: UIColor? {
get { return progressView.progressTintColor }
set { progressView.progressTintColor = newValue }
}
/**
The current progress is represented by a floating-point value between 0.0 and 1.0,
inclusive, where 1.0 indicates the completion of the task. The default value is 0.0.
*/
var progress: Float {
get { return progressView.progress }
set { progressView.progress = newValue }
}
private var progressView: NavigationProgressView {
for subview in navigationBar.subviews {
if let progressView = subview as? NavigationProgressView {
return progressView
}
}
let defaultHeight = CGFloat(2)
let frame = CGRect(
x: 0,
y: navigationBar.frame.height - defaultHeight,
width: navigationBar.frame.width,
height: defaultHeight
)
let progressView = NavigationProgressView(frame: frame)
navigationBar.addSubview(progressView)
progressView.autoresizingMask = [
.flexibleWidth, .flexibleTopMargin
]
return progressView
}
/* ====================================================================== */
// MARK: - Public Method
/* ====================================================================== */
/**
Adjusts the current progress shown by the receiver, optionally animating the change.
- parameter progress: The new progress value.
- parameter animated: true if the change should be animated, false if the change should happen immediately.
*/
func setProgress(_ progress: Float, animated: Bool, completion: @escaping () -> Void) {
progressView.bar.alpha = 1
progressView.setProgress(progress, animated: animated, completion: completion)
}
/**
While progress is changed to 1.0, the bar will fade out. After that, progress will be 0.0.
*/
func finishProgress() {
progressView.bar.alpha = 1
progressView.setProgress(1, animated: true) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
UIView.animate(withDuration: 0.5, animations: { self.progressView.bar.alpha = 0 }) { finished in
self.progressView.progress = 0
}
}
}
}
/**
While progress is changed to 0.0, the bar will fade out.
*/
func cancelProgress() {
progressView.setProgress(0, animated: true) {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
UIView.animate(withDuration: 0.5, animations: {
self.progressView.bar.alpha = 0
})
}
}
}
func updateAccountRefreshProgressIndicator() {
let progress = AccountManager.shared.combinedRefreshProgress
if progress.isComplete {
if self.progress != 0 {
finishProgress()
}
} else {
let percent = Float(progress.numberCompleted) / Float(progress.numberOfTasks)
setProgress(percent, animated: true) {}
}
}
}

View File

@@ -718,15 +718,6 @@ class SceneCoordinator: NSObject, UndoableCommandRunner, UnreadCountProvider {
markArticlesWithUndo(articles, statusKey: .read, flag: true)
}
func markAllAsRead() {
let accounts = AccountManager.shared.activeAccounts
var articles = Set<Article>()
accounts.forEach { account in
articles.formUnion(account.fetchArticles(.unread))
}
markAllAsRead(Array(articles))
}
func markAllAsReadInTimeline() {
markAllAsRead(articles)
masterNavigationController.popViewController(animated: true)