improved reactions a11y

This commit is contained in:
Mauro Romito
2025-06-17 19:54:08 +02:00
committed by Mauro
parent 28038adc0d
commit 12e55d6c28
5 changed files with 53 additions and 10 deletions
+11 -1
View File
@@ -10,6 +10,10 @@ import Foundation
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
internal enum L10n {
/// Add reaction: %1$@
internal static func a11yAddReaction(_ p1: Any) -> String {
return L10n.tr("Localizable", "a11y_add_reaction", String(describing: p1))
}
/// Avatar
internal static var a11yAvatar: String { return L10n.tr("Localizable", "a11y_avatar") }
/// Delete
@@ -72,6 +76,10 @@ internal enum L10n {
}
/// Tap to show all
internal static var a11yReadReceiptsTapToShowAll: String { return L10n.tr("Localizable", "a11y_read_receipts_tap_to_show_all") }
/// Remove reaction: %1$@
internal static func a11yRemoveReaction(_ p1: Any) -> String {
return L10n.tr("Localizable", "a11y_remove_reaction", String(describing: p1))
}
/// Remove reaction with %1$@
internal static func a11yRemoveReactionWith(_ p1: Any) -> String {
return L10n.tr("Localizable", "a11y_remove_reaction_with", String(describing: p1))
@@ -838,7 +846,7 @@ internal enum L10n {
internal static func notificationCompatSummaryTitle(_ p1: Int) -> String {
return L10n.tr("Localizable", "notification_compat_summary_title", p1)
}
/// Notification
/// You have new message(s).
internal static var notificationFallbackContent: String { return L10n.tr("Localizable", "notification_fallback_content") }
/// 📹 Incoming call
internal static var notificationIncomingCall: String { return L10n.tr("Localizable", "notification_incoming_call") }
@@ -2366,6 +2374,8 @@ internal enum L10n {
internal static var screenRoomTimelineReactionsShowLess: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_show_less") }
/// Show more
internal static var screenRoomTimelineReactionsShowMore: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_show_more") }
/// Show reactions summary
internal static var screenRoomTimelineReactionsShowReactionsSummary: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_show_reactions_summary") }
/// New
internal static var screenRoomTimelineReadMarkerTitle: String { return L10n.tr("Localizable", "screen_room_timeline_read_marker_title") }
/// Plural format key: "%#@COUNT@"
@@ -36,6 +36,7 @@ struct EmojiPickerScreen: View {
.background(Circle()
.foregroundColor(emojiBackgroundColor(for: emoji.value)))
}
.accessibilityLabel(accessibilityLabel(for: emoji.value))
}
} header: {
EmojiPickerScreenHeaderView(title: category.name)
@@ -62,6 +63,14 @@ struct EmojiPickerScreen: View {
}
}
private func accessibilityLabel(for emoji: String) -> String {
if selectedEmojis.contains(emoji) {
return L10n.a11yRemoveReaction(emoji)
} else {
return L10n.a11yAddReaction(emoji)
}
}
private func emojiBackgroundColor(for emoji: String) -> Color {
if selectedEmojis.contains(emoji) {
return .compound.bgActionPrimaryRest
@@ -162,15 +162,19 @@ struct TimelineItemMenu: View {
.foregroundColor(reactionBackgroundColor(for: emoji)))
.frame(maxWidth: .infinity, alignment: .leading)
}
.accessibilityLabel(hasReacted(to: emoji) ? L10n.a11yRemoveReaction(emoji) : L10n.a11yAddReaction(emoji))
}
private func hasReacted(to emoji: String) -> Bool {
if let reaction = item.properties.reactions.first(where: { $0.key == emoji }),
reaction.isHighlighted {
return true
}
return false
}
private func reactionBackgroundColor(for emoji: String) -> Color {
if let reaction = item.properties.reactions.first(where: { $0.key == emoji }),
reaction.isHighlighted {
return .compound.bgActionPrimaryRest
} else {
return .clear
}
hasReacted(to: emoji) ? .compound.bgActionPrimaryRest : .clear
}
private func viewsForActions(_ actions: [TimelineItemMenuAction]) -> some View {
@@ -138,11 +138,24 @@ struct TimelineCollapseButtonLabel: View {
}
struct TimelineReactionButton: View {
@Environment(\.accessibilityVoiceOverEnabled) private var voiceOverEnabled
let reaction: AggregatedReaction
let toggleReaction: (String) -> Void
let showReactionSummary: (String) -> Void
@ScaledMetric(relativeTo: .subheadline) private var lineHeight = 20
private var accessibilityLabel: String {
if reaction.isHighlighted {
return reaction.count > 1 ? L10n.tr("Localizable", "screen_room_timeline_reaction_including_you_a11y", reaction.count - 1, reaction.displayKey) : L10n.screenRoomTimelineReactionYouA11y(reaction.displayKey)
}
return L10n.tr("Localizable", "screen_room_timeline_reaction_a11y", reaction.count, reaction.displayKey)
}
private var toggleReactionAccessibilityActionName: String {
reaction.isHighlighted ? L10n.a11yRemoveReaction(reaction.displayKey) : L10n.a11yAddReaction(reaction.displayKey)
}
var body: some View {
label
.onTapGesture {
@@ -151,8 +164,12 @@ struct TimelineReactionButton: View {
.longPressWithFeedback {
showReactionSummary(reaction.key)
}
.accessibilityHint(L10n.commonReaction)
.accessibilityAddTraits(reaction.isHighlighted ? .isSelected : [])
.accessibilityAddTraits(.isButton)
.accessibilityLabel(accessibilityLabel)
.accessibilityHint(toggleReactionAccessibilityActionName)
.accessibilityAction(named: L10n.screenRoomTimelineReactionsShowReactionsSummary) {
showReactionSummary(reaction.key)
}
}
var label: some View {