2021-02-23 12:18:34 +01:00
|
|
|
//
|
2021-02-24 12:19:16 +01:00
|
|
|
// MosaicImageViewContainer.swift
|
2021-02-23 12:18:34 +01:00
|
|
|
// Mastodon
|
|
|
|
//
|
|
|
|
// Created by Cirno MainasuK on 2021-2-23.
|
|
|
|
//
|
|
|
|
|
|
|
|
import os.log
|
|
|
|
import func AVFoundation.AVMakeRect
|
|
|
|
import UIKit
|
|
|
|
|
2021-04-30 13:28:06 +02:00
|
|
|
protocol MosaicImageViewContainerPresentable: AnyObject {
|
2021-02-24 12:19:16 +01:00
|
|
|
var mosaicImageViewContainer: MosaicImageViewContainer { get }
|
2021-04-30 13:28:06 +02:00
|
|
|
var isRevealing: Bool { get }
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 13:28:06 +02:00
|
|
|
protocol MosaicImageViewContainerDelegate: AnyObject {
|
2021-02-24 12:19:16 +01:00
|
|
|
func mosaicImageViewContainer(_ mosaicImageViewContainer: MosaicImageViewContainer, didTapImageView imageView: UIImageView, atIndex index: Int)
|
2021-03-12 05:17:07 +01:00
|
|
|
func mosaicImageViewContainer(_ mosaicImageViewContainer: MosaicImageViewContainer, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
2021-02-24 12:19:16 +01:00
|
|
|
final class MosaicImageViewContainer: UIView {
|
2021-02-23 12:18:34 +01:00
|
|
|
|
2021-02-25 06:47:30 +01:00
|
|
|
weak var delegate: MosaicImageViewContainerDelegate?
|
2021-02-23 12:18:34 +01:00
|
|
|
|
|
|
|
let container = UIStackView()
|
2021-02-25 06:47:30 +01:00
|
|
|
var imageViews: [UIImageView] = [] {
|
2021-02-23 12:18:34 +01:00
|
|
|
didSet {
|
|
|
|
imageViews.forEach { imageView in
|
|
|
|
imageView.isUserInteractionEnabled = true
|
|
|
|
let tapGesture = UITapGestureRecognizer.singleTapGestureRecognizer
|
2021-02-24 12:19:16 +01:00
|
|
|
tapGesture.addTarget(self, action: #selector(MosaicImageViewContainer.photoTapGestureRecognizerHandler(_:)))
|
2021-02-23 12:18:34 +01:00
|
|
|
imageView.addGestureRecognizer(tapGesture)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-04-16 14:06:36 +02:00
|
|
|
var blurhashOverlayImageViews: [UIImageView] = []
|
2021-03-12 05:17:07 +01:00
|
|
|
|
|
|
|
let contentWarningOverlayView: ContentWarningOverlayView = {
|
|
|
|
let contentWarningOverlayView = ContentWarningOverlayView()
|
2021-04-16 14:06:36 +02:00
|
|
|
contentWarningOverlayView.configure(style: .visualEffectView)
|
2021-03-12 05:17:07 +01:00
|
|
|
return contentWarningOverlayView
|
2021-02-25 06:47:30 +01:00
|
|
|
}()
|
|
|
|
|
2021-02-23 12:18:34 +01:00
|
|
|
private var containerHeightLayoutConstraint: NSLayoutConstraint!
|
|
|
|
|
|
|
|
override init(frame: CGRect) {
|
|
|
|
super.init(frame: frame)
|
|
|
|
_init()
|
|
|
|
}
|
|
|
|
|
|
|
|
required init?(coder: NSCoder) {
|
|
|
|
super.init(coder: coder)
|
|
|
|
_init()
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-03-12 05:17:07 +01:00
|
|
|
extension MosaicImageViewContainer: ContentWarningOverlayViewDelegate {
|
|
|
|
func contentWarningOverlayViewDidPressed(_ contentWarningOverlayView: ContentWarningOverlayView) {
|
|
|
|
self.delegate?.mosaicImageViewContainer(self, contentWarningOverlayViewDidPressed: contentWarningOverlayView)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-24 12:19:16 +01:00
|
|
|
extension MosaicImageViewContainer {
|
2021-02-23 12:18:34 +01:00
|
|
|
|
|
|
|
private func _init() {
|
2021-05-10 10:06:00 +02:00
|
|
|
// accessibility
|
|
|
|
accessibilityIgnoresInvertColors = true
|
|
|
|
|
2021-02-23 12:18:34 +01:00
|
|
|
container.translatesAutoresizingMaskIntoConstraints = false
|
2021-02-25 06:47:30 +01:00
|
|
|
container.axis = .horizontal
|
|
|
|
container.distribution = .fillEqually
|
2021-02-23 12:18:34 +01:00
|
|
|
addSubview(container)
|
|
|
|
containerHeightLayoutConstraint = container.heightAnchor.constraint(equalToConstant: 162).priority(.required - 1)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
container.topAnchor.constraint(equalTo: topAnchor),
|
|
|
|
container.leadingAnchor.constraint(equalTo: leadingAnchor),
|
|
|
|
trailingAnchor.constraint(equalTo: container.trailingAnchor),
|
|
|
|
bottomAnchor.constraint(equalTo: container.bottomAnchor),
|
|
|
|
containerHeightLayoutConstraint
|
|
|
|
])
|
|
|
|
|
2021-03-15 12:31:31 +01:00
|
|
|
contentWarningOverlayView.delegate = self
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2021-02-24 12:19:16 +01:00
|
|
|
extension MosaicImageViewContainer {
|
2021-02-23 12:18:34 +01:00
|
|
|
|
|
|
|
func reset() {
|
|
|
|
container.arrangedSubviews.forEach { subview in
|
|
|
|
container.removeArrangedSubview(subview)
|
|
|
|
subview.removeFromSuperview()
|
|
|
|
}
|
|
|
|
container.subviews.forEach { subview in
|
|
|
|
subview.removeFromSuperview()
|
|
|
|
}
|
2021-03-12 05:17:07 +01:00
|
|
|
contentWarningOverlayView.removeFromSuperview()
|
|
|
|
contentWarningOverlayView.blurVisualEffectView.effect = ContentWarningOverlayView.blurVisualEffect
|
|
|
|
contentWarningOverlayView.vibrancyVisualEffectView.alpha = 1.0
|
2021-03-15 12:31:31 +01:00
|
|
|
contentWarningOverlayView.isUserInteractionEnabled = true
|
2021-02-23 12:18:34 +01:00
|
|
|
imageViews = []
|
2021-04-16 14:06:36 +02:00
|
|
|
blurhashOverlayImageViews = []
|
2021-02-23 12:18:34 +01:00
|
|
|
|
|
|
|
container.spacing = 1
|
|
|
|
}
|
|
|
|
|
2021-04-16 14:06:36 +02:00
|
|
|
typealias ConfigurableMosaic = (imageView: UIImageView, blurhashOverlayImageView: UIImageView)
|
|
|
|
|
|
|
|
func setupImageView(aspectRatio: CGSize, maxSize: CGSize) -> ConfigurableMosaic {
|
2021-02-23 12:18:34 +01:00
|
|
|
reset()
|
|
|
|
|
|
|
|
let contentView = UIView()
|
|
|
|
contentView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
container.addArrangedSubview(contentView)
|
|
|
|
|
|
|
|
let rect = AVMakeRect(
|
|
|
|
aspectRatio: aspectRatio,
|
|
|
|
insideRect: CGRect(origin: .zero, size: maxSize)
|
|
|
|
)
|
|
|
|
|
|
|
|
let imageView = UIImageView()
|
|
|
|
imageViews.append(imageView)
|
|
|
|
imageView.layer.masksToBounds = true
|
2021-03-12 05:17:07 +01:00
|
|
|
imageView.layer.cornerRadius = ContentWarningOverlayView.cornerRadius
|
2021-02-25 06:47:30 +01:00
|
|
|
imageView.layer.cornerCurve = .continuous
|
2021-02-23 12:18:34 +01:00
|
|
|
imageView.contentMode = .scaleAspectFill
|
|
|
|
|
|
|
|
imageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
contentView.addSubview(imageView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
imageView.topAnchor.constraint(equalTo: contentView.topAnchor),
|
|
|
|
imageView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
|
|
|
|
imageView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor),
|
|
|
|
imageView.widthAnchor.constraint(equalToConstant: floor(rect.width)).priority(.required - 1),
|
|
|
|
])
|
|
|
|
containerHeightLayoutConstraint.constant = floor(rect.height)
|
|
|
|
containerHeightLayoutConstraint.isActive = true
|
2021-02-25 06:47:30 +01:00
|
|
|
|
2021-04-16 14:06:36 +02:00
|
|
|
let blurhashOverlayImageView = UIImageView()
|
|
|
|
blurhashOverlayImageView.layer.masksToBounds = true
|
|
|
|
blurhashOverlayImageView.layer.cornerRadius = ContentWarningOverlayView.cornerRadius
|
|
|
|
blurhashOverlayImageView.layer.cornerCurve = .continuous
|
|
|
|
blurhashOverlayImageView.contentMode = .scaleAspectFill
|
|
|
|
blurhashOverlayImageViews.append(blurhashOverlayImageView)
|
|
|
|
blurhashOverlayImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
contentView.addSubview(blurhashOverlayImageView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
blurhashOverlayImageView.topAnchor.constraint(equalTo: imageView.topAnchor),
|
|
|
|
blurhashOverlayImageView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
|
|
|
|
blurhashOverlayImageView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
|
|
|
|
blurhashOverlayImageView.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
|
|
|
|
])
|
|
|
|
|
2021-04-19 12:33:11 +02:00
|
|
|
contentWarningOverlayView.translatesAutoresizingMaskIntoConstraints = false
|
2021-03-12 05:17:07 +01:00
|
|
|
addSubview(contentWarningOverlayView)
|
2021-02-25 06:47:30 +01:00
|
|
|
NSLayoutConstraint.activate([
|
2021-03-12 05:17:07 +01:00
|
|
|
contentWarningOverlayView.topAnchor.constraint(equalTo: imageView.topAnchor),
|
|
|
|
contentWarningOverlayView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
|
|
|
|
contentWarningOverlayView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
|
|
|
|
contentWarningOverlayView.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
|
2021-02-25 06:47:30 +01:00
|
|
|
])
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
return (imageView, blurhashOverlayImageView)
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
2021-04-16 14:06:36 +02:00
|
|
|
func setupImageViews(count: Int, maxHeight: CGFloat) -> [ConfigurableMosaic] {
|
2021-02-23 12:18:34 +01:00
|
|
|
reset()
|
|
|
|
guard count > 1 else {
|
|
|
|
return []
|
|
|
|
}
|
|
|
|
|
|
|
|
containerHeightLayoutConstraint.constant = maxHeight
|
|
|
|
containerHeightLayoutConstraint.isActive = true
|
|
|
|
|
|
|
|
let contentLeftStackView = UIStackView()
|
|
|
|
let contentRightStackView = UIStackView()
|
|
|
|
[contentLeftStackView, contentRightStackView].forEach { stackView in
|
|
|
|
stackView.axis = .vertical
|
|
|
|
stackView.distribution = .fillEqually
|
|
|
|
stackView.spacing = 1
|
|
|
|
}
|
|
|
|
container.addArrangedSubview(contentLeftStackView)
|
|
|
|
container.addArrangedSubview(contentRightStackView)
|
|
|
|
|
|
|
|
var imageViews: [UIImageView] = []
|
2021-04-16 14:06:36 +02:00
|
|
|
var blurhashOverlayImageViews: [UIImageView] = []
|
2021-02-23 12:18:34 +01:00
|
|
|
for _ in 0..<count {
|
|
|
|
imageViews.append(UIImageView())
|
2021-04-16 14:06:36 +02:00
|
|
|
blurhashOverlayImageViews.append(UIImageView())
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
self.imageViews.append(contentsOf: imageViews)
|
2021-04-16 14:06:36 +02:00
|
|
|
self.blurhashOverlayImageViews.append(contentsOf: blurhashOverlayImageViews)
|
2021-02-23 12:18:34 +01:00
|
|
|
imageViews.forEach { imageView in
|
|
|
|
imageView.layer.masksToBounds = true
|
2021-03-12 05:17:07 +01:00
|
|
|
imageView.layer.cornerRadius = ContentWarningOverlayView.cornerRadius
|
2021-02-23 12:18:34 +01:00
|
|
|
imageView.layer.cornerCurve = .continuous
|
|
|
|
imageView.contentMode = .scaleAspectFill
|
|
|
|
}
|
2021-04-16 14:06:36 +02:00
|
|
|
blurhashOverlayImageViews.forEach { imageView in
|
|
|
|
imageView.layer.masksToBounds = true
|
|
|
|
imageView.layer.cornerRadius = ContentWarningOverlayView.cornerRadius
|
|
|
|
imageView.layer.cornerCurve = .continuous
|
|
|
|
imageView.contentMode = .scaleAspectFill
|
|
|
|
}
|
2021-02-23 12:18:34 +01:00
|
|
|
if count == 2 {
|
|
|
|
contentLeftStackView.addArrangedSubview(imageViews[0])
|
|
|
|
contentRightStackView.addArrangedSubview(imageViews[1])
|
|
|
|
switch UIApplication.shared.userInterfaceLayoutDirection {
|
|
|
|
case .rightToLeft:
|
|
|
|
imageViews[1].layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
|
|
|
|
imageViews[0].layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
blurhashOverlayImageViews[1].layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
|
|
|
|
blurhashOverlayImageViews[0].layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
|
|
|
|
|
2021-02-23 12:18:34 +01:00
|
|
|
default:
|
|
|
|
imageViews[0].layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
|
|
|
|
imageViews[1].layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
blurhashOverlayImageViews[0].layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
|
|
|
|
blurhashOverlayImageViews[1].layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
} else if count == 3 {
|
|
|
|
contentLeftStackView.addArrangedSubview(imageViews[0])
|
|
|
|
contentRightStackView.addArrangedSubview(imageViews[1])
|
|
|
|
contentRightStackView.addArrangedSubview(imageViews[2])
|
|
|
|
switch UIApplication.shared.userInterfaceLayoutDirection {
|
|
|
|
case .rightToLeft:
|
|
|
|
imageViews[0].layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
|
|
|
|
imageViews[1].layer.maskedCorners = [.layerMinXMinYCorner]
|
|
|
|
imageViews[2].layer.maskedCorners = [.layerMinXMaxYCorner]
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
blurhashOverlayImageViews[0].layer.maskedCorners = [.layerMaxXMinYCorner, .layerMaxXMaxYCorner]
|
|
|
|
blurhashOverlayImageViews[1].layer.maskedCorners = [.layerMinXMinYCorner]
|
|
|
|
blurhashOverlayImageViews[2].layer.maskedCorners = [.layerMinXMaxYCorner]
|
2021-02-23 12:18:34 +01:00
|
|
|
default:
|
|
|
|
imageViews[0].layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
|
|
|
|
imageViews[1].layer.maskedCorners = [.layerMaxXMinYCorner]
|
|
|
|
imageViews[2].layer.maskedCorners = [.layerMaxXMaxYCorner]
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
blurhashOverlayImageViews[0].layer.maskedCorners = [.layerMinXMinYCorner, .layerMinXMaxYCorner]
|
|
|
|
blurhashOverlayImageViews[1].layer.maskedCorners = [.layerMaxXMinYCorner]
|
|
|
|
blurhashOverlayImageViews[2].layer.maskedCorners = [.layerMaxXMaxYCorner]
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
} else if count == 4 {
|
|
|
|
contentLeftStackView.addArrangedSubview(imageViews[0])
|
|
|
|
contentRightStackView.addArrangedSubview(imageViews[1])
|
|
|
|
contentLeftStackView.addArrangedSubview(imageViews[2])
|
|
|
|
contentRightStackView.addArrangedSubview(imageViews[3])
|
|
|
|
switch UIApplication.shared.userInterfaceLayoutDirection {
|
|
|
|
case .rightToLeft:
|
|
|
|
imageViews[0].layer.maskedCorners = [.layerMaxXMinYCorner]
|
|
|
|
imageViews[1].layer.maskedCorners = [.layerMinXMinYCorner]
|
|
|
|
imageViews[2].layer.maskedCorners = [.layerMaxXMaxYCorner]
|
|
|
|
imageViews[3].layer.maskedCorners = [.layerMinXMaxYCorner]
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
blurhashOverlayImageViews[0].layer.maskedCorners = [.layerMaxXMinYCorner]
|
|
|
|
blurhashOverlayImageViews[1].layer.maskedCorners = [.layerMinXMinYCorner]
|
|
|
|
blurhashOverlayImageViews[2].layer.maskedCorners = [.layerMaxXMaxYCorner]
|
|
|
|
blurhashOverlayImageViews[3].layer.maskedCorners = [.layerMinXMaxYCorner]
|
2021-02-23 12:18:34 +01:00
|
|
|
default:
|
|
|
|
imageViews[0].layer.maskedCorners = [.layerMinXMinYCorner]
|
|
|
|
imageViews[1].layer.maskedCorners = [.layerMaxXMinYCorner]
|
|
|
|
imageViews[2].layer.maskedCorners = [.layerMinXMaxYCorner]
|
|
|
|
imageViews[3].layer.maskedCorners = [.layerMaxXMaxYCorner]
|
2021-04-16 14:06:36 +02:00
|
|
|
|
|
|
|
blurhashOverlayImageViews[0].layer.maskedCorners = [.layerMinXMinYCorner]
|
|
|
|
blurhashOverlayImageViews[1].layer.maskedCorners = [.layerMaxXMinYCorner]
|
|
|
|
blurhashOverlayImageViews[2].layer.maskedCorners = [.layerMinXMaxYCorner]
|
|
|
|
blurhashOverlayImageViews[3].layer.maskedCorners = [.layerMaxXMaxYCorner]
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-16 14:06:36 +02:00
|
|
|
for (imageView, blurhashOverlayImageView) in zip(imageViews, blurhashOverlayImageViews) {
|
|
|
|
blurhashOverlayImageView.translatesAutoresizingMaskIntoConstraints = false
|
|
|
|
container.addSubview(blurhashOverlayImageView)
|
|
|
|
NSLayoutConstraint.activate([
|
|
|
|
blurhashOverlayImageView.topAnchor.constraint(equalTo: imageView.topAnchor),
|
|
|
|
blurhashOverlayImageView.leadingAnchor.constraint(equalTo: imageView.leadingAnchor),
|
|
|
|
blurhashOverlayImageView.trailingAnchor.constraint(equalTo: imageView.trailingAnchor),
|
|
|
|
blurhashOverlayImageView.bottomAnchor.constraint(equalTo: imageView.bottomAnchor),
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
2021-04-19 12:33:11 +02:00
|
|
|
contentWarningOverlayView.translatesAutoresizingMaskIntoConstraints = false
|
2021-03-12 05:17:07 +01:00
|
|
|
addSubview(contentWarningOverlayView)
|
2021-02-25 06:47:30 +01:00
|
|
|
NSLayoutConstraint.activate([
|
2021-03-12 05:17:07 +01:00
|
|
|
contentWarningOverlayView.topAnchor.constraint(equalTo: container.topAnchor),
|
|
|
|
contentWarningOverlayView.leadingAnchor.constraint(equalTo: container.leadingAnchor),
|
|
|
|
contentWarningOverlayView.trailingAnchor.constraint(equalTo: container.trailingAnchor),
|
|
|
|
contentWarningOverlayView.bottomAnchor.constraint(equalTo: container.bottomAnchor),
|
2021-02-25 06:47:30 +01:00
|
|
|
])
|
|
|
|
|
2021-04-16 14:06:36 +02:00
|
|
|
return zip(imageViews, blurhashOverlayImageViews).map { ($0, $1) }
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
2021-02-25 06:47:30 +01:00
|
|
|
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
2021-04-30 13:28:06 +02:00
|
|
|
// FIXME: refactor blurhash image and preview image
|
2021-04-28 13:06:45 +02:00
|
|
|
extension MosaicImageViewContainer {
|
|
|
|
|
|
|
|
func setImageViews(alpha: CGFloat) {
|
|
|
|
// blurhashOverlayImageViews.forEach { $0.alpha = alpha }
|
|
|
|
imageViews.forEach { $0.alpha = alpha }
|
|
|
|
}
|
|
|
|
|
|
|
|
func setImageView(alpha: CGFloat, index: Int) {
|
|
|
|
// if index < blurhashOverlayImageViews.count {
|
|
|
|
// blurhashOverlayImageViews[index].alpha = alpha
|
|
|
|
// }
|
|
|
|
if index < imageViews.count {
|
|
|
|
imageViews[index].alpha = alpha
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 13:28:06 +02:00
|
|
|
func thumbnail(at index: Int) -> UIImage? {
|
|
|
|
guard blurhashOverlayImageViews.count == imageViews.count else { return nil }
|
|
|
|
let tuples = Array(zip(blurhashOverlayImageViews, imageViews))
|
|
|
|
guard index < tuples.count else { return nil }
|
|
|
|
let tuple = tuples[index]
|
|
|
|
return tuple.1.image ?? tuple.0.image
|
|
|
|
}
|
|
|
|
|
|
|
|
func thumbnails() -> [UIImage?] {
|
|
|
|
guard blurhashOverlayImageViews.count == imageViews.count else { return [] }
|
|
|
|
let tuples = Array(zip(blurhashOverlayImageViews, imageViews))
|
|
|
|
return tuples.map { blurhashOverlayImageView, imageView -> UIImage? in
|
|
|
|
return imageView.image ?? blurhashOverlayImageView.image
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-28 13:06:45 +02:00
|
|
|
}
|
|
|
|
|
2021-02-24 12:19:16 +01:00
|
|
|
extension MosaicImageViewContainer {
|
2021-02-25 06:47:30 +01:00
|
|
|
|
|
|
|
@objc private func visualEffectViewTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
|
|
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
|
2021-03-12 05:17:07 +01:00
|
|
|
delegate?.mosaicImageViewContainer(self, contentWarningOverlayViewDidPressed: contentWarningOverlayView)
|
2021-02-25 06:47:30 +01:00
|
|
|
}
|
|
|
|
|
2021-02-23 12:18:34 +01:00
|
|
|
@objc private func photoTapGestureRecognizerHandler(_ sender: UITapGestureRecognizer) {
|
|
|
|
guard let imageView = sender.view as? UIImageView else { return }
|
|
|
|
guard let index = imageViews.firstIndex(of: imageView) else { return }
|
|
|
|
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: tap photo at index: %ld", ((#file as NSString).lastPathComponent), #line, #function, index)
|
2021-02-24 12:19:16 +01:00
|
|
|
delegate?.mosaicImageViewContainer(self, didTapImageView: imageView, atIndex: index)
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
2021-02-25 06:47:30 +01:00
|
|
|
|
2021-02-23 12:18:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG && canImport(SwiftUI)
|
|
|
|
import SwiftUI
|
|
|
|
|
|
|
|
struct MosaicImageView_Previews: PreviewProvider {
|
|
|
|
|
|
|
|
static var images: [UIImage] {
|
|
|
|
return ["bradley-dunn", "mrdongok", "lucas-ludwig", "markus-spiske"]
|
|
|
|
.map { UIImage(named: $0)! }
|
|
|
|
}
|
|
|
|
|
|
|
|
static var previews: some View {
|
|
|
|
Group {
|
|
|
|
UIViewPreview(width: 375) {
|
2021-02-24 12:19:16 +01:00
|
|
|
let view = MosaicImageViewContainer()
|
2021-02-23 12:18:34 +01:00
|
|
|
let image = images[3]
|
2021-04-16 14:06:36 +02:00
|
|
|
let (imageView, _) = view.setupImageView(
|
2021-02-23 12:18:34 +01:00
|
|
|
aspectRatio: image.size,
|
|
|
|
maxSize: CGSize(width: 375, height: 400)
|
|
|
|
)
|
|
|
|
imageView.image = image
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
.previewLayout(.fixed(width: 375, height: 400))
|
|
|
|
.previewDisplayName("Portrait - one image")
|
|
|
|
UIViewPreview(width: 375) {
|
2021-02-24 12:19:16 +01:00
|
|
|
let view = MosaicImageViewContainer()
|
2021-02-23 12:18:34 +01:00
|
|
|
let image = images[1]
|
2021-04-16 14:06:36 +02:00
|
|
|
let (imageView, _) = view.setupImageView(
|
2021-02-23 12:18:34 +01:00
|
|
|
aspectRatio: image.size,
|
|
|
|
maxSize: CGSize(width: 375, height: 400)
|
|
|
|
)
|
|
|
|
imageView.layer.masksToBounds = true
|
|
|
|
imageView.layer.cornerRadius = 8
|
|
|
|
imageView.contentMode = .scaleAspectFill
|
|
|
|
imageView.image = image
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
.previewLayout(.fixed(width: 375, height: 400))
|
|
|
|
.previewDisplayName("Landscape - one image")
|
|
|
|
UIViewPreview(width: 375) {
|
2021-02-24 12:19:16 +01:00
|
|
|
let view = MosaicImageViewContainer()
|
2021-02-23 12:18:34 +01:00
|
|
|
let images = self.images.prefix(2)
|
2021-04-16 14:06:36 +02:00
|
|
|
let mosaics = view.setupImageViews(count: images.count, maxHeight: 162)
|
|
|
|
for (i, mosiac) in mosaics.enumerated() {
|
|
|
|
let (imageView, blurhashOverlayImageView) = mosiac
|
2021-02-23 12:18:34 +01:00
|
|
|
imageView.image = images[i]
|
|
|
|
}
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
.previewLayout(.fixed(width: 375, height: 200))
|
|
|
|
.previewDisplayName("two image")
|
|
|
|
UIViewPreview(width: 375) {
|
2021-02-24 12:19:16 +01:00
|
|
|
let view = MosaicImageViewContainer()
|
2021-02-23 12:18:34 +01:00
|
|
|
let images = self.images.prefix(3)
|
2021-04-16 14:06:36 +02:00
|
|
|
let mosaics = view.setupImageViews(count: images.count, maxHeight: 162)
|
|
|
|
for (i, mosiac) in mosaics.enumerated() {
|
|
|
|
let (imageView, blurhashOverlayImageView) = mosiac
|
2021-02-23 12:18:34 +01:00
|
|
|
imageView.image = images[i]
|
|
|
|
}
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
.previewLayout(.fixed(width: 375, height: 200))
|
|
|
|
.previewDisplayName("three image")
|
|
|
|
UIViewPreview(width: 375) {
|
2021-02-24 12:19:16 +01:00
|
|
|
let view = MosaicImageViewContainer()
|
2021-02-23 12:18:34 +01:00
|
|
|
let images = self.images.prefix(4)
|
2021-04-16 14:06:36 +02:00
|
|
|
let mosaics = view.setupImageViews(count: images.count, maxHeight: 162)
|
|
|
|
for (i, mosiac) in mosaics.enumerated() {
|
|
|
|
let (imageView, blurhashOverlayImageView) = mosiac
|
2021-02-23 12:18:34 +01:00
|
|
|
imageView.image = images[i]
|
|
|
|
}
|
|
|
|
return view
|
|
|
|
}
|
|
|
|
.previewLayout(.fixed(width: 375, height: 200))
|
|
|
|
.previewDisplayName("four image")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
#endif
|