Tusker/Tusker/Screens/Large Image/LargeImageContentView.swift

179 lines
5.7 KiB
Swift

//
// LargeImageContentView.swift
// Tusker
//
// Created by Shadowfacts on 6/17/20.
// Copyright © 2020 Shadowfacts. All rights reserved.
//
import UIKit
import Pachyderm
import AVFoundation
import VisionKit
protocol LargeImageContentView: UIView {
var animationImage: UIImage? { get }
var activityItemsForSharing: [Any] { get }
var owner: LargeImageViewController? { get set }
func setControlsVisible(_ controlsVisible: Bool)
func grayscaleStateChanged()
}
class LargeImageImageContentView: UIImageView, LargeImageContentView {
#if !targetEnvironment(macCatalyst)
@available(iOS 16.0, *)
private static let analyzer = ImageAnalyzer()
private var _analysisInteraction: AnyObject?
@available(iOS 16.0, *)
private var analysisInteraction: ImageAnalysisInteraction? { _analysisInteraction as? ImageAnalysisInteraction }
#endif
var animationImage: UIImage? { image! }
var activityItemsForSharing: [Any] {
[image!]
}
weak var owner: LargeImageViewController?
private var sourceData: Data?
init(image: UIImage) {
super.init(image: image)
contentMode = .scaleAspectFit
isUserInteractionEnabled = true
#if !targetEnvironment(macCatalyst)
if #available(iOS 16.0, *),
ImageAnalyzer.isSupported {
let interaction = ImageAnalysisInteraction()
self._analysisInteraction = interaction
interaction.delegate = self
interaction.preferredInteractionTypes = .automatic
addInteraction(interaction)
Task {
do {
let result = try await LargeImageImageContentView.analyzer.analyze(image, configuration: ImageAnalyzer.Configuration([.text, .machineReadableCode]))
interaction.analysis = result
} catch {
// if analysis fails, we just don't show anything
}
}
}
#endif
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setControlsVisible(_ controlsVisible: Bool) {
#if !targetEnvironment(macCatalyst)
if #available(iOS 16.0, *),
let analysisInteraction {
// note: passing animated: true here doesn't seem to do anything by itself as of iOS 16.2 (20C5032e)
// so the LargeImageViewController handles animating, but we still need to pass true here otherwise it doesn't animate
analysisInteraction.setSupplementaryInterfaceHidden(!controlsVisible, animated: true)
}
#endif
}
func grayscaleStateChanged() {
guard let data = sourceData else {
return
}
let image: UIImage?
if Preferences.shared.grayscaleImages {
image = ImageGrayscalifier.convert(url: nil, data: data)
} else {
image = UIImage(data: data)
}
if let image = image {
self.image = image
}
}
}
#if !targetEnvironment(macCatalyst)
@available(iOS 16.0, *)
extension LargeImageImageContentView: ImageAnalysisInteractionDelegate {
func presentingViewController(for interaction: ImageAnalysisInteraction) -> UIViewController? {
return owner
}
}
#endif
class LargeImageGifContentView: GIFImageView, LargeImageContentView {
var animationImage: UIImage? { image }
var activityItemsForSharing: [Any] {
// todo: should gifs share the data?
[image].compactMap { $0 }
}
weak var owner: LargeImageViewController?
init(gifController: GIFController) {
super.init(image: gifController.lastFrame?.image)
contentMode = .scaleAspectFit
gifController.attach(to: self)
// todo: doing this in the init feels wrong
gifController.startAnimating()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setControlsVisible(_ controlsVisible: Bool) {
}
func grayscaleStateChanged() {
// todo
}
}
class LargeImageGifvContentView: GifvAttachmentView, LargeImageContentView {
private(set) var animationImage: UIImage?
var activityItemsForSharing: [Any] {
// todo: what should we share for gifvs?
// some SO posts indicate that just sharing a URL to the video should work, but that may need to be a local URL?
[]
}
weak var owner: LargeImageViewController?
private let asset: AVURLAsset
// The content view needs to supply an intrinsicContentSize for the LargeImageViewController to handle layout/scrolling/zooming correctly
override var intrinsicContentSize: CGSize {
// This is a really sucky workaround for the fact that in the content view, we don't have access to the size of the underlying video.
// There's probably some way of getting this from the AVPlayer/AVAsset directly
animationImage?.size ?? CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric)
}
init(attachment: Attachment, source: UIImageView) {
precondition(attachment.kind == .gifv)
self.asset = AVURLAsset(url: attachment.url)
super.init(asset: asset, gravity: .resizeAspect)
self.animationImage = source.image
self.player.play()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func setControlsVisible(_ controlsVisible: Bool) {
}
func grayscaleStateChanged() {
// no-op, GifvAttachmentView observes the grayscale state itself
}
}