feat(keyboard): harden polish/clipboard guards and ship 1.6.6 (build 59)
Keep marketing version at 1.6.6 and bump build to 59. Strengthen never-answer polish safeguards, clipboard reply-intent continuity, voice undo UX, device UITests harness, eval fixtures, and What's New assets.
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
// RecordButtonGesturePolicy.swift
|
||||
// OSGKeyboard · Shared
|
||||
//
|
||||
// Pure tap / hold routing for the mic button. Kept out of the view so the
|
||||
// "one press produces at most one action" invariant is unit-testable: the
|
||||
// clipboard long-press flips the phase while the finger is still down, and
|
||||
// regressions there let a single press both open and close a round.
|
||||
|
||||
import Foundation
|
||||
|
||||
public enum RecordButtonGestureAction: Equatable, Sendable {
|
||||
case none
|
||||
/// Start dictation, cancel a preparing clipboard intent, or stop recording —
|
||||
/// all of which the coordinator resolves from its own phase.
|
||||
case toggle
|
||||
case beginClipboardCommand
|
||||
}
|
||||
|
||||
public enum RecordButtonGesturePolicy {
|
||||
/// Action for a press released before the hold threshold.
|
||||
public static func tapAction(
|
||||
phase: RecordButton.Phase,
|
||||
isEnabled: Bool
|
||||
) -> RecordButtonGestureAction {
|
||||
switch phase {
|
||||
case .idleUnavailable:
|
||||
return .toggle
|
||||
case .idleReady, .error, .preparing, .recording:
|
||||
return isEnabled ? .toggle : .none
|
||||
case .processing:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
/// Action for a press held past the threshold. A `.none` result means the
|
||||
/// hold did not consume the press, so its release still counts as a tap and
|
||||
/// no gesture becomes a dead key.
|
||||
public static func holdAction(
|
||||
phase: RecordButton.Phase,
|
||||
isEnabled: Bool,
|
||||
supportsClipboardLongPress: Bool
|
||||
) -> RecordButtonGestureAction {
|
||||
switch phase {
|
||||
case .idleReady, .idleUnavailable, .error:
|
||||
guard supportsClipboardLongPress else { return .none }
|
||||
guard isEnabled || phase == .idleUnavailable else { return .none }
|
||||
return .beginClipboardCommand
|
||||
case .recording:
|
||||
return isEnabled ? .toggle : .none
|
||||
case .preparing, .processing:
|
||||
return .none
|
||||
}
|
||||
}
|
||||
|
||||
/// A hold that produced an action owns the press; its release must be
|
||||
/// swallowed rather than replayed as a tap.
|
||||
public static func consumesPress(_ action: RecordButtonGestureAction) -> Bool {
|
||||
action != .none
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user