// // MediaPreviewViewModel.swift // Mastodon // // Created by MainasuK Cirno on 2021-4-28. // import UIKit import Combine import CoreData import CoreDataStack import Pageboy final class MediaPreviewViewModel: NSObject { // input let context: AppContext let initialItem: PreviewItem weak var mediaPreviewImageViewControllerDelegate: MediaPreviewImageViewControllerDelegate? let currentPage: CurrentValueSubject // output let pushTransitionItem: MediaPreviewTransitionItem let viewControllers: [UIViewController] init(context: AppContext, meta: StatusImagePreviewMeta, pushTransitionItem: MediaPreviewTransitionItem) { self.context = context self.initialItem = .status(meta) var viewControllers: [UIViewController] = [] let managedObjectContext = self.context.managedObjectContext managedObjectContext.performAndWait { let status = managedObjectContext.object(with: meta.statusObjectID) as! Status guard let media = status.mediaAttachments?.sorted(by: { $0.index.compare($1.index) == .orderedAscending }) else { return } for (entity, image) in zip(media, meta.preloadThumbnailImages) { let thumbnail: UIImage? = image.flatMap { $0.size != CGSize(width: 1, height: 1) ? $0 : nil } switch entity.type { case .image: guard let url = URL(string: entity.url) else { continue } let meta = MediaPreviewImageViewModel.RemoteImagePreviewMeta(url: url, thumbnail: thumbnail, altText: entity.descriptionString) let mediaPreviewImageModel = MediaPreviewImageViewModel(meta: meta) let mediaPreviewImageViewController = MediaPreviewImageViewController() mediaPreviewImageViewController.viewModel = mediaPreviewImageModel viewControllers.append(mediaPreviewImageViewController) default: continue } } } self.viewControllers = viewControllers self.currentPage = CurrentValueSubject(meta.initialIndex) self.pushTransitionItem = pushTransitionItem super.init() } init(context: AppContext, meta: ProfileBannerImagePreviewMeta, pushTransitionItem: MediaPreviewTransitionItem) { self.context = context self.initialItem = .profileBanner(meta) var viewControllers: [UIViewController] = [] let managedObjectContext = self.context.managedObjectContext managedObjectContext.performAndWait { let account = managedObjectContext.object(with: meta.accountObjectID) as! MastodonUser let avatarURL = account.headerImageURLWithFallback(domain: account.domain) let meta = MediaPreviewImageViewModel.RemoteImagePreviewMeta(url: avatarURL, thumbnail: meta.preloadThumbnailImage, altText: nil) let mediaPreviewImageModel = MediaPreviewImageViewModel(meta: meta) let mediaPreviewImageViewController = MediaPreviewImageViewController() mediaPreviewImageViewController.viewModel = mediaPreviewImageModel viewControllers.append(mediaPreviewImageViewController) } self.viewControllers = viewControllers self.currentPage = CurrentValueSubject(0) self.pushTransitionItem = pushTransitionItem super.init() } init(context: AppContext, meta: ProfileAvatarImagePreviewMeta, pushTransitionItem: MediaPreviewTransitionItem) { self.context = context self.initialItem = .profileAvatar(meta) var viewControllers: [UIViewController] = [] let managedObjectContext = self.context.managedObjectContext managedObjectContext.performAndWait { let account = managedObjectContext.object(with: meta.accountObjectID) as! MastodonUser let avatarURL = account.avatarImageURLWithFallback(domain: account.domain) let meta = MediaPreviewImageViewModel.RemoteImagePreviewMeta(url: avatarURL, thumbnail: meta.preloadThumbnailImage, altText: nil) let mediaPreviewImageModel = MediaPreviewImageViewModel(meta: meta) let mediaPreviewImageViewController = MediaPreviewImageViewController() mediaPreviewImageViewController.viewModel = mediaPreviewImageModel viewControllers.append(mediaPreviewImageViewController) } self.viewControllers = viewControllers self.currentPage = CurrentValueSubject(0) self.pushTransitionItem = pushTransitionItem super.init() } } extension MediaPreviewViewModel { enum PreviewItem { case status(StatusImagePreviewMeta) case profileAvatar(ProfileAvatarImagePreviewMeta) case profileBanner(ProfileBannerImagePreviewMeta) case local(LocalImagePreviewMeta) } struct StatusImagePreviewMeta { let statusObjectID: NSManagedObjectID let initialIndex: Int let preloadThumbnailImages: [UIImage?] } struct ProfileAvatarImagePreviewMeta { let accountObjectID: NSManagedObjectID let preloadThumbnailImage: UIImage? } struct ProfileBannerImagePreviewMeta { let accountObjectID: NSManagedObjectID let preloadThumbnailImage: UIImage? } struct LocalImagePreviewMeta { let image: UIImage } } // MARK: - PageboyViewControllerDataSource extension MediaPreviewViewModel: PageboyViewControllerDataSource { func numberOfViewControllers(in pageboyViewController: PageboyViewController) -> Int { return viewControllers.count } func viewController(for pageboyViewController: PageboyViewController, at index: PageboyViewController.PageIndex) -> UIViewController? { let viewController = viewControllers[index] if let mediaPreviewImageViewController = viewController as? MediaPreviewImageViewController { mediaPreviewImageViewController.delegate = mediaPreviewImageViewControllerDelegate } return viewController } func defaultPage(for pageboyViewController: PageboyViewController) -> PageboyViewController.Page? { guard case let .status(meta) = initialItem else { return nil } return .at(index: meta.initialIndex) } }