forked from shadowfacts/Tusker
Hide large image source view during expand/shrink animation
This commit is contained in:
parent
80cf1850dd
commit
fcab6818b0
|
@ -224,6 +224,7 @@
|
||||||
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; };
|
D6DD353D22F28CD000A9563A /* ContentWarningCopyMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */; };
|
||||||
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */; };
|
D6DD353F22F502EC00A9563A /* Preferences+Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */; };
|
||||||
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */; };
|
||||||
|
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */; };
|
||||||
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; };
|
D6E0DC8E216EDF1E00369478 /* Previewing.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E0DC8D216EDF1E00369478 /* Previewing.swift */; };
|
||||||
D6E6F26321603F8B006A8599 /* CharacterCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26221603F8B006A8599 /* CharacterCounter.swift */; };
|
D6E6F26321603F8B006A8599 /* CharacterCounter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26221603F8B006A8599 /* CharacterCounter.swift */; };
|
||||||
D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; };
|
D6E6F26521604242006A8599 /* CharacterCounterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D6E6F26421604242006A8599 /* CharacterCounterTests.swift */; };
|
||||||
|
@ -512,6 +513,7 @@
|
||||||
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
|
D6DD353C22F28CD000A9563A /* ContentWarningCopyMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentWarningCopyMode.swift; sourceTree = "<group>"; };
|
||||||
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Notification.swift"; sourceTree = "<group>"; };
|
D6DD353E22F502EC00A9563A /* Preferences+Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Preferences+Notification.swift"; sourceTree = "<group>"; };
|
||||||
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
D6DFC69D242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TrackpadScrollGestureRecognizer.swift; sourceTree = "<group>"; };
|
||||||
|
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WeakArray.swift; sourceTree = "<group>"; };
|
||||||
D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = "<group>"; };
|
D6E0DC8D216EDF1E00369478 /* Previewing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Previewing.swift; sourceTree = "<group>"; };
|
||||||
D6E6F26221603F8B006A8599 /* CharacterCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounter.swift; sourceTree = "<group>"; };
|
D6E6F26221603F8B006A8599 /* CharacterCounter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounter.swift; sourceTree = "<group>"; };
|
||||||
D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = "<group>"; };
|
D6E6F26421604242006A8599 /* CharacterCounterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CharacterCounterTests.swift; sourceTree = "<group>"; };
|
||||||
|
@ -1213,6 +1215,7 @@
|
||||||
D6945C2E23AC47C3005C403C /* SavedDataManager.swift */,
|
D6945C2E23AC47C3005C403C /* SavedDataManager.swift */,
|
||||||
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
D6028B9A2150811100F223B9 /* MastodonCache.swift */,
|
||||||
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
D6C693EE216192C2007D6A6D /* TuskerNavigationDelegate.swift */,
|
||||||
|
D6DFC69F242C4CCC00ACC392 /* WeakArray.swift */,
|
||||||
D6F1F84E2193B9BE00F5FE67 /* Caching */,
|
D6F1F84E2193B9BE00F5FE67 /* Caching */,
|
||||||
D6757A7A2157E00100721E32 /* XCallbackURL */,
|
D6757A7A2157E00100721E32 /* XCallbackURL */,
|
||||||
D62D241E217AA46B005076CC /* Shortcuts */,
|
D62D241E217AA46B005076CC /* Shortcuts */,
|
||||||
|
@ -1707,6 +1710,7 @@
|
||||||
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
D6945C3223AC4D36005C403C /* HashtagTimelineViewController.swift in Sources */,
|
||||||
D647D92824257BEB0005044F /* AttachmentPreviewViewController.swift in Sources */,
|
D647D92824257BEB0005044F /* AttachmentPreviewViewController.swift in Sources */,
|
||||||
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */,
|
D66362752137068A00C9CBA2 /* Visibility+Helpers.swift in Sources */,
|
||||||
|
D6DFC6A0242C4CCC00ACC392 /* WeakArray.swift in Sources */,
|
||||||
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */,
|
D6C693FC2162FE6F007D6A6D /* LoadingViewController.swift in Sources */,
|
||||||
D646C95A213B5D0500269FB5 /* LargeImageInteractionController.swift in Sources */,
|
D646C95A213B5D0500269FB5 /* LargeImageInteractionController.swift in Sources */,
|
||||||
D6A3BC7C232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift in Sources */,
|
D6A3BC7C232195C600FD64D5 /* ActionNotificationGroupTableViewCell.swift in Sources */,
|
||||||
|
|
|
@ -13,7 +13,7 @@ import AVKit
|
||||||
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, LargeImageAnimatableViewController {
|
class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
let attachments: [Attachment]
|
let attachments: [Attachment]
|
||||||
let sourcesInfo: [LargeImageViewController.SourceInfo?]
|
let sourceViews: WeakArray<UIImageView>
|
||||||
let startIndex: Int
|
let startIndex: Int
|
||||||
|
|
||||||
let pages: [UIViewController]
|
let pages: [UIViewController]
|
||||||
|
@ -26,12 +26,13 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
return index
|
return index
|
||||||
}
|
}
|
||||||
|
|
||||||
var animationSourceInfo: LargeImageViewController.SourceInfo? { sourcesInfo[currentIndex] }
|
var animationSourceView: UIImageView? { sourceViews[currentIndex] }
|
||||||
var animationImage: UIImage? {
|
var animationImage: UIImage? {
|
||||||
if let sourceImage = sourcesInfo[currentIndex]?.image {
|
if let page = pages[currentIndex] as? LoadingLargeImageViewController,
|
||||||
return sourceImage
|
let image = page.largeImageVC?.image {
|
||||||
|
return image
|
||||||
} else {
|
} else {
|
||||||
return (pages[currentIndex] as? LoadingLargeImageViewController)?.largeImageVC?.image
|
return animationSourceView?.image
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
var animationGifData: Data? {
|
var animationGifData: Data? {
|
||||||
|
@ -59,9 +60,9 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
init(attachments: [Attachment], sourcesInfo: [LargeImageViewController.SourceInfo?], startIndex: Int) {
|
init(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) {
|
||||||
self.attachments = attachments
|
self.attachments = attachments
|
||||||
self.sourcesInfo = sourcesInfo
|
self.sourceViews = WeakArray(sourceViews)
|
||||||
self.startIndex = startIndex
|
self.startIndex = startIndex
|
||||||
|
|
||||||
self.pages = attachments.map {
|
self.pages = attachments.map {
|
||||||
|
|
|
@ -11,10 +11,8 @@ import Gifu
|
||||||
|
|
||||||
class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController {
|
class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController {
|
||||||
|
|
||||||
typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat)
|
weak var animationSourceView: UIImageView?
|
||||||
|
var animationImage: UIImage? { image ?? animationSourceView?.image }
|
||||||
var animationSourceInfo: SourceInfo?
|
|
||||||
var animationImage: UIImage? { animationSourceInfo?.image ?? image }
|
|
||||||
var animationGifData: Data? { gifData }
|
var animationGifData: Data? { gifData }
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
|
@ -59,10 +57,10 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
|
||||||
return !controlsVisible
|
return !controlsVisible
|
||||||
}
|
}
|
||||||
|
|
||||||
init(image: UIImage, description: String?, sourceInfo: SourceInfo?) {
|
init(image: UIImage, description: String?, sourceView: UIImageView?) {
|
||||||
self.image = image
|
self.image = image
|
||||||
self.imageDescription = description
|
self.imageDescription = description
|
||||||
self.animationSourceInfo = sourceInfo
|
self.animationSourceView = sourceView
|
||||||
|
|
||||||
super.init(nibName: "LargeImageViewController", bundle: nil)
|
super.init(nibName: "LargeImageViewController", bundle: nil)
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ class LoadingLargeImageViewController: UIViewController, LargeImageAnimatableVie
|
||||||
|
|
||||||
var shrinkGestureEnabled = true
|
var shrinkGestureEnabled = true
|
||||||
|
|
||||||
var animationSourceInfo: LargeImageViewController.SourceInfo?
|
weak var animationSourceView: UIImageView?
|
||||||
var animationImage: UIImage? { animationSourceInfo?.image ?? largeImageVC?.image }
|
var animationImage: UIImage? { largeImageVC?.image ?? animationSourceView?.image }
|
||||||
var animationGifData: Data? { largeImageVC?.gifData }
|
var animationGifData: Data? { largeImageVC?.gifData }
|
||||||
var dismissInteractionController: LargeImageInteractionController?
|
var dismissInteractionController: LargeImageInteractionController?
|
||||||
|
|
||||||
|
@ -108,7 +108,7 @@ class LoadingLargeImageViewController: UIViewController, LargeImageAnimatableVie
|
||||||
|
|
||||||
func createLargeImage(data: Data) {
|
func createLargeImage(data: Data) {
|
||||||
guard let image = UIImage(data: data) else { return }
|
guard let image = UIImage(data: data) else { return }
|
||||||
largeImageVC = LargeImageViewController(image: image, description: imageDescription, sourceInfo: nil)
|
largeImageVC = LargeImageViewController(image: image, description: imageDescription, sourceView: animationSourceView)
|
||||||
largeImageVC!.initialControlsVisible = initialControlsVisible
|
largeImageVC!.initialControlsVisible = initialControlsVisible
|
||||||
largeImageVC!.shrinkGestureEnabled = false
|
largeImageVC!.shrinkGestureEnabled = false
|
||||||
if url.pathExtension == "gif" {
|
if url.pathExtension == "gif" {
|
||||||
|
|
|
@ -10,12 +10,30 @@ import UIKit
|
||||||
import Gifu
|
import Gifu
|
||||||
|
|
||||||
protocol LargeImageAnimatableViewController: UIViewController {
|
protocol LargeImageAnimatableViewController: UIViewController {
|
||||||
var animationSourceInfo: LargeImageViewController.SourceInfo? { get }
|
var animationSourceView: UIImageView? { get }
|
||||||
var animationImage: UIImage? { get }
|
var animationImage: UIImage? { get }
|
||||||
var animationGifData: Data? { get }
|
var animationGifData: Data? { get }
|
||||||
var dismissInteractionController: LargeImageInteractionController? { get }
|
var dismissInteractionController: LargeImageInteractionController? { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension LargeImageAnimatableViewController {
|
||||||
|
func sourceViewFrame(in coordinateSpace: UIView) -> CGRect? {
|
||||||
|
guard let sourceView = animationSourceView else { return nil }
|
||||||
|
|
||||||
|
var sourceFrame = sourceView.convert(sourceView.bounds, to: coordinateSpace)
|
||||||
|
if let scrollView = coordinateSpace as? UIScrollView {
|
||||||
|
let scale = scrollView.zoomScale
|
||||||
|
let width = sourceFrame.width * scale
|
||||||
|
let height = sourceFrame.height * scale
|
||||||
|
let x = sourceFrame.minX * scale - scrollView.contentOffset.x + scrollView.frame.minX
|
||||||
|
let y = sourceFrame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY
|
||||||
|
sourceFrame = CGRect(x: x, y: y, width: width, height: height)
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceFrame
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning {
|
||||||
|
|
||||||
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
|
||||||
|
@ -32,12 +50,16 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
containerView.addSubview(toVC.view)
|
containerView.addSubview(toVC.view)
|
||||||
|
|
||||||
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
let finalVCFrame = transitionContext.finalFrame(for: toVC)
|
||||||
guard let sourceInfo = toVC.animationSourceInfo,
|
guard let sourceView = toVC.animationSourceView,
|
||||||
|
let sourceFrame = toVC.sourceViewFrame(in: fromVC.view),
|
||||||
let image = toVC.animationImage else {
|
let image = toVC.animationImage else {
|
||||||
toVC.view.frame = finalVCFrame
|
toVC.view.frame = finalVCFrame
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use alpha, becaus isHidden makes stack views re-layout
|
||||||
|
sourceView.alpha = 0
|
||||||
|
|
||||||
var finalFrameSize = finalVCFrame.inset(by: fromVC.view.safeAreaInsets).size
|
var finalFrameSize = finalVCFrame.inset(by: fromVC.view.safeAreaInsets).size
|
||||||
let newWidth = finalFrameSize.width / image.size.width
|
let newWidth = finalFrameSize.width / image.size.width
|
||||||
|
@ -49,13 +71,14 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
}
|
}
|
||||||
let finalFrame = CGRect(origin: CGPoint(x: finalVCFrame.midX - finalFrameSize.width / 2, y: finalVCFrame.midY - finalFrameSize.height / 2), size: finalFrameSize)
|
let finalFrame = CGRect(origin: CGPoint(x: finalVCFrame.midX - finalFrameSize.width / 2, y: finalVCFrame.midY - finalFrameSize.height / 2), size: finalFrameSize)
|
||||||
|
|
||||||
let imageView = GIFImageView(frame: sourceInfo.frame)
|
let imageView = GIFImageView(frame: sourceFrame)
|
||||||
imageView.image = image
|
imageView.image = image
|
||||||
if let gifData = toVC.animationGifData {
|
if let gifData = toVC.animationGifData {
|
||||||
imageView.animate(withGIFData: gifData)
|
imageView.animate(withGIFData: gifData)
|
||||||
}
|
}
|
||||||
imageView.contentMode = .scaleAspectFill
|
imageView.contentMode = .scaleAspectFill
|
||||||
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
imageView.layer.cornerRadius = sourceView.layer.cornerRadius
|
||||||
|
imageView.layer.maskedCorners = sourceView.layer.maskedCorners
|
||||||
imageView.layer.masksToBounds = true
|
imageView.layer.masksToBounds = true
|
||||||
|
|
||||||
let blackView = UIView(frame: finalVCFrame)
|
let blackView = UIView(frame: finalVCFrame)
|
||||||
|
@ -84,6 +107,9 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
fromVC.view.isHidden = false
|
fromVC.view.isHidden = false
|
||||||
blackView.removeFromSuperview()
|
blackView.removeFromSuperview()
|
||||||
imageView.removeFromSuperview()
|
imageView.removeFromSuperview()
|
||||||
|
|
||||||
|
sourceView.alpha = 1
|
||||||
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,12 +27,15 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let sourceInfo = fromVC.animationSourceInfo,
|
guard let sourceView = fromVC.animationSourceView,
|
||||||
|
let sourceFrame = fromVC.sourceViewFrame(in: toVC.view),
|
||||||
let image = fromVC.animationImage else {
|
let image = fromVC.animationImage else {
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// use alpha, becaus isHidden makes stack views re-layout
|
||||||
|
sourceView.alpha = 0
|
||||||
|
|
||||||
let containerView = transitionContext.containerView
|
let containerView = transitionContext.containerView
|
||||||
|
|
||||||
|
@ -66,8 +69,9 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
|
|
||||||
let duration = transitionDuration(using: transitionContext)
|
let duration = transitionDuration(using: transitionContext)
|
||||||
UIView.animate(withDuration: duration, animations: {
|
UIView.animate(withDuration: duration, animations: {
|
||||||
imageView.frame = sourceInfo.frame
|
imageView.frame = sourceFrame
|
||||||
imageView.layer.cornerRadius = sourceInfo.cornerRadius
|
imageView.layer.cornerRadius = sourceView.layer.cornerRadius
|
||||||
|
imageView.layer.maskedCorners = sourceView.layer.maskedCorners
|
||||||
blackView.alpha = 0
|
blackView.alpha = 0
|
||||||
}, completion: { _ in
|
}, completion: { _ in
|
||||||
blackView.removeFromSuperview()
|
blackView.removeFromSuperview()
|
||||||
|
@ -75,6 +79,9 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra
|
||||||
if transitionContext.transitionWasCancelled {
|
if transitionContext.transitionWasCancelled {
|
||||||
toVC.view.removeFromSuperview()
|
toVC.view.removeFromSuperview()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sourceView.alpha = 1
|
||||||
|
|
||||||
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
transitionContext.completeTransition(!transitionContext.transitionWasCancelled)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,30 +150,15 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
vc.presentationController?.delegate = compose
|
vc.presentationController?.delegate = compose
|
||||||
present(vc, animated: true)
|
present(vc, animated: true)
|
||||||
}
|
}
|
||||||
|
|
||||||
private func sourceViewInfo(_ sourceView: UIImageView?) -> LargeImageViewController.SourceInfo? {
|
|
||||||
guard let sourceView = sourceView else { return nil }
|
|
||||||
|
|
||||||
var sourceFrame = sourceView.convert(sourceView.bounds, to: view)
|
|
||||||
if let scrollView = view as? UIScrollView {
|
|
||||||
let scale = scrollView.zoomScale
|
|
||||||
let width = sourceFrame.width * scale
|
|
||||||
let height = sourceFrame.height * scale
|
|
||||||
let x = sourceFrame.minX * scale - scrollView.contentOffset.x + scrollView.frame.minX
|
|
||||||
let y = sourceFrame.minY * scale - scrollView.contentOffset.y + scrollView.frame.minY
|
|
||||||
sourceFrame = CGRect(x: x, y: y, width: width, height: height)
|
|
||||||
}
|
|
||||||
return (image: sourceView.image, frame: sourceFrame, cornerRadius: sourceView.layer.cornerRadius)
|
|
||||||
}
|
|
||||||
|
|
||||||
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
||||||
let vc = LargeImageViewController(image: image, description: description, sourceInfo: sourceViewInfo(sourceView))
|
let vc = LargeImageViewController(image: image, description: description, sourceView: sourceView)
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
||||||
func largeImage(gifData: Data, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
func largeImage(gifData: Data, description: String?, sourceView: UIImageView) -> LargeImageViewController {
|
||||||
let vc = LargeImageViewController(image: UIImage(data: gifData)!, description: description, sourceInfo: sourceViewInfo(sourceView))
|
let vc = LargeImageViewController(image: UIImage(data: gifData)!, description: description, sourceView: sourceView)
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
vc.gifData = gifData
|
vc.gifData = gifData
|
||||||
return vc
|
return vc
|
||||||
|
@ -189,7 +174,7 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
|
|
||||||
func loadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) -> LoadingLargeImageViewController {
|
func loadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) -> LoadingLargeImageViewController {
|
||||||
let vc = LoadingLargeImageViewController(url: url, cache: cache, imageDescription: description)
|
let vc = LoadingLargeImageViewController(url: url, cache: cache, imageDescription: description)
|
||||||
vc.animationSourceInfo = sourceViewInfo(sourceView)
|
vc.animationSourceView = sourceView
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
@ -199,8 +184,7 @@ extension TuskerNavigationDelegate where Self: UIViewController {
|
||||||
}
|
}
|
||||||
|
|
||||||
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController {
|
func gallery(attachments: [Attachment], sourceViews: [UIImageView?], startIndex: Int) -> GalleryViewController {
|
||||||
let sourcesInfo = sourceViews.map(sourceViewInfo)
|
let vc = GalleryViewController(attachments: attachments, sourceViews: sourceViews, startIndex: startIndex)
|
||||||
let vc = GalleryViewController(attachments: attachments, sourcesInfo: sourcesInfo, startIndex: startIndex)
|
|
||||||
vc.transitioningDelegate = self
|
vc.transitioningDelegate = self
|
||||||
return vc
|
return vc
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
//
|
||||||
|
// WeakArray.swift
|
||||||
|
// Tusker
|
||||||
|
//
|
||||||
|
// Created by Shadowfacts on 3/25/20.
|
||||||
|
// Copyright © 2020 Shadowfacts. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
|
||||||
|
fileprivate class WeakWrapper<T: AnyObject> {
|
||||||
|
weak var value: T?
|
||||||
|
|
||||||
|
init(_ value: T?) {
|
||||||
|
self.value = value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct WeakArray<Element: AnyObject>: Collection {
|
||||||
|
private var array: [WeakWrapper<Element>]
|
||||||
|
|
||||||
|
var startIndex: Int { array.startIndex }
|
||||||
|
var endIndex: Int { array.endIndex }
|
||||||
|
|
||||||
|
init(_ elements: [Element]) {
|
||||||
|
array = elements.map { WeakWrapper($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
init(_ elements: [Element?]) {
|
||||||
|
array = elements.map { WeakWrapper($0) }
|
||||||
|
}
|
||||||
|
|
||||||
|
subscript(_ index: Int) -> Element? {
|
||||||
|
return array[index].value
|
||||||
|
}
|
||||||
|
|
||||||
|
func index(after i: Int) -> Int {
|
||||||
|
return array.index(after: i)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue