fix(macos): preserve voice ear boost expiry (#116196)

This commit is contained in:
Vincent Koc
2026-07-30 11:19:25 +08:00
committed by GitHub
parent 9c6e06b557
commit fa0bced544
2 changed files with 40 additions and 3 deletions
+10 -3
View File
@@ -329,7 +329,7 @@ final class AppState {
didSet { self.ifNotPreview { UserDefaults.standard.set(self.remoteCliPath, forKey: remoteCliPathKey) } }
}
private var earBoostTask: Task<Void, Never>?
@ObservationIgnored private var earBoostTask: Task<Void, Never>?
init(
preview: Bool = false,
@@ -782,13 +782,20 @@ final class AppState {
func triggerVoiceEars(ttl: TimeInterval? = 5) {
self.earBoostTask?.cancel()
self.earBoostTask = nil
self.earBoostActive = true
guard let ttl else { return }
self.earBoostTask = Task { [weak self] in
try? await Task.sleep(nanoseconds: UInt64(ttl * 1_000_000_000))
await MainActor.run { [weak self] in self?.earBoostActive = false }
do {
try await Task.sleep(nanoseconds: UInt64(ttl * 1_000_000_000))
} catch {
return
}
guard !Task.isCancelled, let self else { return }
self.earBoostTask = nil
self.earBoostActive = false
}
}
@@ -0,0 +1,30 @@
import Foundation
import Testing
@testable import OpenClaw
@Suite(.serialized)
@MainActor
struct AppStateVoiceEarsTests {
@Test func `indefinite ear boost survives cancelled expiry`() async throws {
let state = AppState(preview: true)
state.triggerVoiceEars(ttl: 60)
state.triggerVoiceEars(ttl: nil)
try await Task.sleep(for: .milliseconds(20))
#expect(state.earBoostActive)
state.stopVoiceEars()
}
@Test func `replacement expiry owns ear boost lifetime`() async throws {
let state = AppState(preview: true)
state.triggerVoiceEars(ttl: 60)
state.triggerVoiceEars(ttl: 0.05)
try await Task.sleep(for: .milliseconds(20))
#expect(state.earBoostActive)
try await Task.sleep(for: .milliseconds(60))
#expect(!state.earBoostActive)
}
}