diff --git a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift index 175ebe474..9d9e73eb3 100644 --- a/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift +++ b/Mastodon/Protocol/Provider/DataSourceFacade+Status.swift @@ -7,9 +7,13 @@ import UIKit import CoreDataStack +import Alamofire +import AlamofireImage import MastodonCore import MastodonUI import MastodonLocalization +import LinkPresentation +import UniformTypeIdentifiers // Delete extension DataSourceFacade { @@ -56,8 +60,7 @@ extension DataSourceFacade { ) async throws -> UIActivityViewController { var activityItems: [Any] = try await dependency.context.managedObjectContext.perform { guard let status = status.object(in: dependency.context.managedObjectContext) else { return [] } - let url = status.url ?? status.uri - return [URL(string: url)].compactMap { $0 } as [Any] + return [StatusActivityItem(status: status)].compactMap { $0 } as [Any] } var applicationActivities: [UIActivity] = [ SafariActivity(sceneCoordinator: dependency.coordinator), // open URL @@ -74,6 +77,54 @@ extension DataSourceFacade { ) return activityViewController } + + private class StatusActivityItem: NSObject, UIActivityItemSource { + init?(status: Status) { + guard let url = URL(string: status.url ?? status.uri) else { return nil } + self.url = url + self.metadata = LPLinkMetadata() + metadata.url = url + metadata.title = "\(status.author.displayName) (@\(status.author.username)@\(status.author.domain))" + metadata.iconProvider = NSItemProvider(object: IconProvider(url: status.author.avatarImageURLWithFallback(domain: status.author.domain))) + } + + 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 + } + + private class IconProvider: NSObject, NSItemProviderWriting { + let url: URL + init(url: URL) { + self.url = url + } + + static var writableTypeIdentifiersForItemProvider: [String] { + [UTType.png.identifier] + } + + func loadData(withTypeIdentifier typeIdentifier: String, forItemProviderCompletionHandler completionHandler: @escaping @Sendable (Data?, Error?) -> Void) -> Progress? { + let filter = ScaledToSizeFilter(size: CGSize.authorAvatarButtonSize) + let receipt = UIImageView.af.sharedImageDownloader.download(URLRequest(url: url), filter: filter, completion: { response in + switch response.result { + case .failure(let error): completionHandler(nil, error) + case .success(let image): completionHandler(image.pngData(), nil) + } + }) + return receipt?.request.downloadProgress + } + } + } } // ActionToolBar diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift index 45e19cc77..e52422770 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/NotificationView.swift @@ -226,14 +226,13 @@ extension NotificationView { .store(in: &_disposeBag) // avatarButton - let authorAvatarButtonSize = CGSize(width: 46, height: 46) - avatarButton.size = authorAvatarButtonSize - avatarButton.avatarImageView.imageViewSize = authorAvatarButtonSize + avatarButton.size = CGSize.authorAvatarButtonSize + avatarButton.avatarImageView.imageViewSize = CGSize.authorAvatarButtonSize avatarButton.translatesAutoresizingMaskIntoConstraints = false authorContainerView.addArrangedSubview(avatarButton) NSLayoutConstraint.activate([ - avatarButton.widthAnchor.constraint(equalToConstant: authorAvatarButtonSize.width).priority(.required - 1), - avatarButton.heightAnchor.constraint(equalToConstant: authorAvatarButtonSize.height).priority(.required - 1), + avatarButton.widthAnchor.constraint(equalToConstant: CGSize.authorAvatarButtonSize.width).priority(.required - 1), + avatarButton.heightAnchor.constraint(equalToConstant: CGSize.authorAvatarButtonSize.height).priority(.required - 1), ]) avatarButton.setContentHuggingPriority(.required - 1, for: .vertical) avatarButton.setContentCompressionResistancePriority(.required - 1, for: .vertical) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift index aac1543a4..e2879d1e8 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusAuthorView.swift @@ -210,14 +210,13 @@ extension StatusAuthorView { // author container: H - [ avatarButton | authorMetaContainer ] private func layoutBase() { // avatarButton - let authorAvatarButtonSize = CGSize(width: 46, height: 46) - avatarButton.size = authorAvatarButtonSize - avatarButton.avatarImageView.imageViewSize = authorAvatarButtonSize + avatarButton.size = CGSize.authorAvatarButtonSize + avatarButton.avatarImageView.imageViewSize = CGSize.authorAvatarButtonSize avatarButton.translatesAutoresizingMaskIntoConstraints = false addArrangedSubview(avatarButton) NSLayoutConstraint.activate([ - avatarButton.widthAnchor.constraint(equalToConstant: authorAvatarButtonSize.width).priority(.required - 1), - avatarButton.heightAnchor.constraint(equalToConstant: authorAvatarButtonSize.height).priority(.required - 1), + avatarButton.widthAnchor.constraint(equalToConstant: CGSize.authorAvatarButtonSize.width).priority(.required - 1), + avatarButton.heightAnchor.constraint(equalToConstant: CGSize.authorAvatarButtonSize.height).priority(.required - 1), ]) avatarButton.setContentHuggingPriority(.required - 1, for: .vertical) avatarButton.setContentCompressionResistancePriority(.required - 1, for: .vertical) diff --git a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift index efc4afee8..8ab34ce4f 100644 --- a/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift +++ b/MastodonSDK/Sources/MastodonUI/View/Content/StatusView.swift @@ -14,6 +14,10 @@ import MastodonAsset import MastodonCore import MastodonLocalization +public extension CGSize { + static let authorAvatarButtonSize = CGSize(width: 46, height: 46) +} + public protocol StatusViewDelegate: AnyObject { func statusView(_ statusView: StatusView, headerDidPressed header: UIView) func statusView(_ statusView: StatusView, authorAvatarButtonDidPressed button: AvatarButton)