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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -97,9 +97,8 @@ public struct FollowButton: View {
Text("account.follow.requested") Text("account.follow.requested")
} else { } else {
Text(viewModel.relationship.following ? "account.follow.following" : "account.follow.follow") Text(viewModel.relationship.following ? "account.follow.following" : "account.follow.follow")
.accessibilityRepresentation { .accessibilityLabel("account.follow.following")
Toggle("account.follow.following", isOn: .constant(viewModel.relationship.following)) .accessibilityValue(viewModel.relationship.following ? "accessibility.general.toggle.on" : "accessibility.general.toggle.off")
}
} }
} }
if viewModel.relationship.following, if viewModel.relationship.following,
@ -112,18 +111,18 @@ public struct FollowButton: View {
} }
} label: { } label: {
Image(systemName: viewModel.relationship.notifying ? "bell.fill" : "bell") 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 { Button {
Task { Task {
await viewModel.toggleReboosts() await viewModel.toggleReboosts()
} }
} label: { } label: {
Image(viewModel.relationship.showingReblogs ? "Rocket.Fill" : "Rocket") 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!) await quickLook.prepareFor(urls: attachments.compactMap { $0.url }, selectedURL: attachment.url!)
} }
} }
.accessibilityElement(children: .combine) .accessibilityElement(children: .ignore)
.modifier(ConditionalAccessibilityLabelAltTextModifier(attachment: attachment)) .accessibilityLabel(Self.accessibilityLabel(for: attachment))
.accessibilityAddTraits([.isButton, .isImage]) .accessibilityAddTraits([.isButton, .isImage])
} else { } else {
if isCompact || theme.statusDisplayStyle == .compact { if isCompact || theme.statusDisplayStyle == .compact {
@ -254,7 +254,6 @@ public struct StatusRowMediaPreviewView: View {
.cornerRadius(4) .cornerRadius(4)
} }
} }
.accessibilityAddTraits(.isImage)
case .gifv, .video, .audio: case .gifv, .video, .audio:
if let url = attachment.url { if let url = attachment.url {
VideoPlayerView(viewModel: .init(url: 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!) await quickLook.prepareFor(urls: attachments.compactMap { $0.url }, selectedURL: attachment.url!)
} }
} }
.accessibilityElement(children: .combine) .accessibilityElement(children: .ignore)
.modifier(ConditionalAccessibilityLabelAltTextModifier(attachment: attachment)) .accessibilityLabel(Self.accessibilityLabel(for: attachment))
.accessibilityAddTraits(.isButton) .accessibilityAddTraits(attachment.supportedType == .image ? [.isImage, .isButton] : .isButton)
} }
} }
@ -335,21 +334,14 @@ public struct StatusRowMediaPreviewView: View {
Spacer() Spacer()
} }
} }
}
/// A ``ViewModifier`` that creates a suitable accessibility label for an image that may or may not have alt text private static func accessibilityLabel(for attachment: MediaAttachment) -> Text {
private struct ConditionalAccessibilityLabelAltTextModifier: ViewModifier {
let attachment: MediaAttachment
func body(content: Content) -> some View {
if let altText = attachment.description { if let altText = attachment.description {
content return Text("accessibility.image.alt-text-\(altText)")
.accessibilityLabel("accessibility.image.alt-text-\(altText)")
} else if let typeDescription = attachment.localizedTypeDescription { } else if let typeDescription = attachment.localizedTypeDescription {
content return Text(typeDescription)
.accessibilityLabel(typeDescription)
} else { } else {
content return Text("accessibility.tabs.profile.picker.media")
} }
} }
} }