mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
210 lines
6.7 KiB
Swift
210 lines
6.7 KiB
Swift
//
|
|
// DataSourceFacade+Media.swift
|
|
// Mastodon
|
|
//
|
|
// Created by MainasuK on 2022-1-26.
|
|
//
|
|
|
|
import UIKit
|
|
import CoreDataStack
|
|
import MastodonUI
|
|
import MastodonLocalization
|
|
import MastodonSDK
|
|
|
|
extension DataSourceFacade {
|
|
|
|
@MainActor
|
|
static func coordinateToMediaPreviewScene(
|
|
dependency: NeedsDependency & MediaPreviewableViewController,
|
|
mediaPreviewItem: MediaPreviewViewModel.PreviewItem,
|
|
mediaPreviewTransitionItem: MediaPreviewTransitionItem
|
|
) {
|
|
let mediaPreviewViewModel = MediaPreviewViewModel(
|
|
context: dependency.context,
|
|
item: mediaPreviewItem,
|
|
transitionItem: mediaPreviewTransitionItem
|
|
)
|
|
_ = dependency.coordinator.present(
|
|
scene: .mediaPreview(viewModel: mediaPreviewViewModel),
|
|
from: dependency,
|
|
transition: .custom(transitioningDelegate: dependency.mediaPreviewTransitionController)
|
|
)
|
|
}
|
|
|
|
}
|
|
|
|
extension DataSourceFacade {
|
|
|
|
struct AttachmentPreviewContext {
|
|
let containerView: ContainerView
|
|
let mediaView: MediaView
|
|
let index: Int
|
|
|
|
enum ContainerView {
|
|
case mediaView(MediaView)
|
|
case mediaGridContainerView(MediaGridContainerView)
|
|
}
|
|
|
|
func thumbnails() async -> [UIImage?] {
|
|
switch containerView {
|
|
case .mediaView(let mediaView):
|
|
let thumbnail = await mediaView.thumbnail()
|
|
return [thumbnail]
|
|
case .mediaGridContainerView(let mediaGridContainerView):
|
|
let thumbnails = await mediaGridContainerView.mediaViews.parallelMap { mediaView in
|
|
return await mediaView.thumbnail()
|
|
}
|
|
return thumbnails
|
|
}
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
static func coordinateToMediaPreviewScene(
|
|
dependency: NeedsDependency & MediaPreviewableViewController,
|
|
status: MastodonStatus,
|
|
previewContext: AttachmentPreviewContext
|
|
) async throws {
|
|
let managedObjectContext = dependency.context.managedObjectContext
|
|
let status = status.reblog ?? status
|
|
let attachments = status.entity.mastodonAttachments
|
|
|
|
let thumbnails = await previewContext.thumbnails()
|
|
|
|
let _source: MediaPreviewTransitionItem.Source? = {
|
|
switch previewContext.containerView {
|
|
case .mediaView(let mediaView):
|
|
return .attachment(mediaView)
|
|
case .mediaGridContainerView(let mediaGridContainerView):
|
|
return .attachments(mediaGridContainerView)
|
|
}
|
|
}()
|
|
guard let source = _source else {
|
|
return
|
|
}
|
|
|
|
let mediaPreviewTransitionItem: MediaPreviewTransitionItem = {
|
|
let item = MediaPreviewTransitionItem(
|
|
source: source,
|
|
previewableViewController: dependency
|
|
)
|
|
|
|
let mediaView = previewContext.mediaView
|
|
|
|
item.initialFrame = {
|
|
let initialFrame = mediaView.superview!.convert(mediaView.frame, to: nil)
|
|
assert(initialFrame != .zero)
|
|
return initialFrame
|
|
}()
|
|
|
|
let thumbnail = mediaView.thumbnail()
|
|
item.image = thumbnail
|
|
|
|
item.aspectRatio = {
|
|
if let thumbnail = thumbnail {
|
|
return thumbnail.size
|
|
}
|
|
let index = previewContext.index
|
|
guard index < attachments.count else { return nil }
|
|
let size = attachments[index].size
|
|
return size
|
|
}()
|
|
|
|
return item
|
|
}()
|
|
|
|
|
|
let mediaPreviewItem = MediaPreviewViewModel.PreviewItem.attachment(.init(
|
|
attachments: attachments,
|
|
initialIndex: previewContext.index,
|
|
thumbnails: thumbnails
|
|
))
|
|
|
|
coordinateToMediaPreviewScene(
|
|
dependency: dependency,
|
|
mediaPreviewItem: mediaPreviewItem,
|
|
mediaPreviewTransitionItem: mediaPreviewTransitionItem
|
|
)
|
|
}
|
|
|
|
}
|
|
|
|
extension DataSourceFacade {
|
|
|
|
struct ImagePreviewContext {
|
|
let imageView: UIImageView
|
|
let containerView: ContainerView
|
|
|
|
enum ContainerView {
|
|
case profileAvatar(ProfileHeaderView)
|
|
case profileBanner(ProfileHeaderView)
|
|
}
|
|
|
|
func thumbnail() -> UIImage? {
|
|
return imageView.image
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
static func coordinateToMediaPreviewScene(
|
|
dependency: NeedsDependency & MediaPreviewableViewController,
|
|
account: Mastodon.Entity.Account,
|
|
previewContext: ImagePreviewContext
|
|
) async throws {
|
|
|
|
let avatarAssetURL = account.avatar
|
|
let headerAssetURL = account.header
|
|
|
|
let thumbnail = previewContext.thumbnail()
|
|
|
|
let source: MediaPreviewTransitionItem.Source
|
|
switch previewContext.containerView {
|
|
case .profileAvatar(let view): source = .profileAvatar(view)
|
|
case .profileBanner(let view): source = .profileBanner(view)
|
|
}
|
|
|
|
let mediaPreviewTransitionItem = MediaPreviewTransitionItem(
|
|
source: source,
|
|
previewableViewController: dependency
|
|
)
|
|
|
|
let imageView = previewContext.imageView
|
|
mediaPreviewTransitionItem.initialFrame = imageView.superview?.convert(imageView.frame, to: nil)
|
|
mediaPreviewTransitionItem.image = thumbnail
|
|
mediaPreviewTransitionItem.aspectRatio = thumbnail?.size ?? CGSize(width: 100, height: 100)
|
|
mediaPreviewTransitionItem.sourceImageViewCornerRadius = {
|
|
switch previewContext.containerView {
|
|
case .profileAvatar:
|
|
return ProfileHeaderView.avatarImageViewCornerRadius
|
|
case .profileBanner:
|
|
return 0
|
|
}
|
|
}()
|
|
|
|
let mediaPreviewItem: MediaPreviewViewModel.PreviewItem
|
|
switch previewContext.containerView {
|
|
case .profileAvatar:
|
|
mediaPreviewItem = .profileAvatar(.init(
|
|
assetURL: avatarAssetURL,
|
|
thumbnail: thumbnail
|
|
))
|
|
case .profileBanner:
|
|
mediaPreviewItem = .profileBanner(.init(
|
|
assetURL: headerAssetURL,
|
|
thumbnail: thumbnail
|
|
))
|
|
}
|
|
|
|
guard mediaPreviewItem.isAssetURLValid else {
|
|
return
|
|
}
|
|
|
|
coordinateToMediaPreviewScene(
|
|
dependency: dependency,
|
|
mediaPreviewItem: mediaPreviewItem,
|
|
mediaPreviewTransitionItem: mediaPreviewTransitionItem
|
|
)
|
|
}
|
|
|
|
}
|