fix: unify location report state
This commit is contained in:
@ -8,6 +8,8 @@ import Foundation
|
||||
/// 首页在线状态与 2 小时倒计时存储,对齐 Android `LocationStateRepository`。
|
||||
final class HomeLocationStateStore {
|
||||
|
||||
static let shared = HomeLocationStateStore(store: .shared)
|
||||
|
||||
static let onlineDurationMillis: Int64 = 2 * 60 * 60 * 1000
|
||||
|
||||
private(set) var isOnline = false
|
||||
@ -15,11 +17,10 @@ final class HomeLocationStateStore {
|
||||
private(set) var nextReportCountdownSeconds: Int64 = 0
|
||||
private(set) var reminderMinutes = 0
|
||||
|
||||
var onStateChange: (() -> Void)?
|
||||
|
||||
private let store: AppStore
|
||||
private var countdownTask: Task<Void, Never>?
|
||||
private var anchorTimestamp: Int64?
|
||||
private var observers: [ObjectIdentifier: StateObserver] = [:]
|
||||
|
||||
init(store: AppStore = .shared) {
|
||||
self.store = store
|
||||
@ -27,11 +28,38 @@ final class HomeLocationStateStore {
|
||||
isOnline = store.onlineStatus
|
||||
}
|
||||
|
||||
deinit {
|
||||
countdownTask?.cancel()
|
||||
}
|
||||
|
||||
/// 监听状态变化,允许首页与独立位置上报页同时刷新。
|
||||
func observe(_ owner: AnyObject, handler: @escaping () -> Void) {
|
||||
observers[ObjectIdentifier(owner)] = StateObserver(owner: owner, handler: handler)
|
||||
}
|
||||
|
||||
/// 移除指定监听者。
|
||||
func removeObserver(_ owner: AnyObject) {
|
||||
observers.removeValue(forKey: ObjectIdentifier(owner))
|
||||
}
|
||||
|
||||
/// 启动时恢复在线倒计时。
|
||||
func restoreStateIfNeeded() {
|
||||
guard store.onlineStatus else { return }
|
||||
reminderMinutes = store.locationReminderMinutes
|
||||
guard store.onlineStatus else {
|
||||
isOnline = false
|
||||
stopCountdown()
|
||||
notifyChange()
|
||||
return
|
||||
}
|
||||
let lastTime = store.lastLocationReportTime
|
||||
guard lastTime > 0 else { return }
|
||||
guard lastTime > 0 else {
|
||||
isOnline = false
|
||||
store.onlineStatus = false
|
||||
store.clearLastLocationReportTime()
|
||||
stopCountdown()
|
||||
notifyChange()
|
||||
return
|
||||
}
|
||||
|
||||
let now = Int64(Date().timeIntervalSince1970 * 1000)
|
||||
let elapsed = now - lastTime
|
||||
@ -147,6 +175,17 @@ final class HomeLocationStateStore {
|
||||
}
|
||||
|
||||
private func notifyChange() {
|
||||
onStateChange?()
|
||||
observers = observers.filter { $0.value.owner != nil }
|
||||
observers.values.forEach { $0.handler() }
|
||||
}
|
||||
}
|
||||
|
||||
private final class StateObserver {
|
||||
weak var owner: AnyObject?
|
||||
let handler: () -> Void
|
||||
|
||||
init(owner: AnyObject, handler: @escaping () -> Void) {
|
||||
self.owner = owner
|
||||
self.handler = handler
|
||||
}
|
||||
}
|
||||
|
||||
@ -37,7 +37,7 @@ final class HomeViewModel {
|
||||
|
||||
init(
|
||||
appStore: AppStore = .shared,
|
||||
locationStateStore: HomeLocationStateStore = HomeLocationStateStore(),
|
||||
locationStateStore: HomeLocationStateStore = .shared,
|
||||
commonMenuStore: HomeCommonMenuStore = HomeCommonMenuStore(),
|
||||
locationProvider: any LocationProviding = LocationProvider.shared
|
||||
) {
|
||||
@ -50,11 +50,15 @@ final class HomeViewModel {
|
||||
locationProvider: locationProvider
|
||||
)
|
||||
self.commonMenuStore = commonMenuStore
|
||||
self.locationStateStore.onStateChange = { [weak self] in
|
||||
self.locationStateStore.observe(self) { [weak self] in
|
||||
self?.notifyStateChange()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
locationStateStore.removeObserver(self)
|
||||
}
|
||||
|
||||
var isOnline: Bool { locationStateStore.isOnline }
|
||||
var countdownDisplayText: String { locationStateStore.countdownDisplayText }
|
||||
var reminderMinutes: Int { locationStateStore.reminderMinutes }
|
||||
@ -73,6 +77,7 @@ final class HomeViewModel {
|
||||
|
||||
/// 按需重新拉取权限。
|
||||
func reloadIfNeeded(api: HomeAPI) async {
|
||||
locationStateStore.restoreStateIfNeeded()
|
||||
guard needsPermissionReload else {
|
||||
refreshLocalDisplayState()
|
||||
rebuildCommonMenus()
|
||||
|
||||
@ -29,7 +29,7 @@ final class LocationReportViewModel {
|
||||
private let locationProvider: any LocationProviding
|
||||
|
||||
init(
|
||||
locationStateStore: HomeLocationStateStore = HomeLocationStateStore(),
|
||||
locationStateStore: HomeLocationStateStore = .shared,
|
||||
locationProvider: any LocationProviding = LocationProvider.shared
|
||||
) {
|
||||
self.locationStateStore = locationStateStore
|
||||
@ -38,11 +38,15 @@ final class LocationReportViewModel {
|
||||
locationStateStore: locationStateStore,
|
||||
locationProvider: locationProvider
|
||||
)
|
||||
self.locationStateStore.onStateChange = { [weak self] in
|
||||
self.locationStateStore.observe(self) { [weak self] in
|
||||
self?.notifyStateChange()
|
||||
}
|
||||
}
|
||||
|
||||
deinit {
|
||||
locationStateStore.removeObserver(self)
|
||||
}
|
||||
|
||||
var isOnline: Bool { locationStateStore.isOnline }
|
||||
var countdownDisplayText: String { locationStateStore.countdownDisplayTextSingleHour }
|
||||
var reminderMinutes: Int { locationStateStore.reminderMinutes }
|
||||
|
||||
Reference in New Issue
Block a user