fix(client/apple): the Name field didn't say it was the name either

Same cause as the MAC one, and it deserved the same fix rather than another
one-off: on iOS a TextField's title becomes an accessibility label the moment a
prompt exists and nothing is drawn, so "Optional — e.g. Living Room" was the whole
of what the field said about itself.

The prompt is now built per platform. macOS draws the title as a leading label, so
its prompt only hints at the value; iOS has no label to lean on, so the prompt names
the field too. One string for both leaves you either a Mac panel that says
everything twice — which is what the MAC field started doing in the last commit — or
a phone form of unlabelled boxes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-29 12:06:41 +02:00
co-authored by Claude Opus 5
parent 34a9e32bf8
commit c1d2efe112
@@ -44,6 +44,21 @@ struct AddHostSheet: View {
@State private var editingField: EditField? @State private var editingField: EditField?
#endif #endif
/// A field's placeholder, which is not the same job on both platforms.
///
/// macOS draws a `TextField`'s title as a leading label, so the prompt only has to hint at the
/// VALUE. On iOS that title becomes an accessibility label the moment a prompt exists and
/// nothing is drawn the prompt is the field's entire visible identity, so it has to name the
/// field as well as hint at it. Writing one string for both leaves you a Mac panel that says
/// everything twice or a phone form of unlabelled boxes.
private static func prompt(touch: String, desktop: String) -> Text {
#if os(macOS)
Text(desktop)
#else
Text(touch)
#endif
}
private var isEditing: Bool { existing != nil } private var isEditing: Bool { existing != nil }
private var actionTitle: String { isEditing ? "Save" : "Add Host" } private var actionTitle: String { isEditing ? "Save" : "Add Host" }
private var canSave: Bool { !address.trimmingCharacters(in: .whitespaces).isEmpty } private var canSave: Bool { !address.trimmingCharacters(in: .whitespaces).isEmpty }
@@ -113,16 +128,18 @@ struct AddHostSheet: View {
#else #else
VStack(spacing: 0) { VStack(spacing: 0) {
Form { Form {
TextField("Name", text: $name, prompt: Text("Optional — e.g. Living Room")) TextField(
"Name", text: $name,
prompt: Self.prompt(
touch: "Name (optional, e.g. Living Room)",
desktop: "Optional — e.g. Living Room"))
TextField("Address", text: $address, prompt: Text("IP or hostname")) TextField("Address", text: $address, prompt: Text("IP or hostname"))
TextField("Port", value: $port, format: .number.grouping(.never)) TextField("Port", value: $port, format: .number.grouping(.never))
// The PROMPT is the only thing on show here on iOS (a field's title is its
// accessibility label once a prompt is given), so it has to name the field
// itself "Wake-on-LAN auto-filled when known" read as if that were the
// value being asked for.
TextField( TextField(
"MAC address", text: $mac, "MAC address", text: $mac,
prompt: Text("MAC address (for Wake-on-LAN, optional)")) prompt: Self.prompt(
touch: "MAC address (for Wake-on-LAN, optional)",
desktop: "For Wake-on-LAN, optional"))
.autocorrectionDisabled() .autocorrectionDisabled()
#if os(iOS) #if os(iOS)
.textInputAutocapitalization(.never) .textInputAutocapitalization(.never)