mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
improved reactions a11y
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
"Notification" = "Notification";
|
"Notification" = "Notification";
|
||||||
|
"a11y_add_reaction" = "Add reaction: %1$@";
|
||||||
"a11y_avatar" = "Avatar";
|
"a11y_avatar" = "Avatar";
|
||||||
"a11y_delete" = "Delete";
|
"a11y_delete" = "Delete";
|
||||||
"a11y_hide_password" = "Hide password";
|
"a11y_hide_password" = "Hide password";
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
"a11y_read_receipts_multiple" = "Read by %1$@ and %2$@";
|
"a11y_read_receipts_multiple" = "Read by %1$@ and %2$@";
|
||||||
"a11y_read_receipts_single" = "Read by %1$@";
|
"a11y_read_receipts_single" = "Read by %1$@";
|
||||||
"a11y_read_receipts_tap_to_show_all" = "Tap to show all";
|
"a11y_read_receipts_tap_to_show_all" = "Tap to show all";
|
||||||
|
"a11y_remove_reaction" = "Remove reaction: %1$@";
|
||||||
"a11y_remove_reaction_with" = "Remove reaction with %1$@";
|
"a11y_remove_reaction_with" = "Remove reaction with %1$@";
|
||||||
"a11y_send_files" = "Send files";
|
"a11y_send_files" = "Send files";
|
||||||
"a11y_show_password" = "Show password";
|
"a11y_show_password" = "Show password";
|
||||||
@@ -357,6 +359,7 @@
|
|||||||
"notification_channel_noisy" = "Noisy notifications";
|
"notification_channel_noisy" = "Noisy notifications";
|
||||||
"notification_channel_ringing_calls" = "Ringing calls";
|
"notification_channel_ringing_calls" = "Ringing calls";
|
||||||
"notification_channel_silent" = "Silent notifications";
|
"notification_channel_silent" = "Silent notifications";
|
||||||
|
"notification_fallback_content" = "You have new message(s).";
|
||||||
"notification_incoming_call" = "📹 Incoming call";
|
"notification_incoming_call" = "📹 Incoming call";
|
||||||
"notification_inline_reply_failed" = "** Failed to send - please open room";
|
"notification_inline_reply_failed" = "** Failed to send - please open room";
|
||||||
"notification_invite_body" = "Invited you to chat";
|
"notification_invite_body" = "Invited you to chat";
|
||||||
@@ -534,6 +537,7 @@
|
|||||||
"screen_room_timeline_tombstoned_room_message" = "This room has been replaced and is no longer active";
|
"screen_room_timeline_tombstoned_room_message" = "This room has been replaced and is no longer active";
|
||||||
"screen_room_timeline_upgraded_room_action" = "See old messages";
|
"screen_room_timeline_upgraded_room_action" = "See old messages";
|
||||||
"screen_room_timeline_upgraded_room_message" = "This room is a continuation of another room";
|
"screen_room_timeline_upgraded_room_message" = "This room is a continuation of another room";
|
||||||
|
"screen_room_timeline_reactions_show_reactions_summary" = "Show reactions summary";
|
||||||
"screen_roomlist_tombstoned_room_description" = "This room has been upgraded";
|
"screen_roomlist_tombstoned_room_description" = "This room has been upgraded";
|
||||||
"screen_security_and_privacy_add_room_address_action" = "Add room address";
|
"screen_security_and_privacy_add_room_address_action" = "Add room address";
|
||||||
"screen_security_and_privacy_ask_to_join_option_description" = "Anyone can ask to join the room but an administrator or moderator will have to accept the request.";
|
"screen_security_and_privacy_ask_to_join_option_description" = "Anyone can ask to join the room but an administrator or moderator will have to accept the request.";
|
||||||
@@ -1212,7 +1216,6 @@
|
|||||||
"banner_set_up_recovery_submit" = "Set up recovery";
|
"banner_set_up_recovery_submit" = "Set up recovery";
|
||||||
"dialog_title_error" = "Error";
|
"dialog_title_error" = "Error";
|
||||||
"dialog_title_success" = "Success";
|
"dialog_title_success" = "Success";
|
||||||
"notification_fallback_content" = "Notification";
|
|
||||||
"notification_invitation_action_join" = "Join";
|
"notification_invitation_action_join" = "Join";
|
||||||
"notification_invitation_action_reject" = "Reject";
|
"notification_invitation_action_reject" = "Reject";
|
||||||
"notification_room_action_mark_as_read" = "Mark as read";
|
"notification_room_action_mark_as_read" = "Mark as read";
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import Foundation
|
|||||||
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
|
// swiftlint:disable explicit_type_interface function_parameter_count identifier_name line_length
|
||||||
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
|
// swiftlint:disable nesting type_body_length type_name vertical_whitespace_opening_braces
|
||||||
internal enum L10n {
|
internal enum L10n {
|
||||||
|
/// Add reaction: %1$@
|
||||||
|
internal static func a11yAddReaction(_ p1: Any) -> String {
|
||||||
|
return L10n.tr("Localizable", "a11y_add_reaction", String(describing: p1))
|
||||||
|
}
|
||||||
/// Avatar
|
/// Avatar
|
||||||
internal static var a11yAvatar: String { return L10n.tr("Localizable", "a11y_avatar") }
|
internal static var a11yAvatar: String { return L10n.tr("Localizable", "a11y_avatar") }
|
||||||
/// Delete
|
/// Delete
|
||||||
@@ -72,6 +76,10 @@ internal enum L10n {
|
|||||||
}
|
}
|
||||||
/// Tap to show all
|
/// Tap to show all
|
||||||
internal static var a11yReadReceiptsTapToShowAll: String { return L10n.tr("Localizable", "a11y_read_receipts_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$@
|
/// Remove reaction with %1$@
|
||||||
internal static func a11yRemoveReactionWith(_ p1: Any) -> String {
|
internal static func a11yRemoveReactionWith(_ p1: Any) -> String {
|
||||||
return L10n.tr("Localizable", "a11y_remove_reaction_with", String(describing: p1))
|
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 {
|
internal static func notificationCompatSummaryTitle(_ p1: Int) -> String {
|
||||||
return L10n.tr("Localizable", "notification_compat_summary_title", p1)
|
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") }
|
internal static var notificationFallbackContent: String { return L10n.tr("Localizable", "notification_fallback_content") }
|
||||||
/// 📹 Incoming call
|
/// 📹 Incoming call
|
||||||
internal static var notificationIncomingCall: String { return L10n.tr("Localizable", "notification_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") }
|
internal static var screenRoomTimelineReactionsShowLess: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_show_less") }
|
||||||
/// Show more
|
/// Show more
|
||||||
internal static var screenRoomTimelineReactionsShowMore: String { return L10n.tr("Localizable", "screen_room_timeline_reactions_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
|
/// New
|
||||||
internal static var screenRoomTimelineReadMarkerTitle: String { return L10n.tr("Localizable", "screen_room_timeline_read_marker_title") }
|
internal static var screenRoomTimelineReadMarkerTitle: String { return L10n.tr("Localizable", "screen_room_timeline_read_marker_title") }
|
||||||
/// Plural format key: "%#@COUNT@"
|
/// Plural format key: "%#@COUNT@"
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ struct EmojiPickerScreen: View {
|
|||||||
.background(Circle()
|
.background(Circle()
|
||||||
.foregroundColor(emojiBackgroundColor(for: emoji.value)))
|
.foregroundColor(emojiBackgroundColor(for: emoji.value)))
|
||||||
}
|
}
|
||||||
|
.accessibilityLabel(accessibilityLabel(for: emoji.value))
|
||||||
}
|
}
|
||||||
} header: {
|
} header: {
|
||||||
EmojiPickerScreenHeaderView(title: category.name)
|
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 {
|
private func emojiBackgroundColor(for emoji: String) -> Color {
|
||||||
if selectedEmojis.contains(emoji) {
|
if selectedEmojis.contains(emoji) {
|
||||||
return .compound.bgActionPrimaryRest
|
return .compound.bgActionPrimaryRest
|
||||||
|
|||||||
@@ -162,15 +162,19 @@ struct TimelineItemMenu: View {
|
|||||||
.foregroundColor(reactionBackgroundColor(for: emoji)))
|
.foregroundColor(reactionBackgroundColor(for: emoji)))
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.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 {
|
private func reactionBackgroundColor(for emoji: String) -> Color {
|
||||||
if let reaction = item.properties.reactions.first(where: { $0.key == emoji }),
|
hasReacted(to: emoji) ? .compound.bgActionPrimaryRest : .clear
|
||||||
reaction.isHighlighted {
|
|
||||||
return .compound.bgActionPrimaryRest
|
|
||||||
} else {
|
|
||||||
return .clear
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private func viewsForActions(_ actions: [TimelineItemMenuAction]) -> some View {
|
private func viewsForActions(_ actions: [TimelineItemMenuAction]) -> some View {
|
||||||
|
|||||||
@@ -138,11 +138,24 @@ struct TimelineCollapseButtonLabel: View {
|
|||||||
}
|
}
|
||||||
|
|
||||||
struct TimelineReactionButton: View {
|
struct TimelineReactionButton: View {
|
||||||
|
@Environment(\.accessibilityVoiceOverEnabled) private var voiceOverEnabled
|
||||||
|
|
||||||
let reaction: AggregatedReaction
|
let reaction: AggregatedReaction
|
||||||
let toggleReaction: (String) -> Void
|
let toggleReaction: (String) -> Void
|
||||||
let showReactionSummary: (String) -> Void
|
let showReactionSummary: (String) -> Void
|
||||||
@ScaledMetric(relativeTo: .subheadline) private var lineHeight = 20
|
@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 {
|
var body: some View {
|
||||||
label
|
label
|
||||||
.onTapGesture {
|
.onTapGesture {
|
||||||
@@ -151,8 +164,12 @@ struct TimelineReactionButton: View {
|
|||||||
.longPressWithFeedback {
|
.longPressWithFeedback {
|
||||||
showReactionSummary(reaction.key)
|
showReactionSummary(reaction.key)
|
||||||
}
|
}
|
||||||
.accessibilityHint(L10n.commonReaction)
|
.accessibilityAddTraits(.isButton)
|
||||||
.accessibilityAddTraits(reaction.isHighlighted ? .isSelected : [])
|
.accessibilityLabel(accessibilityLabel)
|
||||||
|
.accessibilityHint(toggleReactionAccessibilityActionName)
|
||||||
|
.accessibilityAction(named: L10n.screenRoomTimelineReactionsShowReactionsSummary) {
|
||||||
|
showReactionSummary(reaction.key)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var label: some View {
|
var label: some View {
|
||||||
|
|||||||
Reference in New Issue
Block a user