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>
This commit is contained in:
Cursor Agent
2026-07-26 10:34:52 +00:00
parent e6f99d2744
commit 70ba3a4359
18 changed files with 801 additions and 36 deletions
+18 -1
View File
@@ -237,7 +237,22 @@ public final class ProviderConfig: ObservableObject, @unchecked Sendable {
}
}
/// Idle window before an active Flow session expires; resets on each utterance.
/// PiP vs Live Activity keep-alive (mutually exclusive).
@Published public var flowKeepAliveMode: FlowKeepAliveMode {
didSet {
guard !isApplyingConfiguration, flowKeepAliveMode != configuration.flowKeepAliveMode else { return }
configuration.flowKeepAliveMode = flowKeepAliveMode
if flowKeepAliveMode == .pictureInPicture {
configuration.flowSkipAppSwitch = true
if flowSkipAppSwitch != true {
flowSkipAppSwitch = true
}
}
persistConfiguration()
}
}
/// Idle window before an active Flow session expires; Live Activity mode only.
@Published public var flowInactivityDuration: FlowInactivityDuration {
didSet {
guard !isApplyingConfiguration,
@@ -347,6 +362,7 @@ public final class ProviderConfig: ObservableObject, @unchecked Sendable {
polishIntensity = configuration.polishIntensity
llmThinkingEnabled = configuration.llmThinkingEnabled
flowSkipAppSwitch = configuration.flowSkipAppSwitch
flowKeepAliveMode = configuration.flowKeepAliveMode
flowInactivityDuration = configuration.flowInactivityDuration
localASRCustomLanguageModelEnabled = configuration.localASRCustomLanguageModelEnabled
isSyncingProviderAPIKey = true
@@ -433,6 +449,7 @@ public final class ProviderConfig: ObservableObject, @unchecked Sendable {
polishIntensity = fresh.polishIntensity
llmThinkingEnabled = fresh.llmThinkingEnabled
flowSkipAppSwitch = fresh.flowSkipAppSwitch
flowKeepAliveMode = fresh.flowKeepAliveMode
flowInactivityDuration = fresh.flowInactivityDuration
localASRCustomLanguageModelEnabled = fresh.localASRCustomLanguageModelEnabled
isSyncingProviderAPIKey = true