Files
Mauro Romito ed58120fd3 Associate the room address field helper text and error with the field
The address field already had an accessibility label, but the section's
helper text and validation error were only shown in a separate footer and
weren't conveyed to VoiceOver when focusing the field. Compose them into the
field's accessibility hint.

Addresses #5258.
2026-06-23 13:06:36 +02:00

97 lines
3.2 KiB
Swift

//
// Copyright 2025 Element Creations Ltd.
// Copyright 2024-2025 New Vector Ltd.
//
// SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial.
// Please see LICENSE in the repository root for full details.
//
import Compound
import SwiftUI
struct EditRoomAddressListRow: View {
@Binding var aliasLocalPart: String
var serverName: String
/// The error to display, if any. Also associated with the field for VoiceOver.
var errorDescription: String?
/// The section's helper text, associated with the field for VoiceOver.
var footerText: String?
private var fullAddress: String {
"#\(aliasLocalPart):\(serverName)"
}
/// Associates the helper text and any error with the field, as they're otherwise
/// only shown in a separate section footer.
private var accessibilityHint: String {
[L10n.a11yEditRoomAddressHint(fullAddress), footerText, errorDescription]
.compactMap { $0 }
.joined(separator: "\n")
}
var body: some View {
ListRow(kind: .custom {
HStack(spacing: 0) {
Text("#")
.font(.compound.bodyLG)
.foregroundStyle(.compound.textSecondary)
.accessibilityHidden(true)
TextField("", text: $aliasLocalPart)
.textInputAutocapitalization(.never)
.autocorrectionDisabled()
.textContentType(.URL)
.tint(.compound.iconAccentTertiary)
.font(.compound.bodyLG)
.foregroundStyle(.compound.textPrimary)
.padding(.horizontal, 8)
.accessibilityLabel(L10n.a11yAddress)
.accessibilityHint(accessibilityHint)
Text(":\(serverName)")
.font(.compound.bodyLG)
.foregroundStyle(.compound.textSecondary)
.accessibilityHidden(true)
}
.padding(ListRowPadding.textFieldInsets)
.environment(\.layoutDirection, .leftToRight)
.errorBackground(errorDescription != nil)
})
}
}
private extension View {
@ViewBuilder
private var shape: some View {
if #available(iOS 26, *) {
Capsule()
.inset(by: 1)
.fill(.compound.bgCriticalSubtleHovered)
.stroke(Color.compound.borderCriticalPrimary)
} else {
RoundedRectangle(cornerRadius: 10)
.inset(by: 1)
.fill(.compound.bgCriticalSubtleHovered)
.stroke(Color.compound.borderCriticalPrimary)
}
}
func errorBackground(_ shouldDisplay: Bool) -> some View {
listRowBackground(shouldDisplay ? AnyView(shape) : AnyView(Color.compound.bgCanvasDefaultLevel1))
}
}
enum EditRoomAddressErrorState {
case alreadyExists
case invalidSymbols
}
extension Set<EditRoomAddressErrorState> {
var errorDescription: String? {
if contains(.alreadyExists) {
return L10n.errorRoomAddressAlreadyExists
} else if contains(.invalidSymbols) {
return L10n.errorRoomAddressInvalidSymbols
}
return nil
}
}