diff --git a/Localization/StringsConvertor/input/en.lproj/app.json b/Localization/StringsConvertor/input/en.lproj/app.json index 80b0882d9..8867385e2 100644 --- a/Localization/StringsConvertor/input/en.lproj/app.json +++ b/Localization/StringsConvertor/input/en.lproj/app.json @@ -136,6 +136,12 @@ "vote": "Vote", "closed": "Closed" }, + "meta_entity": { + "url": "Link: %s", + "hashtag": "Hastag %s", + "mention": "Show Profile: %s", + "email": "Email address: %s" + }, "actions": { "reply": "Reply", "reblog": "Reblog", diff --git a/Localization/app.json b/Localization/app.json index 80b0882d9..8867385e2 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -136,6 +136,12 @@ "vote": "Vote", "closed": "Closed" }, + "meta_entity": { + "url": "Link: %s", + "hashtag": "Hastag %s", + "mention": "Show Profile: %s", + "email": "Email address: %s" + }, "actions": { "reply": "Reply", "reblog": "Reblog", diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift index a3315211e..c9850a0d3 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusTableViewCell.swift @@ -99,6 +99,10 @@ extension StatusTableViewCell { return true } + override var accessibilityCustomActions: [UIAccessibilityCustomAction]? { + get { statusView.accessibilityCustomActions } + set { } + } } // MARK: - AdaptiveContainerMarginTableViewCell diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index 0ee85cdc8..44ae29267 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -314,6 +314,24 @@ public enum L10n { /// Undo reblog public static let unreblog = L10n.tr("Localizable", "Common.Controls.Status.Actions.Unreblog") } + public enum MetaEntity { + /// Email address: %@ + public static func email(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.MetaEntity.Email", String(describing: p1)) + } + /// Hastag %@ + public static func hashtag(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.MetaEntity.Hashtag", String(describing: p1)) + } + /// Show Profile: %@ + public static func mention(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.MetaEntity.Mention", String(describing: p1)) + } + /// Link: %@ + public static func url(_ p1: Any) -> String { + return L10n.tr("Localizable", "Common.Controls.Status.MetaEntity.Url", String(describing: p1)) + } + } public enum Poll { /// Closed public static let closed = L10n.tr("Localizable", "Common.Controls.Status.Poll.Closed") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings index 5375a81af..9114b96e5 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/en.lproj/Localizable.strings @@ -108,6 +108,10 @@ Please check your internet connection."; "Common.Controls.Status.Actions.Unreblog" = "Undo reblog"; "Common.Controls.Status.ContentWarning" = "Content Warning"; "Common.Controls.Status.MediaContentWarning" = "Tap anywhere to reveal"; +"Common.Controls.Status.MetaEntity.Email" = "Email address: %@"; +"Common.Controls.Status.MetaEntity.Hashtag" = "Hastag %@"; +"Common.Controls.Status.MetaEntity.Mention" = "Show Profile: %@"; +"Common.Controls.Status.MetaEntity.Url" = "Link: %@"; "Common.Controls.Status.Poll.Closed" = "Closed"; "Common.Controls.Status.Poll.Vote" = "Vote"; "Common.Controls.Status.SensitiveContent" = "Sensitive Content"; diff --git a/MastodonSDK/Sources/MastodonUI/Extension/MetaEntity+Accessibility.swift b/MastodonSDK/Sources/MastodonUI/Extension/MetaEntity+Accessibility.swift new file mode 100644 index 000000000..b604a3870 --- /dev/null +++ b/MastodonSDK/Sources/MastodonUI/Extension/MetaEntity+Accessibility.swift @@ -0,0 +1,27 @@ +// +// MetaEntity+Accessibility.swift +// +// +// Created by Jed Fox on 2022-11-03. +// + +import Meta +import MastodonLocalization + +extension Meta.Entity { + var accessibilityCustomActionLabel: String? { + switch meta { + case .url(_, trimmed: _, url: let url, userInfo: _): + return L10n.Common.Controls.Status.MetaEntity.url(url) + case .hashtag(_, hashtag: let hashtag, userInfo: _): + return L10n.Common.Controls.Status.MetaEntity.hashtag(hashtag) + case .mention(_, mention: let mention, userInfo: _): + return L10n.Common.Controls.Status.MetaEntity.mention(mention) + case .email(let email, userInfo: _): + return L10n.Common.Controls.Status.MetaEntity.email(email) + // emoji are not actionable + case .emoji: + return nil + } + } +} diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index d0b5daa6f..416226cbb 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -315,7 +315,6 @@ extension StatusView.ViewModel { statusView.contentMetaText.configure( content: content ) - statusView.contentMetaText.textView.accessibilityLabel = content.string statusView.contentMetaText.textView.accessibilityTraits = [.staticText] statusView.contentMetaText.textView.accessibilityElementsHidden = false } else { @@ -727,8 +726,23 @@ extension StatusView.ViewModel { statusView.accessibilityLabel = accessibilityLabel } .store(in: &disposeBag) + + Publishers.CombineLatest( + $content, + $isContentReveal.removeDuplicates() + ) + .map { content, isRevealed in + guard isRevealed, let entities = content?.entities else { return [] } + return entities.compactMap { entity in + guard let name = entity.accessibilityCustomActionLabel else { return nil } + return UIAccessibilityCustomAction(name: name) { action in + statusView.delegate?.statusView(statusView, metaText: statusView.contentMetaText, didSelectMeta: entity.meta) + return true + } + } + } + .assign(to: \.accessibilityCustomActions, on: statusView.contentMetaText.textView) + .store(in: &disposeBag) } } - - diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index 8ab34ce4f..563bc7e3d 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -547,6 +547,13 @@ extension StatusView { } +extension StatusView { + public override var accessibilityCustomActions: [UIAccessibilityCustomAction]? { + get { contentMetaText.textView.accessibilityCustomActions } + set { } + } +} + // MARK: - AdaptiveContainerView extension StatusView: AdaptiveContainerView { public func updateContainerViewComponentsLayoutMarginsRelativeArrangementBehavior(isEnabled: Bool) {