// // DataSourceFacade+Profile.swift // Mastodon // // Created by MainasuK on 2022-1-13. // import UIKit import CoreDataStack extension DataSourceFacade { static func coordinateToProfileScene( provider: DataSourceProvider, target: StatusTarget, status: ManagedObjectRecord ) async { let _redirectRecord = await DataSourceFacade.author( managedObjectContext: provider.context.managedObjectContext, status: status, target: target ) guard let redirectRecord = _redirectRecord else { assertionFailure() return } await coordinateToProfileScene( provider: provider, user: redirectRecord ) } @MainActor static func coordinateToProfileScene( provider: DataSourceProvider, user: ManagedObjectRecord ) async { guard let user = user.object(in: provider.context.managedObjectContext) else { assertionFailure() return } let profileViewModel = CachedProfileViewModel( context: provider.context, mastodonUser: user ) provider.coordinator.present( scene: .profile(viewModel: profileViewModel), from: provider, transition: .show ) } } extension DataSourceFacade { static func coordinateToProfileScene( provider: DataSourceProvider, status: ManagedObjectRecord, mention: String, // username, userInfo: [AnyHashable: Any]? ) async { guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return } let domain = authenticationBox.domain let href = userInfo?["href"] as? String guard let url = href.flatMap({ URL(string: $0) }) else { return } let managedObjectContext = provider.context.managedObjectContext let mentions = try? await managedObjectContext.perform { return status.object(in: managedObjectContext)?.mentions ?? [] } guard let mention = mentions?.first(where: { $0.username == mention }) else { await provider.coordinator.present( scene: .safari(url: url), from: provider, transition: .safariPresent(animated: true, completion: nil) ) return } let userID = mention.id let profileViewModel: ProfileViewModel = { // check if self guard userID != authenticationBox.userID else { return MeProfileViewModel(context: provider.context) } let request = MastodonUser.sortedFetchRequest request.fetchLimit = 1 request.predicate = MastodonUser.predicate(domain: domain, id: userID) let _user = provider.context.managedObjectContext.safeFetch(request).first if let user = _user { return CachedProfileViewModel(context: provider.context, mastodonUser: user) } else { return RemoteProfileViewModel(context: provider.context, userID: userID) } }() await provider.coordinator.present( scene: .profile(viewModel: profileViewModel), from: provider, transition: .show ) } } extension DataSourceFacade { struct ProfileActionMenuContext { let isMuting: Bool let isBlocking: Bool let isMyself: Bool let cell: UITableViewCell? let sourceView: UIView? let barButtonItem: UIBarButtonItem? } // @MainActor // static func createProfileActionMenu( // dependency: NeedsDependency, // user: ManagedObjectRecord // ) -> UIMenu { // var children: [UIMenuElement] = [] // let name = mastodonUser.displayNameWithFallback // // if let shareUser = shareUser { // let shareAction = UIAction( // title: L10n.Common.Controls.Actions.shareUser(name), // image: UIImage(systemName: "square.and.arrow.up"), // identifier: nil, // discoverabilityTitle: nil, // attributes: [], // state: .off // ) { [weak provider, weak sourceView, weak barButtonItem] _ in // guard let provider = provider else { return } // let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: shareUser, dependency: provider) // provider.coordinator.present( // scene: .activityViewController( // activityViewController: activityViewController, // sourceView: sourceView, // barButtonItem: barButtonItem // ), // from: provider, // transition: .activityViewControllerPresent(animated: true, completion: nil) // ) // } // children.append(shareAction) // } // // if let shareStatus = shareStatus { // let shareAction = UIAction( // title: L10n.Common.Controls.Actions.sharePost, // image: UIImage(systemName: "square.and.arrow.up"), // identifier: nil, // discoverabilityTitle: nil, // attributes: [], // state: .off // ) { [weak provider, weak sourceView, weak barButtonItem] _ in // guard let provider = provider else { return } // let activityViewController = createActivityViewControllerForMastodonUser(status: shareStatus, dependency: provider) // provider.coordinator.present( // scene: .activityViewController( // activityViewController: activityViewController, // sourceView: sourceView, // barButtonItem: barButtonItem // ), // from: provider, // transition: .activityViewControllerPresent(animated: true, completion: nil) // ) // } // children.append(shareAction) // } // // if !isMyself { // // mute // let muteAction = UIAction( // title: isMuting ? L10n.Common.Controls.Friendship.unmuteUser(name) : L10n.Common.Controls.Friendship.mute, // image: isMuting ? UIImage(systemName: "speaker") : UIImage(systemName: "speaker.slash"), // discoverabilityTitle: isMuting ? nil : L10n.Common.Controls.Friendship.muteUser(name), // attributes: isMuting ? [] : .destructive, // state: .off // ) { [weak provider, weak cell] _ in // guard let provider = provider else { return } // // UserProviderFacade.toggleUserMuteRelationship( // provider: provider, // cell: cell // ) // .sink { _ in // // do nothing // } receiveValue: { _ in // // do nothing // } // .store(in: &provider.context.disposeBag) // } // if isMuting { // children.append(muteAction) // } else { // let muteMenu = UIMenu(title: L10n.Common.Controls.Friendship.muteUser(name), image: UIImage(systemName: "speaker.slash"), options: [], children: [muteAction]) // children.append(muteMenu) // } // } // // if !isMyself { // // block // let blockAction = UIAction( // title: isBlocking ? L10n.Common.Controls.Friendship.unblockUser(name) : L10n.Common.Controls.Friendship.block, // image: isBlocking ? UIImage(systemName: "hand.raised.slash") : UIImage(systemName: "hand.raised"), // discoverabilityTitle: isBlocking ? nil : L10n.Common.Controls.Friendship.blockUser(name), // attributes: isBlocking ? [] : .destructive, // state: .off // ) { [weak provider, weak cell] _ in // guard let provider = provider else { return } // // UserProviderFacade.toggleUserBlockRelationship( // provider: provider, // cell: cell // ) // .sink { _ in // // do nothing // } receiveValue: { _ in // // do nothing // } // .store(in: &provider.context.disposeBag) // } // if isBlocking { // children.append(blockAction) // } else { // let blockMenu = UIMenu(title: L10n.Common.Controls.Friendship.blockUser(name), image: UIImage(systemName: "hand.raised"), options: [], children: [blockAction]) // children.append(blockMenu) // } // } // // if !isMyself { // let reportAction = UIAction( // title: L10n.Common.Controls.Actions.reportUser(name), // image: UIImage(systemName: "flag"), // identifier: nil, // discoverabilityTitle: nil, // attributes: [], // state: .off // ) { [weak provider] _ in // guard let provider = provider else { return } // guard let authenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { // return // } // let viewModel = ReportViewModel( // context: provider.context, // domain: authenticationBox.domain, // user: mastodonUser, // status: nil // ) // provider.coordinator.present( // scene: .report(viewModel: viewModel), // from: provider, // transition: .modal(animated: true, completion: nil) // ) // } // children.append(reportAction) // } // // if !isInSameDomain { // if isDomainBlocking { // let unblockDomainAction = UIAction( // title: L10n.Common.Controls.Actions.unblockDomain(mastodonUser.domainFromAcct), // image: UIImage(systemName: "nosign"), // identifier: nil, // discoverabilityTitle: nil, // attributes: [], // state: .off // ) { [weak provider, weak cell] _ in // guard let provider = provider else { return } // provider.context.blockDomainService.unblockDomain(userProvider: provider, cell: cell) // } // children.append(unblockDomainAction) // } else { // let blockDomainAction = UIAction( // title: L10n.Common.Controls.Actions.blockDomain(mastodonUser.domainFromAcct), // image: UIImage(systemName: "nosign"), // identifier: nil, // discoverabilityTitle: nil, // attributes: [], // state: .off // ) { [weak provider, weak cell] _ in // guard let provider = provider else { return } // // let alertController = UIAlertController(title: L10n.Common.Alerts.BlockDomain.title(mastodonUser.domainFromAcct), message: nil, preferredStyle: .alert) // let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in } // alertController.addAction(cancelAction) // let blockDomainAction = UIAlertAction(title: L10n.Common.Alerts.BlockDomain.blockEntireDomain, style: .destructive) { [weak provider, weak cell] _ in // guard let provider = provider else { return } // provider.context.blockDomainService.blockDomain(userProvider: provider, cell: cell) // } // alertController.addAction(blockDomainAction) // provider.present(alertController, animated: true, completion: nil) // } // children.append(blockDomainAction) // } // } // // if let status = shareStatus, isMyself { // let deleteAction = UIAction( // title: L10n.Common.Controls.Actions.delete, // image: UIImage(systemName: "delete.left"), // identifier: nil, // discoverabilityTitle: nil, // attributes: [.destructive], // state: .off // ) { [weak provider] _ in // guard let provider = provider else { return } // // let alertController = UIAlertController(title: L10n.Common.Alerts.DeletePost.title, message: nil, preferredStyle: .alert) // let cancelAction = UIAlertAction(title: L10n.Common.Controls.Actions.cancel, style: .default) { _ in } // alertController.addAction(cancelAction) // let deleteAction = UIAlertAction(title: L10n.Common.Alerts.DeletePost.delete, style: .destructive) { [weak provider] _ in // guard let provider = provider else { return } // guard let activeMastodonAuthenticationBox = provider.context.authenticationService.activeMastodonAuthenticationBox.value else { return } // provider.context.apiService.deleteStatus( // domain: activeMastodonAuthenticationBox.domain, // statusID: status.id, // authorizationBox: activeMastodonAuthenticationBox // ) // .sink { _ in // // do nothing // } receiveValue: { _ in // // do nothing // } // .store(in: &provider.context.disposeBag) // } // alertController.addAction(deleteAction) // provider.present(alertController, animated: true, completion: nil) // } // children.append(deleteAction) // } // // return UIMenu(title: "", options: [], children: children) // } static func createActivityViewController( dependency: NeedsDependency, user: ManagedObjectRecord ) async throws -> UIActivityViewController? { let managedObjectContext = dependency.context.managedObjectContext let activityItems: [Any] = try await managedObjectContext.perform { guard let user = user.object(in: managedObjectContext) else { return [] } return user.activityItems } guard !activityItems.isEmpty else { assertionFailure() return nil } let activityViewController = await UIActivityViewController( activityItems: activityItems, applicationActivities: [SafariActivity(sceneCoordinator: dependency.coordinator)] ) return activityViewController } static func createActivityViewControllerForMastodonUser(status: Status, dependency: NeedsDependency) -> UIActivityViewController { let activityViewController = UIActivityViewController( activityItems: status.activityItems, applicationActivities: [SafariActivity(sceneCoordinator: dependency.coordinator)] ) return activityViewController } }