mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-02 12:07:55 +00:00
ed58120fd3
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.
97 lines
3.2 KiB
Swift
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
|
|
}
|
|
}
|