Files

39 lines
1.4 KiB
Swift

import Foundation
/// Whether anyone is looking at the app: the phone UI in the foreground, or CarPlay connected.
/// Work that only feeds a screen (stemd polling, a shallow output buffer for snappy faders)
/// checks this, so a locked phone playing music does as little as it can.
enum AppActivity {
private static let lock = UnfairLock()
nonisolated(unsafe) private static var phone = true
nonisolated(unsafe) private static var car = false
nonisolated(unsafe) private static var waiters: [CheckedContinuation<Void, Never>] = []
static var isActive: Bool { lock.with { phone || car } }
static func setPhone(_ on: Bool) { update { phone = on } }
static func setCar(_ on: Bool) { update { car = on } }
private static func update(_ change: () -> Void) {
let ready = lock.with { () -> [CheckedContinuation<Void, Never>] in
change()
guard phone || car else { return [] }
defer { waiters = [] }
return waiters
}
ready.forEach { $0.resume() }
}
/// Returns once the app is active, at once if it already is.
static func untilActive() async {
await withCheckedContinuation { (c: CheckedContinuation<Void, Never>) in
let now = lock.with { () -> Bool in
if phone || car { return true }
waiters.append(c)
return false
}
if now { c.resume() }
}
}
}