102 lines
2.9 KiB
Swift
102 lines
2.9 KiB
Swift
|
//
|
||
|
// RefreshProgressModel.swift
|
||
|
// NetNewsWire
|
||
|
//
|
||
|
// Created by Phil Viso on 7/2/20.
|
||
|
// Copyright © 2020 Ranchero Software. All rights reserved.
|
||
|
//
|
||
|
|
||
|
import Account
|
||
|
import Combine
|
||
|
import Foundation
|
||
|
import SwiftUI
|
||
|
|
||
|
class RefreshProgressModel: ObservableObject {
|
||
|
|
||
|
enum State {
|
||
|
case refreshProgress(Float)
|
||
|
case lastRefreshDateText(String)
|
||
|
case none
|
||
|
}
|
||
|
|
||
|
@Published var state = State.none
|
||
|
|
||
|
private static var dateFormatter: RelativeDateTimeFormatter = {
|
||
|
let formatter = RelativeDateTimeFormatter()
|
||
|
formatter.dateTimeStyle = .named
|
||
|
|
||
|
return formatter
|
||
|
}()
|
||
|
|
||
|
private let lastRefreshDate: () -> Date?
|
||
|
private let combinedRefreshProgress: () -> CombinedRefreshProgress
|
||
|
|
||
|
private static let lastRefreshDateTextUpdateInterval = 60
|
||
|
private static let lastRefreshDateTextRelativeDateFormattingThreshold = 60.0
|
||
|
|
||
|
init(lastRefreshDateProvider: @escaping () -> Date?,
|
||
|
combinedRefreshProgressProvider: @escaping () -> CombinedRefreshProgress) {
|
||
|
self.lastRefreshDate = lastRefreshDateProvider
|
||
|
self.combinedRefreshProgress = combinedRefreshProgressProvider
|
||
|
|
||
|
updateState()
|
||
|
|
||
|
observeRefreshProgress()
|
||
|
scheduleLastRefreshDateTextUpdate()
|
||
|
}
|
||
|
|
||
|
// MARK: Observing account changes
|
||
|
|
||
|
private func observeRefreshProgress() {
|
||
|
NotificationCenter.default.addObserver(self, selector: #selector(updateState), name: .AccountRefreshProgressDidChange, object: nil)
|
||
|
}
|
||
|
|
||
|
// MARK: Refreshing state
|
||
|
|
||
|
@objc private func updateState() {
|
||
|
let progress = combinedRefreshProgress()
|
||
|
|
||
|
if !progress.isComplete {
|
||
|
let fractionCompleted = Float(progress.numberCompleted) / Float(progress.numberOfTasks)
|
||
|
self.state = .refreshProgress(fractionCompleted)
|
||
|
} else if let lastRefreshDate = self.lastRefreshDate() {
|
||
|
let text = localizedLastRefreshText(lastRefreshDate: lastRefreshDate)
|
||
|
self.state = .lastRefreshDateText(text)
|
||
|
} else {
|
||
|
self.state = .none
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private func scheduleLastRefreshDateTextUpdate() {
|
||
|
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(Self.lastRefreshDateTextUpdateInterval)) {
|
||
|
self.updateState()
|
||
|
self.scheduleLastRefreshDateTextUpdate()
|
||
|
}
|
||
|
}
|
||
|
|
||
|
private func localizedLastRefreshText(lastRefreshDate: Date) -> String {
|
||
|
let now = Date()
|
||
|
|
||
|
if now > lastRefreshDate.addingTimeInterval(Self.lastRefreshDateTextRelativeDateFormattingThreshold) {
|
||
|
let localizedDate = Self.dateFormatter.localizedString(for: lastRefreshDate, relativeTo: now)
|
||
|
let formatString = NSLocalizedString("Updated %@", comment: "Updated") as NSString
|
||
|
|
||
|
return NSString.localizedStringWithFormat(formatString, localizedDate) as String
|
||
|
} else {
|
||
|
return NSLocalizedString("Updated Just Now", comment: "Updated Just Now")
|
||
|
}
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
extension RefreshProgressModel {
|
||
|
|
||
|
convenience init() {
|
||
|
self.init(
|
||
|
lastRefreshDateProvider: { AccountManager.shared.lastArticleFetchEndTime },
|
||
|
combinedRefreshProgressProvider: { AccountManager.shared.combinedRefreshProgress }
|
||
|
)
|
||
|
}
|
||
|
|
||
|
}
|