2bc8c1b87d
Adapt typing/voice surfaces for iPad width and height, add the system globe key and last-input editing flow, harden host-only Rime deployment, and remove clipboard voice commands. Bump build to 61.
54 lines
1.7 KiB
Swift
54 lines
1.7 KiB
Swift
// KeyboardSurfaceRoot.swift
|
|
// OSGKeyboard · Keyboard Extension
|
|
//
|
|
// Switches between voice and typing surfaces driven by KeyboardState.surface.
|
|
|
|
import SwiftUI
|
|
import OSGKeyboardShared
|
|
|
|
struct KeyboardSurfaceRoot: View {
|
|
@ObservedObject var state: KeyboardState
|
|
@ObservedObject var typing: TypingSessionController
|
|
|
|
var onInsert: (String) -> Void
|
|
var onDeleteBackward: () -> Void
|
|
|
|
/// Height is deliberately independent of the surface: the voice surface
|
|
/// adopts the typing surface's content-driven height and parks the surplus
|
|
/// above its action cluster, so switching surfaces never resizes the
|
|
/// keyboard. Keeping this a single expression is what guarantees it.
|
|
static func height(
|
|
for surface: KeyboardState.Surface,
|
|
isIPad: Bool = false,
|
|
width: CGFloat = 0
|
|
) -> CGFloat {
|
|
TypingSurfaceMetrics.contentHeight(isIPad: isIPad, width: width)
|
|
}
|
|
|
|
var body: some View {
|
|
Group {
|
|
switch state.surface {
|
|
case .voice:
|
|
KeyboardRootView(
|
|
state: state,
|
|
typing: typing,
|
|
onInsert: onInsert
|
|
)
|
|
case .typing:
|
|
TypingRootView(
|
|
state: state,
|
|
typing: typing,
|
|
onInsert: onInsert,
|
|
onDeleteBackward: onDeleteBackward
|
|
)
|
|
}
|
|
}
|
|
.animation(.easeInOut(duration: 0.15), value: state.surface)
|
|
.onChange(of: state.surface) { _, newSurface in
|
|
if newSurface == .voice {
|
|
typing.leaveTypingMode()
|
|
}
|
|
}
|
|
}
|
|
}
|