Skip to content

Commit

Permalink
Improve voice over labels and actions (#726)
Browse files Browse the repository at this point in the history
* Improve voice over labels and navigation

* Numerous label fixes, image removals, and actions

* Fix UI-tests caused by adding accessibility actions which changes elements to buttons
  • Loading branch information
laevandus authored Jan 23, 2025
1 parent 9557751 commit 1ceac73
Show file tree
Hide file tree
Showing 23 changed files with 127 additions and 4 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).

### 🐞 Fixed
- Fix thread reply action shown when inside a Thread [#717](https://github.com/GetStream/stream-chat-swiftui/pull/717)
- Improve voice over by adding missing labels, removing decorative images, and setting accessibility actions [#726](https://github.com/GetStream/stream-chat-swiftui/pull/726)
### 🔄 Changed
- Deprecate unused `ChatMessage.userDisplayInfo(from:)` which only accessed cached data [#718](https://github.com/GetStream/stream-chat-swiftui/pull/718)
### 🎭 New Localizations
Add localizable keys for supporting accessibility labels:
- `channel.list.scroll-to-bottom.title`
- `channel.header.info.title`
- `message.attachment.accessibility-label`
- `message.read-status.seen-by*`
- `message.cell.sent-at`
- `composer.picker.show-all`
- `composer.audio-recording.*`

# [4.70.0](https://github.com/GetStream/stream-chat-swiftui/releases/tag/4.70.0)
_January 15, 2025_
Expand Down
3 changes: 3 additions & 0 deletions DemoAppSwiftUI/ChannelHeader/CustomChannelHeader.swift
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,15 @@ public struct CustomChannelHeader: ToolbarContent {
.background(colors.tintColor)
.clipShape(Circle())
}
.accessibilityLabel(Text("New Channel"))
}
ToolbarItem(placement: .navigationBarLeading) {
Button {
actionsPopupShown = true
} label: {
StreamLazyImage(url: currentUserController.currentUser?.imageURL)
.accessibilityLabel("Account Actions")
.accessibilityAddTraits(.isButton)
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,20 +71,23 @@ public struct DefaultChatChannelHeader: ToolbarContent {
.clipShape(Circle())
.offset(x: 8)
}
.accessibilityLabel(Text(L10n.Channel.Header.Info.title))

NavigationLink(isActive: $isActive) {
LazyView(ChatChannelInfoView(channel: channel, shownFromMessageList: true))
} label: {
EmptyView()
}

.accessibilityHidden(true)

ChannelAvatarView(
avatar: headerImage,
showOnlineIndicator: onlineIndicatorShown,
size: CGSize(width: 36, height: 36)
)
.offset(x: 8)
.allowsHitTesting(false)
.accessibilityHidden(true)
}
.accessibilityIdentifier("ChannelAvatarView")
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,9 @@ public struct ChatChannelInfoView: View, KeyboardReadable {
.onTapGesture {
viewModel.addUsersShown = false
}
.accessibilityAction {
viewModel.addUsersShown = false
}
AddUsersView(
loadedUserIds: viewModel.participants.map(\.id),
onUserTap: viewModel.addUserTapped(_:)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ public struct AttachmentPickerTypeView: View {
pickerType: .media,
selected: attachmentPickerType
)
.accessibilityLabel(Text(L10n.Composer.Picker.showAll))
.accessibilityIdentifier("PickerTypeButtonMedia")
}

Expand All @@ -65,6 +66,7 @@ public struct AttachmentPickerTypeView: View {
pickerType: .instantCommands,
selected: attachmentPickerType
)
.accessibilityLabel(Text(L10n.Composer.Suggestions.Commands.header))
.accessibilityIdentifier("PickerTypeButtonCommands")
}
case .collapsed:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public struct AttachmentSourcePickerView: View {
isSelected: selected == .files,
onTap: onTap
)
.accessibilityLabel(L10n.Composer.Picker.file)
.accessibilityIdentifier("attachmentPickerFiles")

AttachmentPickerButton(
Expand All @@ -176,6 +177,7 @@ public struct AttachmentSourcePickerView: View {
isSelected: selected == .polls,
onTap: onTap
)
.accessibilityLabel(L10n.Composer.Polls.createPoll)
.accessibilityIdentifier("attachmentPickerPolls")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public struct SendMessageButton: View {
)
}
.disabled(!enabled)
.accessibilityAddTraits(.isButton)
.accessibilityLabel(Text(L10n.Composer.Placeholder.message))
.accessibilityIdentifier("SendMessageButton")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,5 +85,12 @@ public struct VoiceRecordingButton: View {
}
}
)
.accessibilityRemoveTraits(.isImage)
.accessibilityAddTraits(.isButton)
.accessibilityLabel(Text(L10n.Composer.AudioRecording.start))
.accessibilityAction {
viewModel.recordingState = .recording(.zero)
viewModel.startRecording()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct RecordingView: View {
HStack {
Image(systemName: "mic")
.foregroundColor(.red)
.accessibilityHidden(true)
RecordingDurationView(duration: audioRecordingInfo.duration)

Spacer()
Expand All @@ -30,6 +31,7 @@ struct RecordingView: View {
}
.foregroundColor(Color(colors.textLowEmphasis))
.opacity(opacityForSlideToCancel)
.accessibilityHidden(true)

Spacer()

Expand All @@ -38,6 +40,7 @@ struct RecordingView: View {
} label: {
Image(systemName: "mic")
}
.accessibilityLabel(Text(L10n.Composer.AudioRecording.stop))
}
.padding(.all, 12)
.overlay(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ struct VoiceRecordingView: View {
.resizable()
.aspectRatio(contentMode: .fit)
.frame(height: 40)
.accessibilityHidden(true)
}
}
.onReceive(handler.$context, perform: { value in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,9 @@ struct BottomReactionsView: View {
.onLongPressGesture {
onLongPress()
}
.accessibilityAction {
viewModel.reactionTapped(reaction)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ public struct FileAttachmentView: View {
.onTapGesture {
fullScreenShown = true
}
.accessibilityAction {
fullScreenShown = true
}

Spacer()
}
Expand Down Expand Up @@ -134,6 +137,7 @@ public struct FileAttachmentDisplayView: View {
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 34, height: 40)
.accessibilityHidden(true)
VStack(alignment: .leading, spacing: 8) {
Text(title)
.font(fonts.bodyBold)
Expand All @@ -146,6 +150,7 @@ public struct FileAttachmentDisplayView: View {
}
Spacer()
}
.accessibilityElement(children: .combine)
}

private var previewImage: UIImage {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public struct GiphyBadgeView: View {
BottomLeftView {
HStack(spacing: 4) {
Image(uiImage: images.commandGiphy)
.accessibilityHidden(true)
Text(L10n.Message.GiphyAttachment.title)
.font(fonts.bodyBold)
.foregroundColor(Color(colors.staticColorText))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,11 @@ struct LazyLoadingImage: View {
imageTapped(index ?? 0)
}
)
.accessibilityLabel(L10n.Message.Attachment.accessibilityLabel((index ?? 0) + 1))
.accessibilityAddTraits(source.type == .video ? .startsMediaSession : .isImage)
.accessibilityAction {
imageTapped(index ?? 0)
}
}
} else if error != nil {
Color(.secondarySystemBackground)
Expand All @@ -383,6 +388,7 @@ struct LazyLoadingImage: View {

if source.type == .video && width > 64 && source.uploadingState == nil {
VideoPlayIcon()
.accessibilityHidden(true)
}
}
.onAppear {
Expand Down Expand Up @@ -414,6 +420,7 @@ struct LazyLoadingImage: View {
.allowsHitTesting(false)
.scaleEffect(1.0001) // Needed because of SwiftUI sometimes incorrectly displaying landscape images.
.clipped()
.accessibilityHidden(true)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ public struct MessageAuthorAndDateView: View {
}
Spacer()
}
.accessibilityElement(children: .contain)
.accessibilityElement(children: .combine)
.accessibilityIdentifier("MessageAuthorAndDateView")
}
}
Expand Down Expand Up @@ -80,11 +80,16 @@ struct MessageDateView: View {
return text
}

var accessibilityLabel: String {
L10n.Message.Cell.sentAt(text)
}

var body: some View {
Text(text)
.font(fonts.footnote)
.foregroundColor(Color(colors.textLowEmphasis))
.animation(nil)
.accessibilityLabel(Text(accessibilityLabel))
.accessibilityIdentifier("MessageDateView")
}
}
Expand Down Expand Up @@ -119,6 +124,11 @@ public struct MessageReadIndicatorView: View {
.customizable()
.foregroundColor(!readUsers.isEmpty ? colors.tintColor : Color(colors.textLowEmphasis))
.frame(height: 16)
.accessibilityLabel(
Text(
readUsers.isEmpty ? L10n.Message.ReadStatus.seenByNoOne : L10n.Message.ReadStatus.seenByOthers
)
)
.accessibilityIdentifier("readIndicatorCheckmark")
}
.accessibilityElement(children: .contain)
Expand Down Expand Up @@ -161,6 +171,7 @@ public struct MessagePinDetailsView: View {
Image(uiImage: images.pin)
.customizable()
.frame(maxHeight: 12)
.accessibilityHidden(true)
Text("\(L10n.Message.Cell.pinnedBy) \(message.pinDetails?.pinnedBy.name ?? L10n.Message.Cell.unknownPin)")
.font(fonts.footnote)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@ public struct ScrollToBottomButton: View {
.frame(width: buttonSize, height: buttonSize)
.modifier(ShadowViewModifier(cornerRadius: buttonSize / 2))
}
.accessibilityLabel(Text(L10n.Channel.List.ScrollToBottom.title))
.padding()
.overlay(
unreadCount > 0 ?
Expand Down Expand Up @@ -526,6 +527,7 @@ public struct DateIndicatorView: View {
.padding(.all, 8)
Spacer()
}
.accessibilityAddTraits(.isHeader)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ struct QuotedMessageViewContainer<Factory: ViewFactory>: View {
.onTapGesture(perform: {
scrolledId = quotedMessage.messageId
})
.accessibilityAction {
scrolledId = quotedMessage.messageId
}
.accessibilityIdentifier("QuotedMessageViewContainer")
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ struct VideoAttachmentContentView: View {
.scaledToFill()
.clipped()
.allowsHitTesting(false)
.accessibilityHidden(true)

if width > 64 && attachment.uploadingState == nil {
VStack {
Expand All @@ -166,6 +167,9 @@ struct VideoAttachmentContentView: View {
.onTapGesture {
fullScreenShown = true
}
.accessibilityAction {
fullScreenShown = true
}
}
} else if error != nil {
Color(.secondarySystemBackground)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ struct ReactionsContainer: View {
.onLongPressGesture {
onLongPressGesture()
}
.accessibilityAction {
onTapGesture()
}
}

Spacer()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -164,12 +164,14 @@ public struct ChannelMemberView: View {
showOnlineIndicator: onlineIndicatorShown,
size: memberSize
)
.accessibilityHidden(true)

Text(name)
.font(fonts.footnoteBold)
.multilineTextAlignment(.center)
.lineLimit(2)
.frame(maxWidth: memberSize.width, maxHeight: 34, alignment: .top)
.accessibilityLabel(Text(name) + Text(onlineIndicatorShown ? ", \(L10n.Message.Title.online)" : ""))
}
}
}
Loading

0 comments on commit 1ceac73

Please sign in to comment.