Accessibility bug fixes (#1348)

* Fix bug affecting accessibillityRepresentation of type Toggle

Previously, the action on the button would not get executed. This is a SwiftUI bug, as views passed into `accessibilityRepresentation` should not have any behaviour.

Now, we set an equivalent `accessibilityValue` on|off to emulate the same functionality.

* Remove conditional ViewModifier in favour of inlined modifier

Since this view is part of the `StatusRowView` it’s better to err on the side of less branching with ModifiedContent<>

* Avoid combining StatusRowMediaPreviewView accessibility children

By combining the elements, the end result was that the intended action (opening QuickLook) was swallowed in favour of displaying the alt text alert of images.
This commit is contained in:
Chris Kolbu 2023-04-03 19:14:44 +10:00 committed by GitHub
parent db81486f14
commit f728ea652e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 53 additions and 24 deletions

View File

@ -517,6 +517,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Далучыць фота";
"accessibility.editor.button.poll" = "Апытанне";
"accessibility.editor.button.spoiler" = "Папярэджанне пра спойлер";

View File

@ -511,6 +511,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Attach photo";
"accessibility.editor.button.poll" = "Poll";
"accessibility.editor.button.spoiler" = "Spoiler warning";

View File

@ -500,6 +500,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Foto anhängen";
"accessibility.editor.button.poll" = "Umfrage";
"accessibility.editor.button.spoiler" = "Inhaltswarnung";

View File

@ -512,6 +512,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Attach photo";
"accessibility.editor.button.poll" = "Poll";
"accessibility.editor.button.spoiler" = "Spoiler warning";

View File

@ -513,6 +513,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Attach photo";
"accessibility.editor.button.poll" = "Poll";
"accessibility.editor.button.spoiler" = "Spoiler warning";

View File

@ -513,6 +513,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Añadir foto";
"accessibility.editor.button.poll" = "Encuesta";
"accessibility.editor.button.spoiler" = "Advertencia";

View File

@ -501,6 +501,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Erantsi irudia";
"accessibility.editor.button.poll" = "Bozketa";
"accessibility.editor.button.spoiler" = "Edukiari buruzko oharra";

View File

@ -508,6 +508,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Attacher la photo";
"accessibility.editor.button.poll" = "Sondage";
"accessibility.editor.button.spoiler" = "Alerte spoiler";

View File

@ -512,6 +512,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Allega foto";
"accessibility.editor.button.poll" = "Sondaggio";
"accessibility.editor.button.spoiler" = "Avviso di Spoiler";

View File

@ -512,6 +512,8 @@
"filter.expiry-%@" = "有効期限: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "画像を添付";
"accessibility.editor.button.poll" = "投票";
"accessibility.editor.button.spoiler" = "ネタバレを警告";

View File

@ -514,6 +514,8 @@
"filter.expiry-%@" = "%@까지 가림";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "미디어 첨부";
"accessibility.editor.button.poll" = "투표";
"accessibility.editor.button.spoiler" = "열람 주의 문구";

View File

@ -512,6 +512,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Attach photo";
"accessibility.editor.button.poll" = "Poll";
"accessibility.editor.button.spoiler" = "Spoiler warning";

View File

@ -509,6 +509,8 @@
"enum.expand-media.hide-sensitive" = "Verberg gevoelige";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Voeg foto toe";
"accessibility.editor.button.poll" = "Poll";
"accessibility.editor.button.spoiler" = "Spoilerwaarschuwing";

View File

@ -503,6 +503,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Dołącz zdjęcie";
"accessibility.editor.button.poll" = "Sondaż";
"accessibility.editor.button.spoiler" = "Ostrzeżenie o spoilerze";

View File

@ -512,6 +512,8 @@
"filter.expiry-%@" = "Expiração: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Anexar foto";
"accessibility.editor.button.poll" = "Enquete";
"accessibility.editor.button.spoiler" = "Aviso de spoiler";

View File

@ -512,6 +512,8 @@
"enum.expand-media.hide-sensitive" = "Hide Sensitive";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Attach photo";
"accessibility.editor.button.poll" = "Poll";
"accessibility.editor.button.spoiler" = "Spoiler warning";

View File

@ -513,6 +513,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "Додати світлину";
"accessibility.editor.button.poll" = "Опитування";
"accessibility.editor.button.spoiler" = "Увага! Спойлер.";

View File

@ -514,6 +514,8 @@
"enum.expand-media.hide-sensitive" = "隐藏敏感内容";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "添加图片";
"accessibility.editor.button.poll" = "投票";
"accessibility.editor.button.spoiler" = "剧透警告";

View File

@ -513,6 +513,8 @@
"filter.expiry-%@" = "Expiry: %@";
// MARK: Accessibility
"accessibility.general.toggle.on" = "On";
"accessibility.general.toggle.off" = "Off";
"accessibility.editor.button.attach-photo" = "附上相片";
"accessibility.editor.button.poll" = "投票";
"accessibility.editor.button.spoiler" = "劇透警告";

View File

@ -97,9 +97,8 @@ public struct FollowButton: View {
Text("account.follow.requested")
} else {
Text(viewModel.relationship.following ? "account.follow.following" : "account.follow.follow")
.accessibilityRepresentation {
Toggle("account.follow.following", isOn: .constant(viewModel.relationship.following))
}
.accessibilityLabel("account.follow.following")
.accessibilityValue(viewModel.relationship.following ? "accessibility.general.toggle.on" : "accessibility.general.toggle.off")
}
}
if viewModel.relationship.following,
@ -112,18 +111,18 @@ public struct FollowButton: View {
}
} label: {
Image(systemName: viewModel.relationship.notifying ? "bell.fill" : "bell")
}.accessibilityRepresentation {
Toggle("accessibility.tabs.profile.user-notifications.label", isOn: .constant(viewModel.relationship.notifying))
}
.accessibilityLabel("accessibility.tabs.profile.user-notifications.label")
.accessibilityValue(viewModel.relationship.notifying ? "accessibility.general.toggle.on" : "accessibility.general.toggle.off")
Button {
Task {
await viewModel.toggleReboosts()
}
} label: {
Image(viewModel.relationship.showingReblogs ? "Rocket.Fill" : "Rocket")
}.accessibilityRepresentation {
Toggle("accessibility.tabs.profile.user-reblogs.label", isOn: .constant(viewModel.relationship.showingReblogs))
}
.accessibilityLabel("accessibility.tabs.profile.user-reblogs.label")
.accessibilityValue(viewModel.relationship.showingReblogs ? "accessibility.general.toggle.on" : "accessibility.general.toggle.off")
}
}
}

View File

@ -90,8 +90,8 @@ public struct StatusRowMediaPreviewView: View {
await quickLook.prepareFor(urls: attachments.compactMap { $0.url }, selectedURL: attachment.url!)
}
}
.accessibilityElement(children: .combine)
.modifier(ConditionalAccessibilityLabelAltTextModifier(attachment: attachment))
.accessibilityElement(children: .ignore)
.accessibilityLabel(Self.accessibilityLabel(for: attachment))
.accessibilityAddTraits([.isButton, .isImage])
} else {
if isCompact || theme.statusDisplayStyle == .compact {
@ -254,7 +254,6 @@ public struct StatusRowMediaPreviewView: View {
.cornerRadius(4)
}
}
.accessibilityAddTraits(.isImage)
case .gifv, .video, .audio:
if let url = attachment.url {
VideoPlayerView(viewModel: .init(url: url))
@ -274,9 +273,9 @@ public struct StatusRowMediaPreviewView: View {
await quickLook.prepareFor(urls: attachments.compactMap { $0.url }, selectedURL: attachment.url!)
}
}
.accessibilityElement(children: .combine)
.modifier(ConditionalAccessibilityLabelAltTextModifier(attachment: attachment))
.accessibilityAddTraits(.isButton)
.accessibilityElement(children: .ignore)
.accessibilityLabel(Self.accessibilityLabel(for: attachment))
.accessibilityAddTraits(attachment.supportedType == .image ? [.isImage, .isButton] : .isButton)
}
}
@ -335,21 +334,14 @@ public struct StatusRowMediaPreviewView: View {
Spacer()
}
}
}
/// A ``ViewModifier`` that creates a suitable accessibility label for an image that may or may not have alt text
private struct ConditionalAccessibilityLabelAltTextModifier: ViewModifier {
let attachment: MediaAttachment
func body(content: Content) -> some View {
private static func accessibilityLabel(for attachment: MediaAttachment) -> Text {
if let altText = attachment.description {
content
.accessibilityLabel("accessibility.image.alt-text-\(altText)")
return Text("accessibility.image.alt-text-\(altText)")
} else if let typeDescription = attachment.localizedTypeDescription {
content
.accessibilityLabel(typeDescription)
return Text(typeDescription)
} else {
content
return Text("accessibility.tabs.profile.picker.media")
}
}
}