iOS/Sources/Shared/API/WatchHelpers.swift

111 lines
3.9 KiB
Swift

import Communicator
import Foundation
import ObjectMapper
import PromiseKit
import RealmSwift
#if os(watchOS)
import ClockKit
import WatchKit
#endif
public enum WatchContext: String, CaseIterable {
case servers
case complications
case ssid = "SSID"
case activeFamilies
case watchModel
case watchVersion
case watchBattery
case watchBatteryState
}
public extension HomeAssistantAPI {
// Be mindful of 262.1kb maximum size for context - https://stackoverflow.com/a/35076706/486182
private static var watchContext: Content {
var content: Content = Communicator.shared.mostRecentlyReceievedContext.content
#if os(iOS)
content[WatchContext.servers.rawValue] = Current.servers.restorableState()
content[WatchContext.complications.rawValue] = Array(Current.realm().objects(WatchComplication.self)).toJSON()
#if targetEnvironment(simulator)
content[WatchContext.ssid.rawValue] = "SimulatorWiFi"
#else
content[WatchContext.ssid.rawValue] = Current.connectivity.currentWiFiSSID()
#endif
#elseif os(watchOS)
let activeFamilies: [String]? = CLKComplicationServer.sharedInstance().activeComplications?.compactMap {
ComplicationGroupMember(family: $0.family).rawValue
}
content[WatchContext.activeFamilies.rawValue] = activeFamilies
content[WatchContext.watchModel.rawValue] = Current.device.systemModel()
content[WatchContext.watchVersion.rawValue] = Current.device.systemVersion()
let currentWatchInterfaceDevice = WKInterfaceDevice.current()
currentWatchInterfaceDevice.isBatteryMonitoringEnabled = true
content[WatchContext.watchBattery.rawValue] = currentWatchInterfaceDevice.batteryLevel
content[WatchContext.watchBatteryState.rawValue] = currentWatchInterfaceDevice.batteryState.rawValue
#endif
return content
}
static func SyncWatchContext() -> NSError? {
#if os(iOS)
guard case .paired(.installed) = Communicator.shared.currentWatchState else {
Current.Log.warning("Tried to sync HAAPI config to watch but watch not paired or app not installed")
return nil
}
#endif
let context = Context(content: HomeAssistantAPI.watchContext)
do {
try Communicator.shared.sync(context)
Current.Log.info("updated context")
} catch let error as NSError {
Current.Log.error("Updating the context failed: \(error)")
return error
}
return nil
}
func updateComplications(passively: Bool) -> Promise<Void> {
#if os(iOS)
guard case .paired = Communicator.shared.currentWatchState else {
Current.Log.verbose("skipping complication updates; no paired watch")
return .value(())
}
#endif
let complications = Set(
Current.realm().objects(WatchComplication.self)
.filter("serverIdentifier = %@", server.identifier.rawValue)
)
guard let request = WebhookResponseUpdateComplications.request(for: complications) else {
Current.Log.verbose("no complications need templates rendered")
#if os(iOS)
// in case the user deleted the last complication, sync that fact up to the watch
_ = HomeAssistantAPI.SyncWatchContext()
#else
// in case the user updated just the complication's metadata, force a refresh
WebhookResponseUpdateComplications.updateComplications()
#endif
return .value(())
}
if passively {
return Current.webhooks.sendPassive(identifier: .updateComplications, server: server, request: request)
} else {
return Current.webhooks.send(identifier: .updateComplications, server: server, request: request)
}
}
}