feat: add share action for profile scene
This commit is contained in:
parent
672db8f3c2
commit
3b03ed63ce
|
@ -44,6 +44,8 @@
|
|||
"sign_up": "Sign Up",
|
||||
"see_more": "See More",
|
||||
"preview": "Preview",
|
||||
"share": "Share",
|
||||
"share_user": "Share %s",
|
||||
"open_in_safari": "Open in Safari"
|
||||
},
|
||||
"status": {
|
||||
|
@ -73,6 +75,7 @@
|
|||
"pending": "Pending",
|
||||
"block": "Block",
|
||||
"block_user": "Block %s",
|
||||
"block_domain": "Block %s",
|
||||
"unblock": "Unblock",
|
||||
"unblock_user": "Unblock %s",
|
||||
"blocked": "Blocked",
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
DB71FD5225F8CCAA00512AE1 /* APIService+Status.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */; };
|
||||
DB72601C25E36A2100235243 /* MastodonServerRulesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */; };
|
||||
DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */; };
|
||||
DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB73B48F261F030A002E9E9F /* SafariActivity.swift */; };
|
||||
DB789A0B25F9F2950071ACA0 /* ComposeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */; };
|
||||
DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */; };
|
||||
DB789A1C25F9F76A0071ACA0 /* ComposeStatusContentCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB789A1B25F9F76A0071ACA0 /* ComposeStatusContentCollectionViewCell.swift */; };
|
||||
|
@ -595,6 +596,7 @@
|
|||
DB71FD5125F8CCAA00512AE1 /* APIService+Status.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Status.swift"; sourceTree = "<group>"; };
|
||||
DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = "<group>"; };
|
||||
DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = "<group>"; };
|
||||
DB73B48F261F030A002E9E9F /* SafariActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SafariActivity.swift; sourceTree = "<group>"; };
|
||||
DB789A0A25F9F2950071ACA0 /* ComposeViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewController.swift; sourceTree = "<group>"; };
|
||||
DB789A1125F9F2CC0071ACA0 /* ComposeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeViewModel.swift; sourceTree = "<group>"; };
|
||||
DB789A1B25F9F76A0071ACA0 /* ComposeStatusContentCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusContentCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
|
@ -1142,8 +1144,8 @@
|
|||
DB084B5125CBC56300F898ED /* CoreDataStack */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB45FAE225CA7181005A8AC7 /* MastodonUser.swift */,
|
||||
DB084B5625CBC56C00F898ED /* Status.swift */,
|
||||
DB45FAE225CA7181005A8AC7 /* MastodonUser.swift */,
|
||||
DB9D6C3725E508BE0051B173 /* Attachment.swift */,
|
||||
);
|
||||
path = CoreDataStack;
|
||||
|
@ -1233,6 +1235,7 @@
|
|||
DB9E0D6925EDFFE500CFDD76 /* Helper */,
|
||||
DB8AF56225C138BC002E6C99 /* Extension */,
|
||||
2D5A3D0125CF8640002347D6 /* Vender */,
|
||||
DB73B495261F030D002E9E9F /* Activity */,
|
||||
DB5086CB25CC0DB400C2C187 /* Preference */,
|
||||
2D69CFF225CA9E2200C3A1B2 /* Protocol */,
|
||||
DB98338425C945ED00AD9700 /* Generated */,
|
||||
|
@ -1372,6 +1375,14 @@
|
|||
path = ServerRules;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB73B495261F030D002E9E9F /* Activity */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
DB73B48F261F030A002E9E9F /* SafariActivity.swift */,
|
||||
);
|
||||
path = Activity;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
DB789A1025F9F29B0071ACA0 /* Compose */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2219,6 +2230,7 @@
|
|||
5DDDF1A92617489F00311060 /* Mastodon+Entity+History.swift in Sources */,
|
||||
DB59F11825EFA35B001F1DAB /* StripProgressView.swift in Sources */,
|
||||
DB59F10425EF5EBC001F1DAB /* TableViewCellHeightCacheableContainer.swift in Sources */,
|
||||
DB73B490261F030A002E9E9F /* SafariActivity.swift in Sources */,
|
||||
DB9A48962603685D008B817C /* MastodonAttachmentService+UploadState.swift in Sources */,
|
||||
DB66728C25F9F8DC00D60309 /* ComposeViewModel+Diffable.swift in Sources */,
|
||||
DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */,
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
//
|
||||
// SafariActivity.swift
|
||||
// Mastodon
|
||||
//
|
||||
// Created by MainasuK Cirno on 2021-4-8.
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import SafariServices
|
||||
|
||||
final class SafariActivity: UIActivity {
|
||||
|
||||
weak var sceneCoordinator: SceneCoordinator?
|
||||
var url: NSURL?
|
||||
|
||||
init(sceneCoordinator: SceneCoordinator) {
|
||||
self.sceneCoordinator = sceneCoordinator
|
||||
}
|
||||
|
||||
override var activityType: UIActivity.ActivityType? {
|
||||
return UIActivity.ActivityType("org.joinmastodon.Mastodon.safari-activity")
|
||||
}
|
||||
|
||||
override var activityTitle: String? {
|
||||
return L10n.Common.Controls.Actions.openInSafari
|
||||
}
|
||||
|
||||
override var activityImage: UIImage? {
|
||||
return UIImage(systemName: "safari")
|
||||
}
|
||||
|
||||
override func canPerform(withActivityItems activityItems: [Any]) -> Bool {
|
||||
for item in activityItems {
|
||||
guard let _ = item as? NSURL, sceneCoordinator != nil else { continue }
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
override func prepare(withActivityItems activityItems: [Any]) {
|
||||
for item in activityItems {
|
||||
guard let url = item as? NSURL else { continue }
|
||||
self.url = url
|
||||
}
|
||||
}
|
||||
|
||||
override var activityViewController: UIViewController? {
|
||||
return nil
|
||||
}
|
||||
|
||||
override func perform() {
|
||||
guard let url = url else {
|
||||
activityDidFinish(false)
|
||||
return
|
||||
}
|
||||
|
||||
sceneCoordinator?.present(scene: .safari(url: url as URL), from: nil, transition: .safariPresent(animated: true, completion: nil))
|
||||
activityDidFinish(true)
|
||||
}
|
||||
|
||||
}
|
|
@ -33,8 +33,8 @@ extension SceneCoordinator {
|
|||
case custom(transitioningDelegate: UIViewControllerTransitioningDelegate)
|
||||
case customPush
|
||||
case safariPresent(animated: Bool, completion: (() -> Void)? = nil)
|
||||
case activityViewControllerPresent(animated: Bool, completion: (() -> Void)? = nil)
|
||||
case alertController(animated: Bool, completion: (() -> Void)? = nil)
|
||||
case activityViewControllerPresent(animated: Bool, completion: (() -> Void)? = nil)
|
||||
}
|
||||
|
||||
enum Scene {
|
||||
|
@ -59,8 +59,9 @@ extension SceneCoordinator {
|
|||
case favorite(viewModel: FavoriteViewModel)
|
||||
|
||||
// misc
|
||||
case alertController(alertController: UIAlertController)
|
||||
case safari(url: URL)
|
||||
case alertController(alertController: UIAlertController)
|
||||
case activityViewController(activityViewController: UIActivityViewController, sourceView: UIView?, barButtonItem: UIBarButtonItem?)
|
||||
|
||||
#if DEBUG
|
||||
case publicTimeline
|
||||
|
@ -170,11 +171,11 @@ extension SceneCoordinator {
|
|||
viewController.modalPresentationCapturesStatusBarAppearance = true
|
||||
presentingViewController.present(viewController, animated: animated, completion: completion)
|
||||
|
||||
case .activityViewControllerPresent(let animated, let completion):
|
||||
case .alertController(let animated, let completion):
|
||||
viewController.modalPresentationCapturesStatusBarAppearance = true
|
||||
presentingViewController.present(viewController, animated: animated, completion: completion)
|
||||
|
||||
case .alertController(let animated, let completion):
|
||||
case .activityViewControllerPresent(let animated, let completion):
|
||||
viewController.modalPresentationCapturesStatusBarAppearance = true
|
||||
presentingViewController.present(viewController, animated: animated, completion: completion)
|
||||
}
|
||||
|
@ -237,6 +238,12 @@ private extension SceneCoordinator {
|
|||
let _viewController = FavoriteViewController()
|
||||
_viewController.viewModel = viewModel
|
||||
viewController = _viewController
|
||||
case .safari(let url):
|
||||
guard let scheme = url.scheme?.lowercased(),
|
||||
scheme == "http" || scheme == "https" else {
|
||||
return nil
|
||||
}
|
||||
viewController = SFSafariViewController(url: url)
|
||||
case .alertController(let alertController):
|
||||
if let popoverPresentationController = alertController.popoverPresentationController {
|
||||
assert(
|
||||
|
@ -246,12 +253,10 @@ private extension SceneCoordinator {
|
|||
)
|
||||
}
|
||||
viewController = alertController
|
||||
case .safari(let url):
|
||||
guard let scheme = url.scheme?.lowercased(),
|
||||
scheme == "http" || scheme == "https" else {
|
||||
return nil
|
||||
}
|
||||
viewController = SFSafariViewController(url: url)
|
||||
case .activityViewController(let activityViewController, let sourceView, let barButtonItem):
|
||||
activityViewController.popoverPresentationController?.sourceView = sourceView
|
||||
activityViewController.popoverPresentationController?.barButtonItem = barButtonItem
|
||||
viewController = activityViewController
|
||||
#if DEBUG
|
||||
case .publicTimeline:
|
||||
let _viewController = PublicTimelineViewController()
|
||||
|
|
|
@ -63,3 +63,21 @@ extension MastodonUser {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
extension MastodonUser {
|
||||
|
||||
var profileURL: URL {
|
||||
if let urlString = self.url,
|
||||
let url = URL(string: urlString) {
|
||||
return url
|
||||
} else {
|
||||
return URL(string: "https://\(self.domain)/@\(username)")!
|
||||
}
|
||||
}
|
||||
|
||||
var activityItems: [Any] {
|
||||
var items: [Any] = []
|
||||
items.append(profileURL)
|
||||
return items
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,6 +78,12 @@ internal enum L10n {
|
|||
internal static let savePhoto = L10n.tr("Localizable", "Common.Controls.Actions.SavePhoto")
|
||||
/// See More
|
||||
internal static let seeMore = L10n.tr("Localizable", "Common.Controls.Actions.SeeMore")
|
||||
/// Share
|
||||
internal static let share = L10n.tr("Localizable", "Common.Controls.Actions.Share")
|
||||
/// Share %@
|
||||
internal static func shareUser(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Actions.ShareUser", String(describing: p1))
|
||||
}
|
||||
/// Sign In
|
||||
internal static let signIn = L10n.tr("Localizable", "Common.Controls.Actions.SignIn")
|
||||
/// Sign Up
|
||||
|
@ -90,6 +96,10 @@ internal enum L10n {
|
|||
internal enum Firendship {
|
||||
/// Block
|
||||
internal static let block = L10n.tr("Localizable", "Common.Controls.Firendship.Block")
|
||||
/// Block %@
|
||||
internal static func blockDomain(_ p1: Any) -> String {
|
||||
return L10n.tr("Localizable", "Common.Controls.Firendship.BlockDomain", String(describing: p1))
|
||||
}
|
||||
/// Blocked
|
||||
internal static let blocked = L10n.tr("Localizable", "Common.Controls.Firendship.Blocked")
|
||||
/// Block %@
|
||||
|
|
|
@ -139,7 +139,10 @@ extension UserProviderFacade {
|
|||
for mastodonUser: MastodonUser,
|
||||
isMuting: Bool,
|
||||
isBlocking: Bool,
|
||||
provider: UserProvider
|
||||
needsShareAction: Bool,
|
||||
provider: UserProvider,
|
||||
sourceView: UIView?,
|
||||
barButtonItem: UIBarButtonItem?
|
||||
) -> UIMenu {
|
||||
var children: [UIMenuElement] = []
|
||||
let name = mastodonUser.displayNameWithFallback
|
||||
|
@ -198,7 +201,32 @@ extension UserProviderFacade {
|
|||
children.append(blockMenu)
|
||||
}
|
||||
|
||||
if needsShareAction {
|
||||
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] _ in
|
||||
guard let provider = provider else { return }
|
||||
let activityViewController = createActivityViewControllerForMastodonUser(mastodonUser: mastodonUser, dependency: provider)
|
||||
provider.coordinator.present(
|
||||
scene: .activityViewController(
|
||||
activityViewController: activityViewController,
|
||||
sourceView: sourceView,
|
||||
barButtonItem: barButtonItem
|
||||
),
|
||||
from: provider,
|
||||
transition: .activityViewControllerPresent(animated: true, completion: nil)
|
||||
)
|
||||
}
|
||||
children.append(shareAction)
|
||||
}
|
||||
|
||||
return UIMenu(title: "", options: [], children: children)
|
||||
}
|
||||
|
||||
static func createActivityViewControllerForMastodonUser(mastodonUser: MastodonUser, dependency: NeedsDependency) -> UIActivityViewController {
|
||||
let activityViewController = UIActivityViewController(
|
||||
activityItems: mastodonUser.activityItems,
|
||||
applicationActivities: [SafariActivity(sceneCoordinator: dependency.coordinator)]
|
||||
)
|
||||
return activityViewController
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,11 +24,14 @@ Please check your internet connection.";
|
|||
"Common.Controls.Actions.Save" = "Save";
|
||||
"Common.Controls.Actions.SavePhoto" = "Save photo";
|
||||
"Common.Controls.Actions.SeeMore" = "See More";
|
||||
"Common.Controls.Actions.Share" = "Share";
|
||||
"Common.Controls.Actions.ShareUser" = "Share %@";
|
||||
"Common.Controls.Actions.SignIn" = "Sign In";
|
||||
"Common.Controls.Actions.SignUp" = "Sign Up";
|
||||
"Common.Controls.Actions.TakePhoto" = "Take photo";
|
||||
"Common.Controls.Actions.TryAgain" = "Try Again";
|
||||
"Common.Controls.Firendship.Block" = "Block";
|
||||
"Common.Controls.Firendship.BlockDomain" = "Block %@";
|
||||
"Common.Controls.Firendship.BlockUser" = "Block %@";
|
||||
"Common.Controls.Firendship.Blocked" = "Blocked";
|
||||
"Common.Controls.Firendship.EditInfo" = "Edit info";
|
||||
|
|
|
@ -325,7 +325,8 @@ extension ProfileViewController {
|
|||
}
|
||||
let isMuting = relationshipActionOptionSet.contains(.muting)
|
||||
let isBlocking = relationshipActionOptionSet.contains(.blocking)
|
||||
self.moreMenuBarButtonItem.menu = UserProviderFacade.createProfileActionMenu(for: mastodonUser, isMuting: isMuting, isBlocking: isBlocking, provider: self)
|
||||
let needsShareAction = self.viewModel.isMeBarButtonItemsHidden.value
|
||||
self.moreMenuBarButtonItem.menu = UserProviderFacade.createProfileActionMenu(for: mastodonUser, isMuting: isMuting, isBlocking: isBlocking, needsShareAction: needsShareAction, provider: self, sourceView: nil, barButtonItem: self.moreMenuBarButtonItem)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
viewModel.isRelationshipActionButtonHidden
|
||||
|
@ -446,6 +447,17 @@ extension ProfileViewController {
|
|||
|
||||
@objc private func shareBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
||||
guard let mastodonUser = viewModel.mastodonUser.value else { return }
|
||||
let activityViewController = UserProviderFacade.createActivityViewControllerForMastodonUser(mastodonUser: mastodonUser, dependency: self)
|
||||
coordinator.present(
|
||||
scene: .activityViewController(
|
||||
activityViewController: activityViewController,
|
||||
sourceView: nil,
|
||||
barButtonItem: sender
|
||||
),
|
||||
from: self,
|
||||
transition: .activityViewControllerPresent(animated: true, completion: nil)
|
||||
)
|
||||
}
|
||||
|
||||
@objc private func favoriteBarButtonItemPressed(_ sender: UIBarButtonItem) {
|
||||
|
|
Loading…
Reference in New Issue