Merge pull request #1135 from mastodon/nuke_coredata_translations
Don't persist translations
This commit is contained in:
commit
a3733ea578
|
@ -151,7 +151,7 @@ extension DataSourceFacade {
|
|||
|
||||
struct MenuContext {
|
||||
let author: ManagedObjectRecord<MastodonUser>?
|
||||
let status: ManagedObjectRecord<Status>?
|
||||
let statusViewModel: StatusView.ViewModel?
|
||||
let button: UIButton?
|
||||
let barButtonItem: UIBarButtonItem?
|
||||
}
|
||||
|
@ -266,7 +266,7 @@ extension DataSourceFacade {
|
|||
context: dependency.context,
|
||||
authContext: dependency.authContext,
|
||||
user: user,
|
||||
status: menuContext.status
|
||||
status: menuContext.statusViewModel?.originalStatus?.asRecord
|
||||
)
|
||||
|
||||
_ = dependency.coordinator.present(
|
||||
|
@ -297,7 +297,7 @@ extension DataSourceFacade {
|
|||
)
|
||||
case .bookmarkStatus:
|
||||
Task {
|
||||
guard let status = menuContext.status else {
|
||||
guard let status = menuContext.statusViewModel?.originalStatus?.asRecord else {
|
||||
assertionFailure()
|
||||
return
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ extension DataSourceFacade {
|
|||
Task {
|
||||
let managedObjectContext = dependency.context.managedObjectContext
|
||||
guard let status: ManagedObjectRecord<Status> = try? await managedObjectContext.perform(block: {
|
||||
guard let object = menuContext.status?.object(in: managedObjectContext) else { return nil }
|
||||
guard let object = menuContext.statusViewModel?.originalStatus?.asRecord.object(in: managedObjectContext) else { return nil }
|
||||
let objectID = (object.reblog ?? object).objectID
|
||||
return .init(objectID: objectID)
|
||||
}) else {
|
||||
|
@ -344,7 +344,7 @@ extension DataSourceFacade {
|
|||
style: .destructive
|
||||
) { [weak dependency] _ in
|
||||
guard let dependency = dependency else { return }
|
||||
guard let status = menuContext.status else { return }
|
||||
guard let status = menuContext.statusViewModel?.originalStatus?.asRecord else { return }
|
||||
Task {
|
||||
try await DataSourceFacade.responseToDeleteStatus(
|
||||
dependency: dependency,
|
||||
|
@ -358,12 +358,12 @@ extension DataSourceFacade {
|
|||
dependency.present(alertController, animated: true)
|
||||
|
||||
case .translateStatus:
|
||||
guard let status = menuContext.status else { return }
|
||||
guard let status = menuContext.statusViewModel?.originalStatus?.asRecord else { return }
|
||||
|
||||
do {
|
||||
try await DataSourceFacade.translateStatus(
|
||||
provider: dependency,
|
||||
status: status
|
||||
)
|
||||
let translation = try await DataSourceFacade.translateStatus(provider: dependency,status: status)
|
||||
|
||||
menuContext.statusViewModel?.translation = translation
|
||||
} catch TranslationFailure.emptyOrInvalidResponse {
|
||||
let alertController = UIAlertController(title: L10n.Common.Alerts.TranslationFailed.title, message: L10n.Common.Alerts.TranslationFailed.message, preferredStyle: .alert)
|
||||
alertController.addAction(UIAlertAction(title: L10n.Common.Alerts.TranslationFailed.button, style: .default))
|
||||
|
@ -371,7 +371,7 @@ extension DataSourceFacade {
|
|||
}
|
||||
case .editStatus:
|
||||
|
||||
guard let status = menuContext.status?.object(in: dependency.context.managedObjectContext) else { return }
|
||||
guard let status = menuContext.statusViewModel?.originalStatus?.asRecord.object(in: dependency.context.managedObjectContext) else { return }
|
||||
|
||||
let statusSource = try await dependency.context.apiService.getStatusSource(
|
||||
forStatusID: status.id,
|
||||
|
|
|
@ -9,6 +9,7 @@ import UIKit
|
|||
import CoreData
|
||||
import CoreDataStack
|
||||
import MastodonCore
|
||||
import MastodonSDK
|
||||
|
||||
typealias Provider = UIViewController & NeedsDependency & AuthContextProvider
|
||||
|
||||
|
@ -20,26 +21,26 @@ extension DataSourceFacade {
|
|||
public static func translateStatus(
|
||||
provider: Provider,
|
||||
status: ManagedObjectRecord<Status>
|
||||
) async throws {
|
||||
) async throws -> Mastodon.Entity.Translation? {
|
||||
let selectionFeedbackGenerator = await UISelectionFeedbackGenerator()
|
||||
await selectionFeedbackGenerator.selectionChanged()
|
||||
|
||||
guard
|
||||
let status = status.object(in: provider.context.managedObjectContext)
|
||||
else {
|
||||
return
|
||||
return nil
|
||||
}
|
||||
|
||||
if let reblog = status.reblog {
|
||||
try await translateAndApply(provider: provider, status: reblog)
|
||||
return try await translateStatus(provider: provider, status: reblog)
|
||||
} else {
|
||||
try await translateAndApply(provider: provider, status: status)
|
||||
return try await translateStatus(provider: provider, status: status)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension DataSourceFacade {
|
||||
static func translateStatus(provider: Provider, status: Status) async throws -> Status.TranslatedContent? {
|
||||
static func translateStatus(provider: Provider, status: Status) async throws -> Mastodon.Entity.Translation? {
|
||||
do {
|
||||
let value = try await provider.context
|
||||
.apiService
|
||||
|
@ -49,22 +50,12 @@ private extension DataSourceFacade {
|
|||
).value
|
||||
|
||||
guard let content = value.content else {
|
||||
throw TranslationFailure.emptyOrInvalidResponse
|
||||
return nil
|
||||
}
|
||||
|
||||
return Status.TranslatedContent(content: content, provider: value.provider)
|
||||
return value
|
||||
} catch {
|
||||
throw TranslationFailure.emptyOrInvalidResponse
|
||||
}
|
||||
}
|
||||
|
||||
static func translateAndApply(provider: Provider, status: Status) async throws {
|
||||
do {
|
||||
let translated = try await translateStatus(provider: provider, status: status)
|
||||
status.update(translatedContent: translated)
|
||||
} catch {
|
||||
status.update(translatedContent: nil)
|
||||
throw TranslationFailure.emptyOrInvalidResponse
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,7 +44,7 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Aut
|
|||
action: action,
|
||||
menuContext: .init(
|
||||
author: author,
|
||||
status: nil,
|
||||
statusViewModel: nil,
|
||||
button: button,
|
||||
barButtonItem: nil
|
||||
)
|
||||
|
|
|
@ -498,13 +498,23 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let statusViewModel: StatusView.ViewModel?
|
||||
|
||||
if let cell = cell as? StatusTableViewCell {
|
||||
statusViewModel = await cell.statusView.viewModel
|
||||
} else if let cell = cell as? StatusThreadRootTableViewCell {
|
||||
statusViewModel = await cell.statusView.viewModel
|
||||
} else {
|
||||
statusViewModel = nil
|
||||
}
|
||||
|
||||
try await DataSourceFacade.responseToMenuAction(
|
||||
dependency: self,
|
||||
action: action,
|
||||
menuContext: .init(
|
||||
author: author,
|
||||
status: status,
|
||||
statusViewModel: statusViewModel,
|
||||
button: button,
|
||||
barButtonItem: nil
|
||||
)
|
||||
|
|
|
@ -894,7 +894,7 @@ extension ProfileViewController: MastodonMenuDelegate {
|
|||
action: action,
|
||||
menuContext: DataSourceFacade.MenuContext(
|
||||
author: userRecord,
|
||||
status: nil,
|
||||
statusViewModel: nil,
|
||||
button: nil,
|
||||
barButtonItem: self.moreMenuBarButtonItem
|
||||
)
|
||||
|
|
|
@ -90,8 +90,7 @@ extension StatusTableViewCell {
|
|||
}
|
||||
.store(in: &_disposeBag)
|
||||
|
||||
statusView.viewModel
|
||||
.$translatedFromLanguage
|
||||
statusView.viewModel.$translation
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink(receiveValue: { [weak self] _ in
|
||||
self?.invalidateIntrinsicContentSize()
|
||||
|
|
|
@ -76,8 +76,7 @@ extension StatusThreadRootTableViewCell {
|
|||
statusView.contentMetaText.textView.isAccessibilityElement = true
|
||||
statusView.contentMetaText.textView.isSelectable = true
|
||||
|
||||
statusView.viewModel
|
||||
.$translatedFromLanguage
|
||||
statusView.viewModel.$translation
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink(receiveValue: { [weak self] _ in
|
||||
self?.invalidateIntrinsicContentSize()
|
||||
|
|
|
@ -10,17 +10,7 @@ import Foundation
|
|||
|
||||
public final class Status: NSManagedObject {
|
||||
public typealias ID = String
|
||||
|
||||
public class TranslatedContent: NSObject {
|
||||
public let content: String
|
||||
public let provider: String?
|
||||
|
||||
public init(content: String, provider: String?) {
|
||||
self.content = content
|
||||
self.provider = provider
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// sourcery: autoGenerateProperty
|
||||
@NSManaged public private(set) var identifier: ID
|
||||
// sourcery: autoGenerateProperty
|
||||
|
@ -118,9 +108,6 @@ public final class Status: NSManagedObject {
|
|||
@NSManaged public private(set) var deletedAt: Date?
|
||||
// sourcery: autoUpdatableObject
|
||||
@NSManaged public private(set) var revealedAt: Date?
|
||||
|
||||
// sourcery: autoUpdatableObject
|
||||
@NSManaged public private(set) var translatedContent: TranslatedContent?
|
||||
}
|
||||
|
||||
extension Status {
|
||||
|
@ -535,11 +522,6 @@ extension Status: AutoUpdatableObject {
|
|||
self.revealedAt = revealedAt
|
||||
}
|
||||
}
|
||||
public func update(translatedContent: TranslatedContent?) {
|
||||
if self.translatedContent != translatedContent {
|
||||
self.translatedContent = translatedContent
|
||||
}
|
||||
}
|
||||
public func update(attachments: [MastodonAttachment]) {
|
||||
if self.attachments != attachments {
|
||||
self.attachments = attachments
|
||||
|
|
|
@ -49,7 +49,7 @@ extension Instance {
|
|||
version?.majorServerVersion(greaterThanOrEquals: 4) ?? false // following Tags is support beginning with Mastodon v4.0.0
|
||||
}
|
||||
|
||||
var isTranslationEnabled: Bool {
|
||||
public var isTranslationEnabled: Bool {
|
||||
if let configuration = configurationV2 {
|
||||
return configuration.translation?.enabled == true
|
||||
}
|
||||
|
|
|
@ -84,12 +84,14 @@ public struct MastodonAuthentication: Codable, Hashable {
|
|||
}
|
||||
|
||||
public func instance(in context: NSManagedObjectContext) -> Instance? {
|
||||
guard
|
||||
let instanceObjectIdURI = instanceObjectIdURI,
|
||||
let objectID = context.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: instanceObjectIdURI)
|
||||
else { return nil }
|
||||
|
||||
return try? context.existingObject(with: objectID) as? Instance
|
||||
guard let instanceObjectIdURI,
|
||||
let objectID = context.persistentStoreCoordinator?.managedObjectID(forURIRepresentation: instanceObjectIdURI)
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
let instance = try? context.existingObject(with: objectID) as? Instance
|
||||
return instance
|
||||
}
|
||||
|
||||
public func user(in context: NSManagedObjectContext) -> MastodonUser? {
|
||||
|
|
|
@ -19,12 +19,14 @@ extension APIService {
|
|||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Translation> {
|
||||
let domain = authenticationBox.domain
|
||||
let authorization = authenticationBox.userAuthorization
|
||||
let targetLanguage = Bundle.main.preferredLocalizations.first
|
||||
|
||||
let response = try await Mastodon.API.Statuses.translate(
|
||||
session: session,
|
||||
domain: domain,
|
||||
statusID: statusID,
|
||||
authorization: authorization
|
||||
authorization: authorization,
|
||||
targetLanguage: targetLanguage
|
||||
).singleOutput()
|
||||
|
||||
return response
|
||||
|
|
|
@ -16,7 +16,11 @@ extension Mastodon.API.Statuses {
|
|||
.appendingPathComponent(statusID)
|
||||
.appendingPathComponent("translate")
|
||||
}
|
||||
|
||||
|
||||
public struct TranslateQuery: Codable, PostQuery {
|
||||
public let lang: String
|
||||
}
|
||||
|
||||
/// Translate Status
|
||||
///
|
||||
/// Translate a given Status.
|
||||
|
@ -31,11 +35,21 @@ extension Mastodon.API.Statuses {
|
|||
session: URLSession,
|
||||
domain: String,
|
||||
statusID: Mastodon.Entity.Status.ID,
|
||||
authorization: Mastodon.API.OAuth.Authorization?
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Translation>, Error> {
|
||||
authorization: Mastodon.API.OAuth.Authorization?,
|
||||
targetLanguage: String?
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Translation>, Error> {
|
||||
|
||||
let query: TranslateQuery?
|
||||
|
||||
if let targetLanguage {
|
||||
query = TranslateQuery(lang: targetLanguage)
|
||||
} else {
|
||||
query = nil
|
||||
}
|
||||
|
||||
let request = Mastodon.API.post(
|
||||
url: translateEndpointURL(domain: domain, statusID: statusID),
|
||||
query: nil,
|
||||
query: query,
|
||||
authorization: authorization
|
||||
)
|
||||
return session.dataTaskPublisher(for: request)
|
||||
|
|
|
@ -221,38 +221,27 @@ extension NotificationView.ViewModel {
|
|||
)
|
||||
)
|
||||
.sink { [weak self] authorName, isMuting, isBlocking, isMyselfIsTranslatedIsFollowed in
|
||||
guard let name = authorName?.string else {
|
||||
guard let name = authorName?.string, let self, let context = self.context, let authContext = self.authContext else {
|
||||
notificationView.menuButton.menu = nil
|
||||
return
|
||||
}
|
||||
|
||||
let (isMyself, isTranslated, isFollowed) = isMyselfIsTranslatedIsFollowed
|
||||
|
||||
lazy var instanceConfigurationV2: Mastodon.Entity.V2.Instance.Configuration? = {
|
||||
guard
|
||||
let self = self,
|
||||
let context = self.context,
|
||||
let authContext = self.authContext
|
||||
else { return nil }
|
||||
|
||||
var configuration: Mastodon.Entity.V2.Instance.Configuration? = nil
|
||||
context.managedObjectContext.performAndWait {
|
||||
let authentication = authContext.mastodonAuthenticationBox.authentication
|
||||
configuration = authentication.instance(in: context.managedObjectContext)?.configurationV2
|
||||
}
|
||||
return configuration
|
||||
}()
|
||||
|
||||
let menuContext = NotificationView.AuthorMenuContext(
|
||||
|
||||
let (isMyself, isTranslated, isFollowed) = isMyselfIsTranslatedIsFollowed
|
||||
|
||||
let authentication = authContext.mastodonAuthenticationBox.authentication
|
||||
let instance = authentication.instance(in: context.managedObjectContext)
|
||||
let isTranslationEnabled = instance?.isTranslationEnabled ?? false
|
||||
|
||||
let menuContext = NotificationView.AuthorMenuContext(
|
||||
name: name,
|
||||
isMuting: isMuting,
|
||||
isBlocking: isBlocking,
|
||||
isMyself: isMyself,
|
||||
isBookmarking: false, // no bookmark action display for notification item
|
||||
isFollowed: isFollowed,
|
||||
isTranslationEnabled: instanceConfigurationV2?.translation?.enabled == true,
|
||||
isTranslationEnabled: isTranslationEnabled,
|
||||
isTranslated: isTranslated,
|
||||
statusLanguage: ""
|
||||
statusLanguage: nil
|
||||
)
|
||||
let (menu, actions) = notificationView.setupAuthorMenu(menuContext: menuContext)
|
||||
notificationView.menuButton.menu = menu
|
||||
|
|
|
@ -179,7 +179,10 @@ extension StatusAuthorView {
|
|||
postActions.append(.editStatus)
|
||||
}
|
||||
|
||||
if let statusLanguage = menuContext.statusLanguage, menuContext.isTranslationEnabled {
|
||||
if menuContext.isTranslationEnabled,
|
||||
let statusLanguage = menuContext.statusLanguage,
|
||||
let deviceLanguage = Bundle.main.preferredLocalizations.first,
|
||||
deviceLanguage != statusLanguage {
|
||||
if menuContext.isTranslated == false {
|
||||
postActions.append(.translateStatus(.init(language: statusLanguage)))
|
||||
} else {
|
||||
|
|
|
@ -85,13 +85,10 @@ extension StatusView {
|
|||
configureToolbar(status: status)
|
||||
configureFilter(status: status)
|
||||
viewModel.originalStatus = status
|
||||
[
|
||||
status.publisher(for: \.translatedContent),
|
||||
status.reblog?.publisher(for: \.translatedContent)
|
||||
].compactMap { $0 }
|
||||
.last?
|
||||
|
||||
viewModel.$translation
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
.sink { [weak self] translation in
|
||||
self?.configureTranslated(status: status)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
|
@ -293,36 +290,22 @@ extension StatusView {
|
|||
public func revertTranslation() {
|
||||
guard let originalStatus = viewModel.originalStatus else { return }
|
||||
|
||||
viewModel.translatedFromLanguage = nil
|
||||
viewModel.translatedUsingProvider = nil
|
||||
originalStatus.reblog?.update(translatedContent: nil)
|
||||
originalStatus.update(translatedContent: nil)
|
||||
viewModel.translation = nil
|
||||
configure(status: originalStatus)
|
||||
}
|
||||
|
||||
func configureTranslated(status: Status) {
|
||||
let translatedContent: Status.TranslatedContent? = {
|
||||
if let translatedContent = status.reblog?.translatedContent {
|
||||
return translatedContent
|
||||
}
|
||||
return status.translatedContent
|
||||
|
||||
}()
|
||||
|
||||
guard
|
||||
let translatedContent = translatedContent
|
||||
else {
|
||||
guard let translation = viewModel.translation,
|
||||
let translatedContent = translation.content else {
|
||||
viewModel.isCurrentlyTranslating = false
|
||||
return
|
||||
}
|
||||
|
||||
// content
|
||||
do {
|
||||
let content = MastodonContent(content: translatedContent.content, emojis: status.emojis.asDictionary)
|
||||
let content = MastodonContent(content: translatedContent, emojis: status.emojis.asDictionary)
|
||||
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||
viewModel.content = metaContent
|
||||
viewModel.translatedFromLanguage = status.reblog?.language ?? status.language
|
||||
viewModel.translatedUsingProvider = status.reblog?.translatedContent?.provider ?? status.translatedContent?.provider
|
||||
viewModel.isCurrentlyTranslating = false
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
|
@ -342,7 +325,6 @@ extension StatusView {
|
|||
let content = MastodonContent(content: statusEdit.content, emojis: statusEdit.emojis.asDictionary)
|
||||
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||
viewModel.content = metaContent
|
||||
viewModel.translatedFromLanguage = nil
|
||||
viewModel.isCurrentlyTranslating = false
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
|
@ -351,7 +333,7 @@ extension StatusView {
|
|||
}
|
||||
|
||||
private func configureContent(status: Status) {
|
||||
guard status.translatedContent == nil else {
|
||||
guard viewModel.translation == nil else {
|
||||
return configureTranslated(status: status)
|
||||
}
|
||||
|
||||
|
@ -377,7 +359,6 @@ extension StatusView {
|
|||
let content = MastodonContent(content: status.content, emojis: status.emojis.asDictionary)
|
||||
let metaContent = try MastodonMetaContent.convert(document: content)
|
||||
viewModel.content = metaContent
|
||||
viewModel.translatedFromLanguage = nil
|
||||
viewModel.isCurrentlyTranslating = false
|
||||
} catch {
|
||||
assertionFailure(error.localizedDescription)
|
||||
|
|
|
@ -46,8 +46,7 @@ extension StatusView {
|
|||
|
||||
// Translation
|
||||
@Published public var isCurrentlyTranslating = false
|
||||
@Published public var translatedFromLanguage: String?
|
||||
@Published public var translatedUsingProvider: String?
|
||||
@Published public var translation: Mastodon.Entity.Translation? = nil
|
||||
|
||||
@Published public var timestamp: Date?
|
||||
public var timestampFormatter: ((_ date: Date, _ isEdited: Bool) -> String)?
|
||||
|
@ -148,10 +147,9 @@ extension StatusView {
|
|||
isContentSensitive = false
|
||||
isMediaSensitive = false
|
||||
isSensitiveToggled = false
|
||||
translatedFromLanguage = nil
|
||||
translatedUsingProvider = nil
|
||||
isCurrentlyTranslating = false
|
||||
|
||||
translation = nil
|
||||
|
||||
activeFilters = []
|
||||
filterContext = nil
|
||||
}
|
||||
|
@ -657,60 +655,49 @@ extension StatusView.ViewModel {
|
|||
$isFollowed
|
||||
)
|
||||
let publishersThree = Publishers.CombineLatest(
|
||||
$translatedFromLanguage,
|
||||
$translation,
|
||||
$language
|
||||
)
|
||||
|
||||
|
||||
Publishers.CombineLatest3(
|
||||
publisherOne.eraseToAnyPublisher(),
|
||||
publishersTwo.eraseToAnyPublisher(),
|
||||
publishersThree.eraseToAnyPublisher()
|
||||
).eraseToAnyPublisher()
|
||||
.sink { tupleOne, tupleTwo, tupleThree in
|
||||
let (authorName, isMyself) = tupleOne
|
||||
let (isMuting, isBlocking, isBookmark, isFollowed) = tupleTwo
|
||||
let (translatedFromLanguage, language) = tupleThree
|
||||
|
||||
guard let name = authorName?.string else {
|
||||
statusView.authorView.menuButton.menu = nil
|
||||
return
|
||||
}
|
||||
|
||||
lazy var instanceConfigurationV2: Mastodon.Entity.V2.Instance.Configuration? = {
|
||||
guard
|
||||
let context = self.context,
|
||||
let authContext = self.authContext
|
||||
else {
|
||||
return nil
|
||||
.sink { tupleOne, tupleTwo, tupleThree in
|
||||
let (authorName, isMyself) = tupleOne
|
||||
let (isMuting, isBlocking, isBookmark, isFollowed) = tupleTwo
|
||||
let (translatedFromLanguage, language) = tupleThree
|
||||
|
||||
guard let name = authorName?.string, let context = self.context, let authContext = self.authContext else {
|
||||
statusView.authorView.menuButton.menu = nil
|
||||
return
|
||||
}
|
||||
|
||||
let authentication = authContext.mastodonAuthenticationBox.authentication
|
||||
let instance = authentication.instance(in: context.managedObjectContext)
|
||||
let isTranslationEnabled = instance?.isTranslationEnabled ?? false
|
||||
|
||||
let menuContext = StatusAuthorView.AuthorMenuContext(
|
||||
name: name,
|
||||
isMuting: isMuting,
|
||||
isBlocking: isBlocking,
|
||||
isMyself: isMyself,
|
||||
isBookmarking: isBookmark,
|
||||
isFollowed: isFollowed,
|
||||
isTranslationEnabled: isTranslationEnabled,
|
||||
isTranslated: translatedFromLanguage != nil,
|
||||
statusLanguage: language
|
||||
)
|
||||
|
||||
var configuration: Mastodon.Entity.V2.Instance.Configuration? = nil
|
||||
context.managedObjectContext.performAndWait {
|
||||
let authentication = authContext.mastodonAuthenticationBox.authentication
|
||||
configuration = authentication.instance(in: context.managedObjectContext)?.configurationV2
|
||||
}
|
||||
return configuration
|
||||
}()
|
||||
|
||||
let menuContext = StatusAuthorView.AuthorMenuContext(
|
||||
name: name,
|
||||
isMuting: isMuting,
|
||||
isBlocking: isBlocking,
|
||||
isMyself: isMyself,
|
||||
isBookmarking: isBookmark,
|
||||
isFollowed: isFollowed,
|
||||
isTranslationEnabled: instanceConfigurationV2?.translation?.enabled == true,
|
||||
isTranslated: translatedFromLanguage != nil,
|
||||
statusLanguage: language
|
||||
)
|
||||
let (menu, actions) = authorView.setupAuthorMenu(menuContext: menuContext)
|
||||
authorView.menuButton.menu = menu
|
||||
authorView.authorActions = actions
|
||||
authorView.menuButton.showsMenuAsPrimaryAction = true
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
let (menu, actions) = authorView.setupAuthorMenu(menuContext: menuContext)
|
||||
authorView.menuButton.menu = menu
|
||||
authorView.authorActions = actions
|
||||
authorView.menuButton.showsMenuAsPrimaryAction = true
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
|
||||
private func bindFilter(statusView: StatusView) {
|
||||
$isFiltered
|
||||
.sink { isFiltered in
|
||||
|
@ -877,15 +864,20 @@ 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
|
||||
)
|
||||
let translatedFromLabel = $translation
|
||||
.map { translation -> String? in
|
||||
guard let translation else { return nil }
|
||||
|
||||
let provider = translation.provider ?? L10n.Common.Controls.Status.Translation.unknownProvider
|
||||
let sourceLanguage: String
|
||||
|
||||
if let language = translation.sourceLanguage {
|
||||
sourceLanguage = Locale.current.localizedString(forIdentifier: language) ?? L10n.Common.Controls.Status.Translation.unknownLanguage
|
||||
} else {
|
||||
sourceLanguage = L10n.Common.Controls.Status.Translation.unknownLanguage
|
||||
}
|
||||
return nil
|
||||
|
||||
return L10n.Common.Controls.Status.Translation.translatedFrom(sourceLanguage, provider)
|
||||
}
|
||||
|
||||
translatedFromLabel
|
||||
|
|
|
@ -668,7 +668,7 @@ extension StatusView {
|
|||
}
|
||||
|
||||
private var hideTranslationAction: UIAccessibilityCustomAction? {
|
||||
guard viewModel.translatedFromLanguage != nil else { return nil }
|
||||
guard viewModel.translation?.sourceLanguage != nil else { return nil }
|
||||
return UIAccessibilityCustomAction(name: L10n.Common.Controls.Status.Translation.showOriginal) { [weak self] _ in
|
||||
self?.revertTranslation()
|
||||
return true
|
||||
|
|
Loading…
Reference in New Issue