Files
OSGKeyboard/OSGKeyboardShared/Services/FlowSessionPolicy.swift
T
Cursor Agent 70ba3a4359 feat(flow): add Picture in Picture keep-alive mode
- Add FlowKeepAliveMode (Dynamic Island vs PiP) with iCloud sync
- Settings: keep-alive picker; inactivity timeout only for Live Activity
- PiP: waveform sample-buffer controller, mic released between utterances
- PiP sessions have no idle expiry; user closing PiP ends the session
- FlowSessionManager branches hostReady, session start, and utterance paths
- UIBackgroundModes picture-in-picture; bilingual strings and tests

Co-authored-by: Rocky <hkgood@users.noreply.github.com>
2026-07-26 10:34:52 +00:00

52 lines
1.9 KiB
Swift

// FlowSessionPolicy.swift
// OSGKeyboard · Shared
//
// Reads Flow session behaviour preferences from the App Group.
import Foundation
public enum FlowSessionPolicy {
public static func skipAppSwitch(defaults: UserDefaults? = nil) -> Bool {
let store = resolvedDefaults(defaults)
if store.object(forKey: AppGroupConfiguration.Keys.flowSkipAppSwitch) == nil {
return true
}
return store.bool(forKey: AppGroupConfiguration.Keys.flowSkipAppSwitch)
}
public static func inactivityDuration(defaults: UserDefaults? = nil) -> FlowInactivityDuration {
let store = resolvedDefaults(defaults)
return FlowInactivityDuration.fromStored(
store.string(forKey: AppGroupConfiguration.Keys.flowInactivityDuration)
)
}
public static func sessionDuration(defaults: UserDefaults? = nil) -> TimeInterval {
inactivityDuration(defaults: defaults).timeInterval
}
public static func keepAliveMode(defaults: UserDefaults? = nil) -> FlowKeepAliveMode {
let store = resolvedDefaults(defaults)
return FlowKeepAliveMode.fromStored(
store.string(forKey: AppGroupConfiguration.Keys.flowKeepAliveMode)
)
}
/// PiP sessions have no inactivity expiry; only the Live Activity path times out.
public static func usesInactivityExpiry(defaults: UserDefaults? = nil) -> Bool {
keepAliveMode(defaults: defaults) == .liveActivity
}
private static func resolvedDefaults(_ defaults: UserDefaults?) -> UserDefaults {
if let defaults { return defaults }
guard let available = AppGroup.defaultsIfAvailable else {
#if DEBUG
fatalError("App Group unavailable — inject UserDefaults in tests.")
#else
fatalError("App Group unavailable.")
#endif
}
return available
}
}