feat(flow): harden host handoff, session UX, and Live Activity brand
- fix(keyboard): drop unusable extensionContext.open; report the real result of UIApplication.open and cancel the start watchdog immediately on failure with clear "open OSGKeyboard" guidance instead of a 30s spin - feat(capture): recover from audio route changes (AirPods/wired headset plug-unplug) and phone-call interruptions by rebuilding the engine/tap against the live hardware format - feat(home): add a "Start" button in the Home footer when a session is inactive and permissions are granted (no-jump manual restart) - feat(hostapps): expand the return whitelist to 46 apps (Signal, Zoom, Instagram, X, Douyin, Zhihu, Bilibili, Things, Firefox, ...) with en/zh-Hans names and synced LSApplicationQueriesSchemes - feat(island): use a "ready" checkmark instead of a mic glyph while idle and set a staleDate so an orphaned Live Activity fades after a force-quit - feat(coldstart): use the template OSG brand mark instead of a system waveform glyph in the cold-start overlay - perf(keyboard): rely on Darwin notifications as the primary session signal and drop the fallback poll from 1s to 3s - fix(keyboard): remove the redundant "Start" text button next to the inactive-session hint on the keyboard - docs: correct the per-take cap to 210s (3.5 min) and document that force-quitting no longer resurrects the session (tracker + READMEs)
This commit is contained in:
@@ -61,12 +61,18 @@ final class KeyboardFlowCoordinator {
|
||||
isPendingFlowStart || isFlowRecording || isAwaitingFlowResult
|
||||
}
|
||||
|
||||
/// Session/transcription changes are pushed in real time by Darwin
|
||||
/// notifications (see `KeyboardConfigSync.installDarwinObservers`), so this
|
||||
/// loop is only a low-frequency safety net for coalesced/dropped Darwin
|
||||
/// signals — hence 3 s rather than 1 Hz to save battery while idle.
|
||||
private static let sessionMonitorIntervalNs: UInt64 = 3_000_000_000
|
||||
|
||||
func startSessionMonitor() {
|
||||
flowSessionMonitorTask?.cancel()
|
||||
flowSessionMonitorTask = Task { @MainActor [weak self] in
|
||||
while !Task.isCancelled {
|
||||
self?.refreshSessionState()
|
||||
try? await Task.sleep(nanoseconds: 1_000_000_000)
|
||||
try? await Task.sleep(nanoseconds: Self.sessionMonitorIntervalNs)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,8 +174,14 @@ final class KeyboardFlowCoordinator {
|
||||
debug("openHostApp path=\(path) success=\(success)")
|
||||
guard !success else { return }
|
||||
|
||||
// The open genuinely failed (iOS blocked it / no Full Access). Don't
|
||||
// let the 30s watchdog spin — cancel the pending start immediately and
|
||||
// guide the user to open OSGKeyboard manually.
|
||||
if path == "startflow", isPendingFlowStart {
|
||||
state.lastTranscript = ExtL10n.string("keyboard.flow.manualOpenHost")
|
||||
isPendingFlowStart = false
|
||||
flowStartDeadline = 0
|
||||
stopFlowWatchdog()
|
||||
showManualOpenHint(path: "startflow")
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user