fix(apple/tvOS): system fullscreen keyboard for all text entry — no inline fields
ci / rust (push) Has been cancelled
ci / rust (push) Has been cancelled
SwiftUI's inline TextField on tvOS is structurally wrong for television: it grows when activated, shows a full-width editing surface behind the pill, and floats labels off-center — none of it stylable into the Settings-app look. Per Apple's tvOS text input guidance, real tvOS apps never edit inline: a field is a value ROW, and pressing it raises the SYSTEM fullscreen keyboard. - TVTextEntry (UIViewControllerRepresentable): a UITextField that becomesFirstResponder on appear, presenting the standard tvOS fullscreen keyboard with the field's prompt; done/dismiss commits the text. TVFieldRow is the Settings-style label+value lozenge. - Add Host and PIN pairing on tvOS now use rows + keyboard covers exclusively (the port row also fixes the off-center value text for good — it's a Text, not a field); the port input validates 1...65535. - No SwiftUI TextField remains in any tvOS code path. Verified by screenshot: the dialog rows render exactly like the Settings app, and the address row raises the system linear keyboard with prompt + done. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -33,6 +33,13 @@ struct PairSheet: View {
|
||||
@State private var busy = false
|
||||
@State private var errorText: String?
|
||||
@State private var token = CeremonyToken()
|
||||
#if os(tvOS)
|
||||
private enum EditField: String, Identifiable {
|
||||
case pin, clientName
|
||||
var id: String { rawValue }
|
||||
}
|
||||
@State private var editing: EditField?
|
||||
#endif
|
||||
|
||||
var body: some View {
|
||||
#if os(tvOS)
|
||||
@@ -47,12 +54,12 @@ struct PairSheet: View {
|
||||
.font(.callout)
|
||||
.foregroundStyle(.secondary)
|
||||
.multilineTextAlignment(.center)
|
||||
TextField("PIN", text: $pin, prompt: Text("Shown in the host's log"))
|
||||
.labelsHidden()
|
||||
TextField(
|
||||
"Client name", text: $clientName,
|
||||
prompt: Text("How the host lists this device"))
|
||||
.labelsHidden()
|
||||
TVFieldRow(
|
||||
label: "PIN", value: pin, placeholder: "Shown in the host's log"
|
||||
) { editing = .pin }
|
||||
TVFieldRow(
|
||||
label: "Device name", value: clientName, placeholder: "Apple TV"
|
||||
) { editing = .clientName }
|
||||
if let errorText {
|
||||
Text(errorText)
|
||||
.font(.callout)
|
||||
@@ -74,6 +81,23 @@ struct PairSheet: View {
|
||||
.frame(maxWidth: 1000)
|
||||
.padding(60)
|
||||
.onDisappear { token.cancelled = true }
|
||||
.fullScreenCover(item: $editing) { field in
|
||||
switch field {
|
||||
case .pin:
|
||||
TVTextEntry(
|
||||
title: "PIN (shown in the host's log)", text: pin,
|
||||
keyboardType: .numberPad
|
||||
) {
|
||||
pin = $0.trimmingCharacters(in: .whitespaces)
|
||||
editing = nil
|
||||
}
|
||||
case .clientName:
|
||||
TVTextEntry(title: "Device name", text: clientName) {
|
||||
clientName = $0
|
||||
editing = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
VStack(spacing: 0) {
|
||||
Form {
|
||||
|
||||
Reference in New Issue
Block a user