NetNewsWire/iOS/Feeds/RefreshProgressView.swift
2024-02-26 08:37:15 -08:00

135 lines
3.8 KiB
Swift

//
// 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!
override func awakeFromNib() {
NotificationCenter.default.addObserver(self, selector: #selector(progressDidChange(_:)), name: .AccountRefreshProgressDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(contentSizeCategoryDidChange(_:)), name: UIContentSizeCategory.didChangeNotification, object: nil)
update()
scheduleUpdateRefreshLabel()
isAccessibilityElement = true
accessibilityTraits = [.updatesFrequently, .notEnabled]
}
func update() {
if !AccountManager.shared.combinedRefreshProgress.isComplete {
progressChanged(animated: false)
} else {
updateRefreshLabel()
}
}
override func didMoveToSuperview() {
progressChanged(animated: false)
}
@objc func progressDidChange(_ note: Notification) {
progressChanged(animated: true)
}
@objc func contentSizeCategoryDidChange(_ note: Notification) {
// This hack is probably necessary because custom views in the toolbar don't get
// notifications that the content size changed.
label.font = UIFont.preferredFont(forTextStyle: .footnote)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
}
// MARK: Private
private extension RefreshProgressView {
func progressChanged(animated: Bool) {
// Layout may crash if not in the view hierarchy.
// https://github.com/Ranchero-Software/NetNewsWire/issues/1764
let isInViewHierarchy = self.superview != nil
let progress = AccountManager.shared.combinedRefreshProgress
if progress.isComplete {
if isInViewHierarchy {
progressView.setProgress(1, animated: animated)
}
func completeLabel() {
// Check that there are no pending downloads.
if AccountManager.shared.combinedRefreshProgress.isComplete {
self.updateRefreshLabel()
self.label.isHidden = false
self.progressView.isHidden = true
if self.superview != nil {
self.progressView.setProgress(0, animated: animated)
}
}
}
if animated {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
completeLabel()
}
} else {
completeLabel()
}
} else {
label.isHidden = true
progressView.isHidden = false
if isInViewHierarchy {
let percent = Float(progress.numberCompleted) / Float(progress.numberOfTasks)
// Don't let the progress bar go backwards unless we need to go back more than 25%
if percent > progressView.progress || progressView.progress - percent > 0.25 {
progressView.setProgress(percent, animated: animated)
}
}
}
}
func updateRefreshLabel() {
if let accountLastArticleFetchEndTime = AccountManager.shared.lastArticleFetchEndTime {
if Date() > accountLastArticleFetchEndTime.addingTimeInterval(60) {
let relativeDateTimeFormatter = RelativeDateTimeFormatter()
relativeDateTimeFormatter.dateTimeStyle = .named
let refreshed = relativeDateTimeFormatter.localizedString(for: accountLastArticleFetchEndTime, relativeTo: Date())
let localizedRefreshText = NSLocalizedString("Updated %@", comment: "Updated")
let refreshText = NSString.localizedStringWithFormat(localizedRefreshText as NSString, refreshed) as String
label.text = refreshText
} else {
label.text = NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
}
} else {
label.text = ""
}
accessibilityLabel = label.text
}
func scheduleUpdateRefreshLabel() {
DispatchQueue.main.asyncAfter(deadline: .now() + 60) { [weak self] in
self?.updateRefreshLabel()
self?.scheduleUpdateRefreshLabel()
}
}
}