diff --git a/CHANGES.rst b/CHANGES.rst index bf9bfa3ca..79ce84fd6 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -5,6 +5,7 @@ Bug fix: * VoiceOver: RoomVC: Fix some missing accessibility labels for buttons (#2722). * VoiceOver: RoomVC: Make VoiceOver focus on the contextual menu when selecting an event (#2721). * VoiceOver: RoomVC: Do not lose the focus on the timeline when paginating (with 3 fingers) (#2720). + * VoiceOver: RoomVC: No VoiceOver on media (#2726). Changes in 0.9.4 (2019-09-13) =============================================== diff --git a/Riot/Assets/en.lproj/Vector.strings b/Riot/Assets/en.lproj/Vector.strings index 8deb33c7b..8d1dd18f4 100644 --- a/Riot/Assets/en.lproj/Vector.strings +++ b/Riot/Assets/en.lproj/Vector.strings @@ -323,6 +323,13 @@ "room_accessibility_call" = "Call"; "room_accessibility_hangup" = "Hang up"; +"media_type_accessibility_image" = "Image"; +"media_type_accessibility_audio" = "Audio"; +"media_type_accessibility_video" = "Video"; +"media_type_accessibility_location" = "Location"; +"media_type_accessibility_file" = "File"; +"media_type_accessibility_sticker" = "Sticker"; + // Unknown devices "unknown_devices_alert_title" = "Room contains unknown devices"; "unknown_devices_alert" = "This room contains unknown devices which have not been verified.\nThis means there is no guarantee that the devices belong to the users they claim to.\nWe recommend you go through the verification process for each device before continuing, but you can resend the message without verifying if you prefer."; diff --git a/Riot/Generated/Strings.swift b/Riot/Generated/Strings.swift index 6002846ab..3dd8ff2b2 100644 --- a/Riot/Generated/Strings.swift +++ b/Riot/Generated/Strings.swift @@ -1374,6 +1374,30 @@ internal enum VectorL10n { internal static var mediaPickerTitle: String { return VectorL10n.tr("Vector", "media_picker_title") } + /// Audio + internal static var mediaTypeAccessibilityAudio: String { + return VectorL10n.tr("Vector", "media_type_accessibility_audio") + } + /// File + internal static var mediaTypeAccessibilityFile: String { + return VectorL10n.tr("Vector", "media_type_accessibility_file") + } + /// Image + internal static var mediaTypeAccessibilityImage: String { + return VectorL10n.tr("Vector", "media_type_accessibility_image") + } + /// Location + internal static var mediaTypeAccessibilityLocation: String { + return VectorL10n.tr("Vector", "media_type_accessibility_location") + } + /// Sticker + internal static var mediaTypeAccessibilitySticker: String { + return VectorL10n.tr("Vector", "media_type_accessibility_sticker") + } + /// Video + internal static var mediaTypeAccessibilityVideo: String { + return VectorL10n.tr("Vector", "media_type_accessibility_video") + } /// The Internet connection appears to be offline. internal static var networkOfflinePrompt: String { return VectorL10n.tr("Vector", "network_offline_prompt") diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.h b/Riot/Modules/Room/CellData/RoomBubbleCellData.h index 777063a59..7c34278ff 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.h +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.h @@ -90,4 +90,9 @@ typedef NS_ENUM(NSInteger, RoomBubbleCellDataTag) - (BOOL)showAllReactionsForEvent:(NSString*)eventId; - (void)setShowAllReactions:(BOOL)showAllReactions forEvent:(NSString*)eventId; + +#pragma mark - Accessibility + +- (NSString*)accessibilityLabel; + @end diff --git a/Riot/Modules/Room/CellData/RoomBubbleCellData.m b/Riot/Modules/Room/CellData/RoomBubbleCellData.m index 5fda69f74..a89214ce4 100644 --- a/Riot/Modules/Room/CellData/RoomBubbleCellData.m +++ b/Riot/Modules/Room/CellData/RoomBubbleCellData.m @@ -698,4 +698,58 @@ static NSAttributedString *timestampVerticalWhitespace = nil; } } +- (NSString *)accessibilityLabel +{ + NSString *accessibilityLabel; + + // Only media require manual handling for accessibility + if (self.attachment) + { + NSString *mediaName = [self accessibilityLabelForAttachmentType:self.attachment.type]; + + MXJSONModelSetString(accessibilityLabel, self.events.firstObject.content[@"body"]); + if (accessibilityLabel) + { + accessibilityLabel = [NSString stringWithFormat:@"%@ %@", mediaName, accessibilityLabel]; + } + else + { + accessibilityLabel = mediaName; + } + } + + return accessibilityLabel; +} + +- (NSString*)accessibilityLabelForAttachmentType:(MXKAttachmentType)attachmentType +{ + NSString *accessibilityLabel; + switch (attachmentType) + { + case MXKAttachmentTypeImage: + accessibilityLabel = NSLocalizedStringFromTable(@"media_type_accessibility_image", @"Vector", nil); + break; + case MXKAttachmentTypeAudio: + accessibilityLabel = NSLocalizedStringFromTable(@"media_type_accessibility_audio", @"Vector", nil); + break; + case MXKAttachmentTypeVideo: + accessibilityLabel = NSLocalizedStringFromTable(@"media_type_accessibility_video", @"Vector", nil); + break; + case MXKAttachmentTypeLocation: + accessibilityLabel = NSLocalizedStringFromTable(@"media_type_accessibility_location", @"Vector", nil); + break; + case MXKAttachmentTypeFile: + accessibilityLabel = NSLocalizedStringFromTable(@"media_type_accessibility_file", @"Vector", nil); + break; + case MXKAttachmentTypeSticker: + accessibilityLabel = NSLocalizedStringFromTable(@"media_type_accessibility_sticker", @"Vector", nil); + break; + default: + accessibilityLabel = @""; + break; + } + + return accessibilityLabel; +} + @end diff --git a/Riot/Modules/Room/DataSources/RoomDataSource.m b/Riot/Modules/Room/DataSources/RoomDataSource.m index 3b05bc638..103fd0acc 100644 --- a/Riot/Modules/Room/DataSources/RoomDataSource.m +++ b/Riot/Modules/Room/DataSources/RoomDataSource.m @@ -196,6 +196,8 @@ if ([cell isKindOfClass:MXKRoomBubbleTableViewCell.class]) { MXKRoomBubbleTableViewCell *bubbleCell = (MXKRoomBubbleTableViewCell*)cell; + [self resetAccessibilityForCell:bubbleCell]; + RoomBubbleCellData *cellData = (RoomBubbleCellData*)bubbleCell.bubbleData; NSArray *bubbleComponents = cellData.bubbleComponents; @@ -507,6 +509,8 @@ // Auto animate the sticker in case of animated gif bubbleCell.isAutoAnimatedGif = (cellData.attachment && cellData.attachment.type == MXKAttachmentTypeSticker); + + [self setupAccessibilityForCell:bubbleCell withCellData:cellData]; } return cell; @@ -563,6 +567,35 @@ [self sendVideo:videoLocalURL withThumbnail:videoThumbnail success:success failure:failure]; } + +#pragma - Accessibility + +- (void)setupAccessibilityForCell:(MXKRoomBubbleTableViewCell *)cell withCellData:(RoomBubbleCellData*)cellData +{ + // Set accessibility only on media. Let VoiceOver automatically manages text messages + if (cellData.attachment) + { + NSString *accessibilityLabel = [cellData accessibilityLabel]; + if (cell.messageTextView.text.length) + { + // Files are presented as text with link + cell.messageTextView.accessibilityLabel = accessibilityLabel; + cell.messageTextView.isAccessibilityElement = YES; + } + else + { + cell.attachmentView.accessibilityLabel = accessibilityLabel; + cell.attachmentView.isAccessibilityElement = YES; + } + } +} + +- (void)resetAccessibilityForCell:(MXKRoomBubbleTableViewCell *)cell +{ + cell.messageTextView.accessibilityLabel = nil; + cell.attachmentView.accessibilityLabel = nil; +} + #pragma mark - BubbleReactionsViewModelDelegate - (void)bubbleReactionsViewModel:(BubbleReactionsViewModel *)viewModel didAddReaction:(MXReactionCount *)reactionCount forEventId:(NSString *)eventId