diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 4cfa90add..2693eb55a 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -121,7 +121,7 @@ 855149C8295F1C5F00943D96 /* UIInterfaceOrientationMask.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855149C7295F1C5F00943D96 /* UIInterfaceOrientationMask.swift */; }; 855149CA29606D6400943D96 /* PortraitAlertController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 855149C929606D6400943D96 /* PortraitAlertController.swift */; }; 85904C02293BC0EB0011C817 /* ImageProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C01293BC0EB0011C817 /* ImageProvider.swift */; }; - 85904C04293BC1940011C817 /* URLActivityItemWithMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */; }; + 85904C04293BC1940011C817 /* URLActivityItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85904C03293BC1940011C817 /* URLActivityItem.swift */; }; 85BC11B32932414900E191CD /* AltTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 85BC11B22932414900E191CD /* AltTextViewController.swift */; }; 9E44C7202967AD17004B2A72 /* MastodonSDKDynamic in Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; }; 9E44C7222967AD17004B2A72 /* MastodonSDKDynamic in Embed Frameworks */ = {isa = PBXBuildFile; productRef = 9E44C71F2967AD17004B2A72 /* MastodonSDKDynamic */; settings = {ATTRIBUTES = (CodeSignOnCopy, ); }; }; @@ -761,7 +761,7 @@ 855149C7295F1C5F00943D96 /* UIInterfaceOrientationMask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIInterfaceOrientationMask.swift; sourceTree = ""; }; 855149C929606D6400943D96 /* PortraitAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PortraitAlertController.swift; sourceTree = ""; }; 85904C01293BC0EB0011C817 /* ImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageProvider.swift; sourceTree = ""; }; - 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLActivityItemWithMetadata.swift; sourceTree = ""; }; + 85904C03293BC1940011C817 /* URLActivityItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = URLActivityItem.swift; sourceTree = ""; }; 85BC11B22932414900E191CD /* AltTextViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AltTextViewController.swift; sourceTree = ""; }; 8850E70A1D5FF51432E43653 /* Pods-Mastodon-MastodonUITests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; path = "Target Support Files/Pods-Mastodon-MastodonUITests/Pods-Mastodon-MastodonUITests.asdk - release.xcconfig"; sourceTree = ""; }; 89FE8B85A00419CEF4678056 /* Pods_MastodonTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MastodonTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2901,7 +2901,7 @@ children = ( DBF3B7402733EB9400E21627 /* MastodonLocalCode.swift */, 85904C01293BC0EB0011C817 /* ImageProvider.swift */, - 85904C03293BC1940011C817 /* URLActivityItemWithMetadata.swift */, + 85904C03293BC1940011C817 /* URLActivityItem.swift */, 855149C929606D6400943D96 /* PortraitAlertController.swift */, ); path = Helper; @@ -3630,7 +3630,7 @@ 62FD27D52893708A00B205C5 /* BookmarkViewModel+Diffable.swift in Sources */, DB72602725E36A6F00235243 /* MastodonServerRulesViewModel.swift in Sources */, 2D364F7225E66D7500204FDC /* MastodonResendEmailViewController.swift in Sources */, - 85904C04293BC1940011C817 /* URLActivityItemWithMetadata.swift in Sources */, + 85904C04293BC1940011C817 /* URLActivityItem.swift in Sources */, DB68A06325E905E000CFDF14 /* UIApplication.swift in Sources */, DB02CDAB26256A9500D0A2AF /* ThreadReplyLoaderTableViewCell.swift in Sources */, DBEFCD80282A2AA900C0ABEA /* ReportServerRulesViewModel.swift in Sources */, diff --git a/Mastodon/Helper/URLActivityItem.swift b/Mastodon/Helper/URLActivityItem.swift new file mode 100644 index 000000000..7e63a781c --- /dev/null +++ b/Mastodon/Helper/URLActivityItem.swift @@ -0,0 +1,25 @@ +// +// URLActivityItem.swift +// Mastodon +// +// Created by Jed Fox on 2022-12-03. +// + +import UIKit +import LinkPresentation + +class URLActivityItem: NSObject, UIActivityItemSource { + let url: URL + + init(url: URL) { + self.url = url + } + + func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { + return url + } + + func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { + return url + } +} diff --git a/Mastodon/Helper/URLActivityItemWithMetadata.swift b/Mastodon/Helper/URLActivityItemWithMetadata.swift deleted file mode 100644 index 82d1747fe..000000000 --- a/Mastodon/Helper/URLActivityItemWithMetadata.swift +++ /dev/null @@ -1,33 +0,0 @@ -// -// URLActivityItemWithMetadata.swift -// Mastodon -// -// Created by Jed Fox on 2022-12-03. -// - -import UIKit -import LinkPresentation - -class URLActivityItemWithMetadata: NSObject, UIActivityItemSource { - init(url: URL, configureMetadata: (LPLinkMetadata) -> Void) { - self.url = url - self.metadata = LPLinkMetadata() - metadata.url = url - configureMetadata(metadata) - } - - let url: URL - let metadata: LPLinkMetadata - - func activityViewControllerPlaceholderItem(_ activityViewController: UIActivityViewController) -> Any { - url - } - - func activityViewController(_ activityViewController: UIActivityViewController, itemForActivityType activityType: UIActivity.ActivityType?) -> Any? { - url - } - - func activityViewControllerLinkMetadata(_ activityViewController: UIActivityViewController) -> LPLinkMetadata? { - metadata - } -} diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index 3a9a45f46..87d1c90f9 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -62,19 +62,12 @@ extension DataSourceFacade { status: MastodonStatus ) async throws -> UIActivityViewController { var activityItems: [Any] = { - guard let url = URL(string: status.entity.url ?? status.entity.uri) - else { return [] } + guard let url = URL(string: status.entity.url ?? status.entity.uri) else { return [] } return [ - URLActivityItemWithMetadata(url: url) { metadata in - metadata.title = "\(status.entity.account.displayName) (@\(status.entity.account.acctWithDomain))" - metadata.iconProvider = ImageProvider( - url: status.entity.account.avatarImageURLWithFallback(domain: status.entity.account.domain ?? ""), - filter: ScaledToSizeFilter(size: CGSize.authorAvatarButtonSize) - ).itemProvider - } - ] as [Any] + URLActivityItem(url: url) + ] }() - + var applicationActivities: [UIActivity] = [ SafariActivity(sceneCoordinator: dependency.coordinator), // open URL ] diff --git a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift index e06848f4b..7d19b668e 100644 --- a/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift +++ b/Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift @@ -168,13 +168,7 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte DispatchQueue.main.async { let activityViewController = UIActivityViewController( activityItems: [ - URLActivityItemWithMetadata(url: url) { metadata in - metadata.title = card.title - - if let image = card.image, let url = URL(string: image) { - metadata.iconProvider = ImageProvider(url: url, filter: nil).itemProvider - } - } + URLActivityItem(url: url) ], applicationActivities: [] ) diff --git a/Mastodon/Scene/Profile/ProfileViewController.swift b/Mastodon/Scene/Profile/ProfileViewController.swift index 051a6d6b3..881f44cae 100644 --- a/Mastodon/Scene/Profile/ProfileViewController.swift +++ b/Mastodon/Scene/Profile/ProfileViewController.swift @@ -775,6 +775,8 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate { let account = viewModel.account + viewModel.isUpdating = true + if relationship.blocking { let name = account.displayNameWithFallback @@ -791,6 +793,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate { account: account ) + self.viewModel.isUpdating = false self.viewModel.relationship = newRelationship } } @@ -817,6 +820,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate { guard let newRelationship = try await self.context.apiService.relationship(forAccounts: [account], authenticationBox: self.authContext.mastodonAuthenticationBox).value.first else { return } + self.viewModel.isUpdating = false self.viewModel.relationship = newRelationship } } @@ -842,6 +846,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate { account: account ) + self.viewModel.isUpdating = false self.viewModel.relationship = newRelationship } } @@ -858,6 +863,7 @@ extension ProfileViewController: ProfileHeaderViewControllerDelegate { account: viewModel.account ) + self.viewModel.isUpdating = false self.viewModel.relationship = newRelationship // TODO: update account? // TODO: update me? diff --git a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift index 5e9d098a4..e7408f5f7 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Control/ProfileRelationshipActionButton.swift @@ -10,57 +10,19 @@ import MastodonAsset import MastodonSDK import MastodonLocalization -public final class ProfileRelationshipActionButton: RoundedEdgesButton { - - public let activityIndicatorView: UIActivityIndicatorView = { - let activityIndicatorView = UIActivityIndicatorView(style: .medium) - activityIndicatorView.color = Asset.Colors.Label.primaryReverse.color - return activityIndicatorView - }() - - public override init(frame: CGRect) { - super.init(frame: frame) - _init() - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - _init() - } - -} - -extension ProfileRelationshipActionButton { - private func _init() { - cornerRadius = 10 - titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold) - - activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false - addSubview(activityIndicatorView) - NSLayoutConstraint.activate([ - activityIndicatorView.centerXAnchor.constraint(equalTo: centerXAnchor), - activityIndicatorView.centerYAnchor.constraint(equalTo: centerYAnchor), - ]) - - activityIndicatorView.hidesWhenStopped = true - activityIndicatorView.stopAnimating() - - configureAppearance() - } - - public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - configureAppearance() - } -} - -extension ProfileRelationshipActionButton { - +public final class ProfileRelationshipActionButton: UIButton { public func configure(relationship: Mastodon.Entity.Relationship, between account: Mastodon.Entity.Account, and me: Mastodon.Entity.Account, isEditing: Bool = false, isUpdating: Bool = false) { let isMyself = (account == me) - let title: String + + var configuration = UIButton.Configuration.filled() + + configuration.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 4, bottom: 0, trailing: 4) + configuration.baseBackgroundColor = Asset.Scene.Profile.RelationshipButton.background.color + configuration.activityIndicatorColorTransformer = UIConfigurationColorTransformer({ _ in return Asset.Colors.Label.primaryReverse.color }) + configuration.background.cornerRadius = 10 + + var title: String if isMyself { if isEditing { @@ -84,20 +46,27 @@ extension ProfileRelationshipActionButton { title = L10n.Common.Controls.Friendship.follow } - setTitle(title, for: .normal) - if relationship.blockedBy || account.suspended ?? false { isEnabled = false } else { isEnabled = true } - } - private func configureAppearance() { - setTitleColor(Asset.Colors.Label.primaryReverse.color, for: .normal) - setTitleColor(Asset.Colors.Label.primaryReverse.color.withAlphaComponent(0.5), for: .highlighted) - setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.background.color), for: .normal) - setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.backgroundHighlighted.color), for: .highlighted) - setBackgroundImage(.placeholder(color: Asset.Scene.Profile.RelationshipButton.backgroundHighlighted.color), for: .disabled) + if isUpdating { + configuration.showsActivityIndicator = true + title = "" + } else { + configuration.showsActivityIndicator = false + } + + configuration.attributedTitle = AttributedString( + title, + attributes: AttributeContainer([ + .font: UIFont.systemFont(ofSize: 17, weight: .semibold), + .foregroundColor: Asset.Colors.Label.primaryReverse.color + ]) + ) + + self.configuration = configuration } }