2022-01-27 14:23:39 +01:00
|
|
|
//
|
|
|
|
// DataSourceFacade+Status.swift
|
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by MainasuK on 2022-1-17.
|
|
|
|
//
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
import CoreDataStack
|
2022-10-31 21:01:19 +01:00
|
|
|
import Alamofire
|
|
|
|
import AlamofireImage
|
2022-10-08 07:43:06 +02:00
|
|
|
import MastodonCore
|
2022-01-27 14:23:39 +01:00
|
|
|
import MastodonUI
|
|
|
|
import MastodonLocalization
|
2022-10-31 21:01:19 +01:00
|
|
|
import LinkPresentation
|
|
|
|
import UniformTypeIdentifiers
|
2022-01-27 14:23:39 +01:00
|
|
|
|
2022-02-16 12:47:51 +01:00
|
|
|
// Delete
|
2022-01-27 14:23:39 +01:00
|
|
|
extension DataSourceFacade {
|
|
|
|
|
|
|
|
static func responseToDeleteStatus(
|
2022-10-09 14:07:57 +02:00
|
|
|
dependency: NeedsDependency & AuthContextProvider,
|
|
|
|
status: ManagedObjectRecord<Status>
|
2022-01-27 14:23:39 +01:00
|
|
|
) async throws {
|
|
|
|
_ = try await dependency.context.apiService.deleteStatus(
|
|
|
|
status: status,
|
2022-10-09 14:07:57 +02:00
|
|
|
authenticationBox: dependency.authContext.mastodonAuthenticationBox
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-16 12:47:51 +01:00
|
|
|
// Share
|
2022-01-27 14:23:39 +01:00
|
|
|
extension DataSourceFacade {
|
|
|
|
|
|
|
|
@MainActor
|
|
|
|
public static func responseToStatusShareAction(
|
|
|
|
provider: DataSourceProvider,
|
|
|
|
status: ManagedObjectRecord<Status>,
|
|
|
|
button: UIButton
|
|
|
|
) async throws {
|
|
|
|
let activityViewController = try await createActivityViewController(
|
2022-09-15 15:28:40 +02:00
|
|
|
dependency: provider,
|
2022-01-27 14:23:39 +01:00
|
|
|
status: status
|
|
|
|
)
|
2022-11-17 23:02:43 +01:00
|
|
|
_ = provider.coordinator.present(
|
2022-01-27 14:23:39 +01:00
|
|
|
scene: .activityViewController(
|
|
|
|
activityViewController: activityViewController,
|
|
|
|
sourceView: button,
|
|
|
|
barButtonItem: nil
|
|
|
|
),
|
|
|
|
from: provider,
|
|
|
|
transition: .activityViewControllerPresent(animated: true, completion: nil)
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
private static func createActivityViewController(
|
2022-09-15 15:28:40 +02:00
|
|
|
dependency: NeedsDependency,
|
2022-01-27 14:23:39 +01:00
|
|
|
status: ManagedObjectRecord<Status>
|
|
|
|
) async throws -> UIActivityViewController {
|
2022-09-15 15:28:40 +02:00
|
|
|
var activityItems: [Any] = try await dependency.context.managedObjectContext.perform {
|
2022-12-03 19:09:04 +01:00
|
|
|
guard let status = status.object(in: dependency.context.managedObjectContext),
|
|
|
|
let url = URL(string: status.url ?? status.uri)
|
|
|
|
else { return [] }
|
|
|
|
return [
|
|
|
|
URLActivityItemWithMetadata(url: url) { metadata in
|
|
|
|
metadata.title = "\(status.author.displayName) (@\(status.author.acctWithDomain))"
|
|
|
|
metadata.iconProvider = ImageProvider(
|
|
|
|
url: status.author.avatarImageURLWithFallback(domain: status.author.domain),
|
|
|
|
filter: ScaledToSizeFilter(size: CGSize.authorAvatarButtonSize)
|
|
|
|
).itemProvider
|
|
|
|
}
|
|
|
|
] as [Any]
|
2022-01-27 14:23:39 +01:00
|
|
|
}
|
|
|
|
var applicationActivities: [UIActivity] = [
|
2022-09-15 15:28:40 +02:00
|
|
|
SafariActivity(sceneCoordinator: dependency.coordinator), // open URL
|
2022-01-27 14:23:39 +01:00
|
|
|
]
|
|
|
|
|
2022-09-15 15:28:40 +02:00
|
|
|
if let provider = dependency as? ShareActivityProvider {
|
2022-01-27 14:23:39 +01:00
|
|
|
activityItems.append(contentsOf: provider.activities)
|
|
|
|
applicationActivities.append(contentsOf: provider.applicationActivities)
|
|
|
|
}
|
|
|
|
|
|
|
|
let activityViewController = await UIActivityViewController(
|
|
|
|
activityItems: activityItems,
|
|
|
|
applicationActivities: applicationActivities
|
|
|
|
)
|
|
|
|
return activityViewController
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-02-16 12:47:51 +01:00
|
|
|
// ActionToolBar
|
2022-01-27 14:23:39 +01:00
|
|
|
extension DataSourceFacade {
|
|
|
|
@MainActor
|
|
|
|
static func responseToActionToolbar(
|
2022-10-09 14:07:57 +02:00
|
|
|
provider: DataSourceProvider & AuthContextProvider,
|
2022-01-27 14:23:39 +01:00
|
|
|
status: ManagedObjectRecord<Status>,
|
|
|
|
action: ActionToolbarContainer.Action,
|
|
|
|
sender: UIButton
|
|
|
|
) async throws {
|
|
|
|
let managedObjectContext = provider.context.managedObjectContext
|
|
|
|
let _status: ManagedObjectRecord<Status>? = try? await managedObjectContext.perform {
|
|
|
|
guard let object = status.object(in: managedObjectContext) else { return nil }
|
|
|
|
let objectID = (object.reblog ?? object).objectID
|
|
|
|
return .init(objectID: objectID)
|
|
|
|
}
|
|
|
|
guard let status = _status else {
|
|
|
|
assertionFailure()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch action {
|
|
|
|
case .reply:
|
|
|
|
let selectionFeedbackGenerator = UISelectionFeedbackGenerator()
|
|
|
|
selectionFeedbackGenerator.selectionChanged()
|
|
|
|
|
|
|
|
let composeViewModel = ComposeViewModel(
|
|
|
|
context: provider.context,
|
2022-10-10 13:14:52 +02:00
|
|
|
authContext: provider.authContext,
|
2022-12-03 19:25:07 +01:00
|
|
|
destination: .reply(parent: status)
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
2022-10-09 14:07:57 +02:00
|
|
|
_ = provider.coordinator.present(
|
2022-01-27 14:23:39 +01:00
|
|
|
scene: .compose(viewModel: composeViewModel),
|
|
|
|
from: provider,
|
|
|
|
transition: .modal(animated: true, completion: nil)
|
|
|
|
)
|
|
|
|
case .reblog:
|
|
|
|
try await DataSourceFacade.responseToStatusReblogAction(
|
|
|
|
provider: provider,
|
2022-10-09 14:07:57 +02:00
|
|
|
status: status
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
|
|
|
case .like:
|
|
|
|
try await DataSourceFacade.responseToStatusFavoriteAction(
|
|
|
|
provider: provider,
|
2022-10-09 14:07:57 +02:00
|
|
|
status: status
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
2022-07-29 22:31:38 +02:00
|
|
|
case .bookmark:
|
|
|
|
try await DataSourceFacade.responseToStatusBookmarkAction(
|
|
|
|
provider: provider,
|
2022-10-09 14:07:57 +02:00
|
|
|
status: status
|
2022-07-29 22:31:38 +02:00
|
|
|
)
|
2022-01-27 14:23:39 +01:00
|
|
|
case .share:
|
|
|
|
try await DataSourceFacade.responseToStatusShareAction(
|
|
|
|
provider: provider,
|
|
|
|
status: status,
|
|
|
|
button: sender
|
|
|
|
)
|
|
|
|
} // end switch
|
|
|
|
} // end func
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-02-16 12:47:51 +01:00
|
|
|
// menu
|
2022-01-27 14:23:39 +01:00
|
|
|
extension DataSourceFacade {
|
|
|
|
|
|
|
|
struct MenuContext {
|
|
|
|
let author: ManagedObjectRecord<MastodonUser>?
|
|
|
|
let status: ManagedObjectRecord<Status>?
|
|
|
|
let button: UIButton?
|
|
|
|
let barButtonItem: UIBarButtonItem?
|
|
|
|
}
|
|
|
|
|
|
|
|
@MainActor
|
|
|
|
static func responseToMenuAction(
|
2022-10-09 14:07:57 +02:00
|
|
|
dependency: UIViewController & NeedsDependency & AuthContextProvider,
|
2022-01-27 14:23:39 +01:00
|
|
|
action: MastodonMenu.Action,
|
2022-10-09 14:07:57 +02:00
|
|
|
menuContext: MenuContext
|
2022-01-27 14:23:39 +01:00
|
|
|
) async throws {
|
|
|
|
switch action {
|
2022-11-06 09:22:26 +01:00
|
|
|
case .hideReblogs(let actionContext):
|
|
|
|
let title = actionContext.showReblogs ? L10n.Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.title : L10n.Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.title
|
|
|
|
let message = actionContext.showReblogs ? L10n.Scene.Profile.RelationshipActionAlert.ConfirmHideReblogs.message : L10n.Scene.Profile.RelationshipActionAlert.ConfirmShowReblogs.message
|
|
|
|
|
|
|
|
let alertController = UIAlertController(
|
|
|
|
title: title,
|
|
|
|
message: message,
|
|
|
|
preferredStyle: .alert
|
|
|
|
)
|
|
|
|
|
|
|
|
let actionTitle = actionContext.showReblogs ? L10n.Common.Controls.Friendship.hideReblogs : L10n.Common.Controls.Friendship.showReblogs
|
|
|
|
let showHideReblogsAction = UIAlertAction(
|
|
|
|
title: actionTitle,
|
|
|
|
style: .destructive
|
|
|
|
) { [weak dependency] _ in
|
|
|
|
guard let dependency else { return }
|
|
|
|
|
|
|
|
Task {
|
|
|
|
let managedObjectContext = dependency.context.managedObjectContext
|
|
|
|
let _user: ManagedObjectRecord<MastodonUser>? = try? await managedObjectContext.perform {
|
|
|
|
guard let user = menuContext.author?.object(in: managedObjectContext) else { return nil }
|
|
|
|
return ManagedObjectRecord<MastodonUser>(objectID: user.objectID)
|
|
|
|
}
|
|
|
|
|
|
|
|
guard let user = _user else { return }
|
|
|
|
|
|
|
|
try await DataSourceFacade.responseToShowHideReblogAction(
|
|
|
|
dependency: dependency,
|
|
|
|
user: user
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2022-11-04 16:28:14 +01:00
|
|
|
|
2022-11-06 09:22:26 +01:00
|
|
|
alertController.addAction(showHideReblogsAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
|
2022-11-06 09:22:26 +01:00
|
|
|
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel)
|
|
|
|
alertController.addAction(cancelAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
|
2022-11-06 09:22:26 +01:00
|
|
|
dependency.present(alertController, animated: true)
|
2022-01-27 14:23:39 +01:00
|
|
|
case .muteUser(let actionContext):
|
|
|
|
let alertController = UIAlertController(
|
2022-11-02 17:43:58 +01:00
|
|
|
title: actionContext.isMuting ? L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.title : L10n.Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.title,
|
|
|
|
message: actionContext.isMuting ? L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnmuteUser.message(actionContext.name) : L10n.Scene.Profile.RelationshipActionAlert.ConfirmMuteUser.message(actionContext.name),
|
2022-01-27 14:23:39 +01:00
|
|
|
preferredStyle: .alert
|
|
|
|
)
|
|
|
|
let confirmAction = UIAlertAction(
|
|
|
|
title: actionContext.isMuting ? L10n.Common.Controls.Friendship.unmute : L10n.Common.Controls.Friendship.mute,
|
|
|
|
style: .destructive
|
|
|
|
) { [weak dependency] _ in
|
|
|
|
guard let dependency = dependency else { return }
|
|
|
|
Task {
|
|
|
|
let managedObjectContext = dependency.context.managedObjectContext
|
|
|
|
let _user: ManagedObjectRecord<MastodonUser>? = try? await managedObjectContext.perform {
|
|
|
|
guard let user = menuContext.author?.object(in: managedObjectContext) else { return nil }
|
|
|
|
return ManagedObjectRecord<MastodonUser>(objectID: user.objectID)
|
|
|
|
}
|
|
|
|
guard let user = _user else { return }
|
|
|
|
try await DataSourceFacade.responseToUserMuteAction(
|
|
|
|
dependency: dependency,
|
2022-10-09 14:07:57 +02:00
|
|
|
user: user
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
|
|
|
} // end Task
|
|
|
|
}
|
|
|
|
alertController.addAction(confirmAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel)
|
2022-01-27 14:23:39 +01:00
|
|
|
alertController.addAction(cancelAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
dependency.present(alertController, animated: true)
|
2022-01-27 14:23:39 +01:00
|
|
|
case .blockUser(let actionContext):
|
|
|
|
let alertController = UIAlertController(
|
2022-11-02 17:43:58 +01:00
|
|
|
title: actionContext.isBlocking ? L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.title : L10n.Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.title,
|
|
|
|
message: actionContext.isBlocking ? L10n.Scene.Profile.RelationshipActionAlert.ConfirmUnblockUser.message(actionContext.name) : L10n.Scene.Profile.RelationshipActionAlert.ConfirmBlockUser.message(actionContext.name),
|
2022-01-27 14:23:39 +01:00
|
|
|
preferredStyle: .alert
|
|
|
|
)
|
|
|
|
let confirmAction = UIAlertAction(
|
|
|
|
title: actionContext.isBlocking ? L10n.Common.Controls.Friendship.unblock : L10n.Common.Controls.Friendship.block,
|
|
|
|
style: .destructive
|
|
|
|
) { [weak dependency] _ in
|
|
|
|
guard let dependency = dependency else { return }
|
|
|
|
Task {
|
|
|
|
let managedObjectContext = dependency.context.managedObjectContext
|
|
|
|
let _user: ManagedObjectRecord<MastodonUser>? = try? await managedObjectContext.perform {
|
|
|
|
guard let user = menuContext.author?.object(in: managedObjectContext) else { return nil }
|
|
|
|
return ManagedObjectRecord<MastodonUser>(objectID: user.objectID)
|
|
|
|
}
|
|
|
|
guard let user = _user else { return }
|
|
|
|
try await DataSourceFacade.responseToUserBlockAction(
|
|
|
|
dependency: dependency,
|
2022-10-09 14:07:57 +02:00
|
|
|
user: user
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
|
|
|
} // end Task
|
|
|
|
}
|
|
|
|
alertController.addAction(confirmAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel)
|
2022-01-27 14:23:39 +01:00
|
|
|
alertController.addAction(cancelAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
dependency.present(alertController, animated: true)
|
2022-01-27 14:23:39 +01:00
|
|
|
case .reportUser:
|
2022-02-08 05:36:06 +01:00
|
|
|
Task {
|
|
|
|
guard let user = menuContext.author else { return }
|
|
|
|
|
|
|
|
let reportViewModel = ReportViewModel(
|
|
|
|
context: dependency.context,
|
2022-10-09 14:07:57 +02:00
|
|
|
authContext: dependency.authContext,
|
2022-02-08 05:36:06 +01:00
|
|
|
user: user,
|
|
|
|
status: menuContext.status
|
|
|
|
)
|
|
|
|
|
2022-10-09 14:07:57 +02:00
|
|
|
_ = dependency.coordinator.present(
|
2022-02-08 05:36:06 +01:00
|
|
|
scene: .report(viewModel: reportViewModel),
|
|
|
|
from: dependency,
|
|
|
|
transition: .modal(animated: true, completion: nil)
|
|
|
|
)
|
|
|
|
} // end Task
|
|
|
|
|
2022-01-27 14:23:39 +01:00
|
|
|
case .shareUser:
|
|
|
|
guard let user = menuContext.author else {
|
|
|
|
assertionFailure()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
let _activityViewController = try await DataSourceFacade.createActivityViewController(
|
|
|
|
dependency: dependency,
|
|
|
|
user: user
|
|
|
|
)
|
|
|
|
guard let activityViewController = _activityViewController else { return }
|
2022-10-09 14:07:57 +02:00
|
|
|
_ = dependency.coordinator.present(
|
2022-01-27 14:23:39 +01:00
|
|
|
scene: .activityViewController(
|
|
|
|
activityViewController: activityViewController,
|
|
|
|
sourceView: menuContext.button,
|
|
|
|
barButtonItem: menuContext.barButtonItem
|
|
|
|
),
|
|
|
|
from: dependency,
|
|
|
|
transition: .activityViewControllerPresent(animated: true, completion: nil)
|
|
|
|
)
|
2022-09-15 15:28:40 +02:00
|
|
|
case .bookmarkStatus:
|
|
|
|
Task {
|
|
|
|
guard let status = menuContext.status else {
|
|
|
|
assertionFailure()
|
|
|
|
return
|
|
|
|
}
|
|
|
|
try await DataSourceFacade.responseToStatusBookmarkAction(
|
|
|
|
provider: dependency,
|
|
|
|
status: status
|
|
|
|
)
|
|
|
|
} // end Task
|
|
|
|
case .shareStatus:
|
|
|
|
Task {
|
2023-01-09 15:48:56 +01:00
|
|
|
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 }
|
|
|
|
let objectID = (object.reblog ?? object).objectID
|
|
|
|
return .init(objectID: objectID)
|
|
|
|
}) else {
|
2022-09-15 15:28:40 +02:00
|
|
|
assertionFailure()
|
|
|
|
return
|
|
|
|
}
|
2023-01-09 15:48:56 +01:00
|
|
|
|
2022-09-15 15:28:40 +02:00
|
|
|
let activityViewController = try await DataSourceFacade.createActivityViewController(
|
|
|
|
dependency: dependency,
|
|
|
|
status: status
|
|
|
|
)
|
2022-11-17 23:02:43 +01:00
|
|
|
|
|
|
|
_ = dependency.coordinator.present(
|
2022-09-15 15:28:40 +02:00
|
|
|
scene: .activityViewController(
|
|
|
|
activityViewController: activityViewController,
|
|
|
|
sourceView: menuContext.button,
|
|
|
|
barButtonItem: menuContext.barButtonItem
|
|
|
|
),
|
|
|
|
from: dependency,
|
|
|
|
transition: .activityViewControllerPresent(animated: true, completion: nil)
|
|
|
|
)
|
|
|
|
} // end Task
|
2022-01-27 14:23:39 +01:00
|
|
|
case .deleteStatus:
|
|
|
|
let alertController = UIAlertController(
|
2022-11-02 17:43:58 +01:00
|
|
|
title: L10n.Common.Alerts.DeletePost.title,
|
|
|
|
message: L10n.Common.Alerts.DeletePost.message,
|
2022-01-27 14:23:39 +01:00
|
|
|
preferredStyle: .alert
|
|
|
|
)
|
|
|
|
let confirmAction = UIAlertAction(
|
|
|
|
title: L10n.Common.Controls.Actions.delete,
|
|
|
|
style: .destructive
|
|
|
|
) { [weak dependency] _ in
|
|
|
|
guard let dependency = dependency else { return }
|
|
|
|
guard let status = menuContext.status else { return }
|
|
|
|
Task {
|
|
|
|
try await DataSourceFacade.responseToDeleteStatus(
|
|
|
|
dependency: dependency,
|
2022-10-09 14:07:57 +02:00
|
|
|
status: status
|
2022-01-27 14:23:39 +01:00
|
|
|
)
|
|
|
|
} // end Task
|
|
|
|
}
|
|
|
|
alertController.addAction(confirmAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .cancel)
|
2022-01-27 14:23:39 +01:00
|
|
|
alertController.addAction(cancelAction)
|
2022-11-04 16:28:14 +01:00
|
|
|
dependency.present(alertController, animated: true)
|
2022-01-27 14:23:39 +01:00
|
|
|
|
2022-12-09 16:12:13 +01:00
|
|
|
case .translateStatus:
|
2022-11-30 16:38:31 +01:00
|
|
|
guard let status = menuContext.status else { return }
|
2022-12-09 16:12:13 +01:00
|
|
|
do {
|
|
|
|
try await DataSourceFacade.translateStatus(
|
|
|
|
provider: dependency,
|
|
|
|
status: status
|
|
|
|
)
|
|
|
|
} 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))
|
|
|
|
dependency.present(alertController, animated: true)
|
|
|
|
}
|
2022-01-27 14:23:39 +01:00
|
|
|
}
|
|
|
|
} // end func
|
|
|
|
}
|
2022-01-29 10:02:30 +01:00
|
|
|
|
|
|
|
extension DataSourceFacade {
|
|
|
|
|
|
|
|
static func responseToToggleSensitiveAction(
|
|
|
|
dependency: NeedsDependency,
|
|
|
|
status: ManagedObjectRecord<Status>
|
|
|
|
) async throws {
|
2022-02-11 12:27:14 +01:00
|
|
|
try await dependency.context.managedObjectContext.perform {
|
|
|
|
guard let _status = status.object(in: dependency.context.managedObjectContext) else { return }
|
2022-01-29 10:02:30 +01:00
|
|
|
let status = _status.reblog ?? _status
|
2022-04-18 09:33:29 +02:00
|
|
|
status.update(isSensitiveToggled: !status.isSensitiveToggled)
|
2022-01-29 10:02:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2022-11-04 16:28:14 +01:00
|
|
|
|