From 9c30ecd9c0065b5ba3f06f0ce14e3ff4d1148656 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Mon, 6 Feb 2023 21:29:39 -0500 Subject: [PATCH 1/5] Make the translation info view accessible at the root of a thread --- .../StatusThreadRootTableViewCell.swift | 1 + .../MastodonUI/View/Content/StatusView.swift | 26 ++++++++++++++++--- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift index 73b700e27..6de60c66b 100644 --- a/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift +++ b/Mastodon/Scene/Share/View/TableviewCell/StatusThreadRootTableViewCell.swift @@ -108,6 +108,7 @@ extension StatusThreadRootTableViewCell { statusView.viewModel.isContentReveal ? statusView.contentMetaText.textView : statusView.spoilerOverlayView, + statusView.translatedInfoView, statusView.mediaGridContainerView, statusView.pollTableView, statusView.pollStatusStackView, diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index b2e5a49ae..e51ccfedf 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -197,8 +197,17 @@ public final class StatusView: UIView { label.numberOfLines = 0 return label }() - lazy var translatedInfoView: UIView = { - let containerView = UIView() + + private class TranslatedInfoView: UIView { + var revertAction: (() -> Void)? + + override func accessibilityActivate() -> Bool { + revertAction?() + return true + } + } + public private(set) lazy var translatedInfoView: UIView = { + let containerView = TranslatedInfoView() let revertButton = UIButton() revertButton.titleLabel?.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .bold)) @@ -230,7 +239,14 @@ public final class StatusView: UIView { ]) containerView.isHidden = true - + + containerView.isAccessibilityElement = true + containerView.accessibilityLabel = L10n.Common.Controls.Status.Translation.showOriginal + containerView.accessibilityTraits = [.button] + containerView.revertAction = { [weak self] in + self?.revertTranslation() + } + return containerView }() @@ -750,10 +766,12 @@ extension StatusView { .sink { [weak self] translatedFromLanguage, translatedUsingProvider in guard let self = self else { return } if let translatedFromLanguage = translatedFromLanguage { - self.translatedInfoLabel.text = L10n.Common.Controls.Status.Translation.translatedFrom( + let label = L10n.Common.Controls.Status.Translation.translatedFrom( Locale.current.localizedString(forIdentifier: translatedFromLanguage) ?? L10n.Common.Controls.Status.Translation.unknownLanguage, translatedUsingProvider ?? L10n.Common.Controls.Status.Translation.unknownProvider ) + self.translatedInfoLabel.text = label + self.translatedInfoView.accessibilityValue = label self.translatedInfoView.isHidden = false } else { self.translatedInfoView.isHidden = true From ab7166017b32a9617abdee63d00aa09d47e90fa3 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Mon, 6 Feb 2023 21:32:50 -0500 Subject: [PATCH 2/5] =?UTF-8?q?Fix=20typo:=20=E2=80=9CShown=20Original?= =?UTF-8?q?=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Localization/StringsConvertor/input/Base.lproj/app.json | 2 +- Localization/app.json | 2 +- .../Sources/MastodonLocalization/Generated/Strings.swift | 4 ++-- .../Resources/Base.lproj/Localizable.strings | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Localization/StringsConvertor/input/Base.lproj/app.json b/Localization/StringsConvertor/input/Base.lproj/app.json index b9603ce25..47890e24f 100644 --- a/Localization/StringsConvertor/input/Base.lproj/app.json +++ b/Localization/StringsConvertor/input/Base.lproj/app.json @@ -186,7 +186,7 @@ "translated_from": "Translated from %s using %s", "unknown_language": "Unknown", "unknown_provider": "Unknown", - "show_original": "Shown Original" + "show_original": "Show Original" }, "media": { "accessibility_label": "%s, attachment %d of %d", diff --git a/Localization/app.json b/Localization/app.json index 3150c0d24..2c25c89e3 100644 --- a/Localization/app.json +++ b/Localization/app.json @@ -186,7 +186,7 @@ "translated_from": "Translated from %s using %s", "unknown_language": "Unknown", "unknown_provider": "Unknown", - "show_original": "Shown Original" + "show_original": "Show Original" }, "media": { "accessibility_label": "%s, attachment %d of %d", diff --git a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift index d78e95231..c2006ec42 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift +++ b/MastodonSDK/Sources/MastodonLocalization/Generated/Strings.swift @@ -391,8 +391,8 @@ public enum L10n { public static let url = L10n.tr("Localizable", "Common.Controls.Status.Tag.Url", fallback: "URL") } public enum Translation { - /// Shown Original - public static let showOriginal = L10n.tr("Localizable", "Common.Controls.Status.Translation.ShowOriginal", fallback: "Shown Original") + /// Show Original + public static let showOriginal = L10n.tr("Localizable", "Common.Controls.Status.Translation.ShowOriginal", fallback: "Show Original") /// Translated from %@ using %@ public static func translatedFrom(_ p1: Any, _ p2: Any) -> String { return L10n.tr("Localizable", "Common.Controls.Status.Translation.TranslatedFrom", String(describing: p1), String(describing: p2), fallback: "Translated from %@ using %@") diff --git a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings index b795752ed..5421a6cdd 100644 --- a/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings +++ b/MastodonSDK/Sources/MastodonLocalization/Resources/Base.lproj/Localizable.strings @@ -137,7 +137,7 @@ Please check your internet connection."; "Common.Controls.Status.Tag.Mention" = "Mention"; "Common.Controls.Status.Tag.Url" = "URL"; "Common.Controls.Status.TapToReveal" = "Tap to reveal"; -"Common.Controls.Status.Translation.ShowOriginal" = "Shown Original"; +"Common.Controls.Status.Translation.ShowOriginal" = "Show Original"; "Common.Controls.Status.Translation.TranslatedFrom" = "Translated from %@ using %@"; "Common.Controls.Status.Translation.UnknownLanguage" = "Unknown"; "Common.Controls.Status.Translation.UnknownProvider" = "Unknown"; From 97f51329776c8addd02ce323c26754665962f280 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Mon, 6 Feb 2023 21:39:22 -0500 Subject: [PATCH 3/5] =?UTF-8?q?Add=20a=20=E2=80=9CShow=20Original=E2=80=9D?= =?UTF-8?q?=20accessibility=20action=20to=20statuses=20when=20relevant?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Sources/MastodonUI/View/Content/StatusView.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index e51ccfedf..aaa59f951 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -628,10 +628,19 @@ extension StatusView { get { (contentMetaText.textView.accessibilityCustomActions ?? []) + toolbarActions + + (hideTranslationAction.map { [$0] } ?? []) + (authorView.accessibilityCustomActions ?? []) } set { } } + + private var hideTranslationAction: UIAccessibilityCustomAction? { + guard viewModel.translatedFromLanguage != nil else { return nil } + return UIAccessibilityCustomAction(name: L10n.Common.Controls.Status.Translation.showOriginal) { [weak self] _ in + self?.revertTranslation() + return true + } + } } // MARK: - AdaptiveContainerView From 32fbbc37c17084c3de5a5bc044dfbf3e57f3c9a5 Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Mon, 6 Feb 2023 21:47:58 -0500 Subject: [PATCH 4/5] Move setupTranslationIndicator into StatusView.ViewModel --- .../View/Content/StatusView+ViewModel.swift | 38 +++++++++++++++++- .../MastodonUI/View/Content/StatusView.swift | 40 +------------------ 2 files changed, 38 insertions(+), 40 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index b4430dd8e..a3b2023a5 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -356,6 +356,18 @@ extension StatusView.ViewModel { statusView.authorView.contentSensitiveeToggleButton.setImage(image, for: .normal) } .store(in: &disposeBag) + + $isCurrentlyTranslating + .receive(on: DispatchQueue.main) + .sink { isTranslating in + switch isTranslating { + case true: + statusView.isTranslatingLoadingView.startAnimating() + case false: + statusView.isTranslatingLoadingView.stopAnimating() + } + } + .store(in: &disposeBag) } private func bindMedia(statusView: StatusView) { @@ -820,7 +832,31 @@ extension StatusView.ViewModel { } .assign(to: \.toolbarActions, on: statusView) .store(in: &disposeBag) - + + let translatedFromLabel = Publishers.CombineLatest($translatedFromLanguage, $translatedUsingProvider) + .map { (language, provider) -> String? in + if let language { + return L10n.Common.Controls.Status.Translation.translatedFrom( + Locale.current.localizedString(forIdentifier: language) ?? L10n.Common.Controls.Status.Translation.unknownLanguage, + provider ?? L10n.Common.Controls.Status.Translation.unknownProvider + ) + } + return nil + } + + translatedFromLabel + .receive(on: DispatchQueue.main) + .sink { label in + if let label { + statusView.translatedInfoLabel.text = label + statusView.translatedInfoView.accessibilityValue = label + statusView.translatedInfoView.isHidden = false + } else { + statusView.translatedInfoView.isHidden = true + } + } + .store(in: &disposeBag) + Publishers.CombineLatest3( shortAuthorAccessibilityLabel, contentAccessibilityLabel, diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index aaa59f951..402f1ca42 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -190,7 +190,7 @@ public final class StatusView: UIView { activityIndicatorView.stopAnimating() return activityIndicatorView }() - private let translatedInfoLabel: UILabel = { + let translatedInfoLabel: UILabel = { let label = UILabel() label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .regular)) label.textColor = Asset.Colors.Label.secondary.color @@ -286,7 +286,6 @@ public final class StatusView: UIView { setPollDisplay(isDisplay: false) setFilterHintLabelDisplay(isDisplay: false) setStatusCardControlDisplay(isDisplay: false) - setupTranslationIndicator() } public override init(frame: CGRect) { @@ -753,43 +752,6 @@ extension StatusView: MastodonMenuDelegate { } } -extension StatusView { - func setupTranslationIndicator() { - viewModel.$isCurrentlyTranslating - .receive(on: DispatchQueue.main) - .sink { [weak self] isTranslating in - switch isTranslating { - case true: - self?.isTranslatingLoadingView.startAnimating() - case false: - self?.isTranslatingLoadingView.stopAnimating() - } - } - .store(in: &disposeBag) - - Publishers.CombineLatest( - viewModel.$translatedFromLanguage, - viewModel.$translatedUsingProvider - ) - .receive(on: DispatchQueue.main) - .sink { [weak self] translatedFromLanguage, translatedUsingProvider in - guard let self = self else { return } - if let translatedFromLanguage = translatedFromLanguage { - let label = L10n.Common.Controls.Status.Translation.translatedFrom( - Locale.current.localizedString(forIdentifier: translatedFromLanguage) ?? L10n.Common.Controls.Status.Translation.unknownLanguage, - translatedUsingProvider ?? L10n.Common.Controls.Status.Translation.unknownProvider - ) - self.translatedInfoLabel.text = label - self.translatedInfoView.accessibilityValue = label - self.translatedInfoView.isHidden = false - } else { - self.translatedInfoView.isHidden = true - } - } - .store(in: &disposeBag) - } -} - // MARK: StatusCardControlDelegate extension StatusView: StatusCardControlDelegate { public func statusCardControl(_ statusCardControl: StatusCardControl, didTapURL url: URL) { From 7e9655e903e47a608e53f8becd48ce785f404cdc Mon Sep 17 00:00:00 2001 From: Jed Fox Date: Mon, 6 Feb 2023 21:52:26 -0500 Subject: [PATCH 5/5] =?UTF-8?q?Apply=20=E2=80=9Ctranslated=20from=E2=80=9D?= =?UTF-8?q?=20label=20to=20StatusView=20accessibilityLabel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MastodonUI/View/Content/StatusView+ViewModel.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift index a3b2023a5..4f53ba21a 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView+ViewModel.swift @@ -857,13 +857,14 @@ extension StatusView.ViewModel { } .store(in: &disposeBag) - Publishers.CombineLatest3( + Publishers.CombineLatest4( shortAuthorAccessibilityLabel, contentAccessibilityLabel, + translatedFromLabel, mediaAccessibilityLabel ) - .map { author, content, media in - var labels: [String?] = [content, media] + .map { author, content, translated, media in + var labels: [String?] = [content, translated, media] if statusView.style != .notification { labels.insert(author, at: 0)