116 lines
3.9 KiB
Swift
116 lines
3.9 KiB
Swift
import Foundation
|
|
import WatchConnectivity
|
|
|
|
extension Notification.Name {
|
|
static let fuelBoardWatchRefreshRequested = Notification.Name("FuelBoardWatchRefreshRequested")
|
|
}
|
|
|
|
@MainActor
|
|
final class WatchSyncManager: NSObject, WCSessionDelegate {
|
|
static let shared = WatchSyncManager()
|
|
|
|
private var pendingSnapshotPush = false
|
|
|
|
private override init() {
|
|
super.init()
|
|
}
|
|
|
|
func activate() {
|
|
guard WCSession.isSupported() else { return }
|
|
pendingSnapshotPush = true
|
|
let session = WCSession.default
|
|
if session.delegate !== self {
|
|
session.delegate = self
|
|
}
|
|
session.activate()
|
|
}
|
|
|
|
func pushSnapshot() {
|
|
guard WCSession.isSupported() else { return }
|
|
let session = WCSession.default
|
|
guard session.activationState == .activated else {
|
|
pendingSnapshotPush = true
|
|
return
|
|
}
|
|
do {
|
|
try session.updateApplicationContext(snapshotContext())
|
|
pendingSnapshotPush = false
|
|
} catch {
|
|
print("WATCH-SYNC push failed: \(error.localizedDescription)")
|
|
}
|
|
}
|
|
|
|
private func snapshotContext() -> [String: Any] {
|
|
var context: [String: Any] = [:]
|
|
|
|
if let favourites = try? JSONEncoder().encode(FuelStore.loadFavourites()) {
|
|
context[FuelStore.favouritesKey] = favourites
|
|
}
|
|
if let stations = try? JSONEncoder().encode(FuelStore.loadStations()) {
|
|
context[FuelStore.stationsKey] = stations
|
|
}
|
|
|
|
context[FuelStore.fuelKey] = FuelStore.loadSelectedFuel().rawValue
|
|
context[FuelStore.distanceUnitKey] = FuelStore.loadDistanceUnit().rawValue
|
|
context[FuelStore.priceDisplayStyleKey] = FuelStore.loadPriceDisplayStyle().rawValue
|
|
|
|
if let lastRefresh = FuelStore.loadLastRefresh() {
|
|
context[FuelStore.lastRefreshKey] = String(lastRefresh.timeIntervalSince1970)
|
|
}
|
|
|
|
if let handled = FuelStore.loadWatchRefreshHandled() {
|
|
context[FuelStore.watchRefreshHandledKey] = String(handled.timeIntervalSince1970)
|
|
}
|
|
|
|
if let location = FuelStore.loadLocationWithDate() {
|
|
context[FuelStore.locationKey] = "\(location.coordinate.lat),\(location.coordinate.lng),\(location.date.timeIntervalSince1970)"
|
|
}
|
|
|
|
return context
|
|
}
|
|
|
|
nonisolated func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: (any Error)?) {
|
|
if let error {
|
|
print("WATCH-SYNC activation failed: \(error.localizedDescription)")
|
|
return
|
|
}
|
|
Task { @MainActor in
|
|
if activationState == .activated, self.pendingSnapshotPush {
|
|
self.pushSnapshot()
|
|
}
|
|
}
|
|
}
|
|
|
|
nonisolated func sessionDidBecomeInactive(_ session: WCSession) {}
|
|
|
|
nonisolated func sessionDidDeactivate(_ session: WCSession) {
|
|
Task { @MainActor in
|
|
WCSession.default.activate()
|
|
}
|
|
}
|
|
|
|
nonisolated func session(_ session: WCSession, didReceiveUserInfo userInfo: [String : Any] = [:]) {
|
|
handleIncomingMessage(userInfo)
|
|
}
|
|
|
|
nonisolated func session(_ session: WCSession, didReceiveMessage message: [String : Any]) {
|
|
handleIncomingMessage(message)
|
|
}
|
|
|
|
private nonisolated func handleIncomingMessage(_ payload: [String: Any]) {
|
|
if payload["fuelboard.snapshotRequest"] as? String != nil {
|
|
Task { @MainActor in
|
|
self.pushSnapshot()
|
|
}
|
|
}
|
|
|
|
guard let raw = payload[FuelStore.watchRefreshRequestKey] as? String,
|
|
let timestamp = TimeInterval(raw) else { return }
|
|
let date = Date(timeIntervalSince1970: timestamp)
|
|
Task { @MainActor in
|
|
FuelStore.requestWatchRefresh(date)
|
|
NotificationCenter.default.post(name: .fuelBoardWatchRefreshRequested, object: nil)
|
|
}
|
|
}
|
|
}
|