feat: Implement status translation info footer and reversion

This commit is contained in:
Marcus Kida 2022-12-07 15:41:33 +01:00
parent ac76e7f435
commit 1020ca531a
No known key found for this signature in database
GPG Key ID: 19FF64E08013CA40
6 changed files with 76 additions and 31 deletions

View File

@ -88,7 +88,7 @@ extension StatusTableViewCell {
.store(in: &_disposeBag)
statusView.viewModel
.$isTranslated
.$translatedFromLanguage
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] _ in
self?.invalidateIntrinsicContentSize()

View File

@ -83,7 +83,7 @@ extension StatusThreadRootTableViewCell {
statusView.contentMetaText.textView.isSelectable = true
statusView.viewModel
.$isTranslated
.$translatedFromLanguage
.receive(on: DispatchQueue.main)
.sink(receiveValue: { [weak self] _ in
self?.invalidateIntrinsicContentSize()

View File

@ -55,18 +55,13 @@ extension StatusView {
configurePoll(status: status)
configureToolbar(status: status)
configureFilter(status: status)
status.$translatedContent
viewModel.originalStatus = status
[
status.$translatedContent,
status.reblog?.$translatedContent
].compactMap { $0 }
.last?
.receive(on: DispatchQueue.main)
.compactMap { $0 }
.sink { [weak self] _ in
self?.configureTranslated(status: status)
}
.store(in: &disposeBag)
status.reblog?.$translatedContent
.receive(on: DispatchQueue.main)
.compactMap { $0 }
.sink { [weak self] _ in
self?.configureTranslated(status: status)
}
@ -247,6 +242,14 @@ extension StatusView {
.store(in: &disposeBag)
}
func revertTranslation() {
guard let originalStatus = viewModel.originalStatus else { return }
viewModel.translatedFromLanguage = nil
originalStatus.reblog?.translatedContent = nil
originalStatus.translatedContent = nil
configure(status: originalStatus)
}
func configureTranslated(status: Status) {
let translatedContent: String? = {
if let translatedContent = status.reblog?.translatedContent {
@ -267,7 +270,7 @@ extension StatusView {
let content = MastodonContent(content: translatedContent, emojis: status.emojis.asDictionary)
let metaContent = try MastodonMetaContent.convert(document: content)
viewModel.content = metaContent
viewModel.isTranslated = true
viewModel.translatedFromLanguage = status.reblog?.language ?? status.language
} catch {
assertionFailure(error.localizedDescription)
viewModel.content = PlaintextMetaContent(string: "")
@ -301,7 +304,7 @@ extension StatusView {
let content = MastodonContent(content: status.content, emojis: status.emojis.asDictionary)
let metaContent = try MastodonMetaContent.convert(document: content)
viewModel.content = metaContent
viewModel.isTranslated = false
viewModel.translatedFromLanguage = nil
} catch {
assertionFailure(error.localizedDescription)
viewModel.content = PlaintextMetaContent(string: "")

View File

@ -44,7 +44,7 @@ extension StatusView {
@Published public var isMyself = false
@Published public var isMuting = false
@Published public var isBlocking = false
@Published public var isTranslated = false
@Published public var translatedFromLanguage: String?
@Published public var timestamp: Date?
public var timestampFormatter: ((_ date: Date) -> String)?
@ -137,7 +137,7 @@ extension StatusView {
isContentSensitive = false
isMediaSensitive = false
isSensitiveToggled = false
isTranslated = false
translatedFromLanguage = nil
activeFilters = []
filterContext = nil
@ -586,7 +586,7 @@ extension StatusView.ViewModel {
$isBookmark
)
let publishersThree = Publishers.CombineLatest(
$isTranslated,
$translatedFromLanguage,
$language
)
@ -598,7 +598,7 @@ extension StatusView.ViewModel {
.sink { tupleOne, tupleTwo, tupleThree in
let (authorName, isMyself) = tupleOne
let (isMuting, isBlocking, isBookmark) = tupleTwo
let (isTranslated, language) = tupleThree
let (translatedFromLanguage, language) = tupleThree
guard let name = authorName?.string else {
statusView.authorView.menuButton.menu = nil
@ -611,7 +611,7 @@ extension StatusView.ViewModel {
isBlocking: isBlocking,
isMyself: isMyself,
isBookmarking: isBookmark,
isTranslated: isTranslated,
isTranslated: translatedFromLanguage != nil,
statusLanguage: language
)
let (menu, actions) = authorView.setupAuthorMenu(menuContext: menuContext)

View File

@ -176,6 +176,37 @@ public final class StatusView: UIView {
indicatorView.stopAnimating()
return indicatorView
}()
private let translatedInfoLabel = UILabel()
lazy var translatedInfoView: UIView = {
let containerView = UIView()
let revertButton = UIButton()
revertButton.setTitle("Show Original", for: .normal)
revertButton.setTitleColor(Asset.Colors.brand.color, for: .normal)
revertButton.addAction(UIAction { [weak self] _ in
self?.revertTranslation()
}, for: .touchUpInside)
[containerView, translatedInfoLabel, revertButton].forEach {
$0.translatesAutoresizingMaskIntoConstraints = false
}
[translatedInfoLabel, revertButton].forEach {
containerView.addSubview($0)
}
NSLayoutConstraint.activate([
containerView.heightAnchor.constraint(equalToConstant: 20),
translatedInfoLabel.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
translatedInfoLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: 16),
revertButton.centerYAnchor.constraint(equalTo: containerView.centerYAnchor),
revertButton.trailingAnchor.constraint(equalTo: containerView.trailingAnchor, constant: -16)
])
containerView.isHidden = true
return containerView
}()
// toolbar
let actionToolbarAdaptiveMarginContainerView = AdaptiveMarginContainerView()
@ -217,6 +248,7 @@ public final class StatusView: UIView {
setMediaDisplay(isDisplay: false)
setPollDisplay(isDisplay: false)
setFilterHintLabelDisplay(isDisplay: false)
setupTranslationIndicator()
}
public override init(frame: CGRect) {
@ -275,16 +307,6 @@ extension StatusView {
// statusMetricView
statusMetricView.delegate = self
// status translation
viewModel.$isTranslated.sink { [weak self] isTranslated in
guard
let self = self,
let status = self.viewModel.originalStatus
else { return }
self.configureTranslated(status: status)
}
.store(in: &disposeBag)
}
}
@ -448,6 +470,9 @@ extension StatusView.Style {
statusView.filterHintLabel.centerXAnchor.constraint(equalTo: statusView.containerStackView.centerXAnchor),
statusView.filterHintLabel.centerYAnchor.constraint(equalTo: statusView.containerStackView.centerYAnchor),
])
// translated info
statusView.containerStackView.addArrangedSubview(statusView.translatedInfoView)
}
func inline(statusView: StatusView) {
@ -660,6 +685,23 @@ extension StatusView: MastodonMenuDelegate {
}
}
extension StatusView {
func setupTranslationIndicator() {
viewModel.$translatedFromLanguage
.receive(on: DispatchQueue.main)
.sink { [weak self] translatedFromLanguage in
guard let self = self else { return }
if let translatedFromLanguage = translatedFromLanguage {
self.translatedInfoLabel.text = String(format: "Translated from %@", Locale.current.localizedString(forIdentifier: translatedFromLanguage) ?? "Unknown")
self.translatedInfoView.isHidden = false
} else {
self.translatedInfoView.isHidden = true
}
}
.store(in: &disposeBag)
}
}
#if DEBUG
import SwiftUI

View File

@ -129,7 +129,7 @@ extension MastodonMenu {
return deleteAction
case let .translateStatus(context):
let translateAction = BuiltAction(
title: String(format: "Translate from %@", context.language),
title: String(format: "Translate from %@", Locale.current.localizedString(forIdentifier: context.language) ?? "Unknown"),
image: UIImage(systemName: "character.book.closed")
) { [weak delegate] in
guard let delegate = delegate else { return }