diff --git a/Tusker.xcodeproj/project.pbxproj b/Tusker.xcodeproj/project.pbxproj index 82d22558..bcb5cd19 100644 --- a/Tusker.xcodeproj/project.pbxproj +++ b/Tusker.xcodeproj/project.pbxproj @@ -13,8 +13,6 @@ 0427033A22B31269000D31B6 /* AdvancedPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */; }; 0427037C22B316B9000D31B6 /* SilentActionPrefs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */; }; 0450531F22B0097E00100BA2 /* Timline+UI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0450531E22B0097E00100BA2 /* Timline+UI.swift */; }; - 0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */; }; - 0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */; }; 04586B4122B2FFB10021BD04 /* PreferencesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4022B2FFB10021BD04 /* PreferencesView.swift */; }; 04586B4322B301470021BD04 /* AppearancePrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 04586B4222B301470021BD04 /* AppearancePrefsView.swift */; }; 0461A3902163CBAE00C0A807 /* Cache.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0461A38F2163CBAE00C0A807 /* Cache.framework */; }; @@ -297,8 +295,6 @@ 0427033922B31269000D31B6 /* AdvancedPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AdvancedPrefsView.swift; sourceTree = ""; }; 0427037B22B316B9000D31B6 /* SilentActionPrefs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SilentActionPrefs.swift; sourceTree = ""; }; 0450531E22B0097E00100BA2 /* Timline+UI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Timline+UI.swift"; sourceTree = ""; }; - 0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryExpandAnimationController.swift; sourceTree = ""; }; - 0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GalleryShrinkAnimationController.swift; sourceTree = ""; }; 04586B4022B2FFB10021BD04 /* PreferencesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesView.swift; sourceTree = ""; }; 04586B4222B301470021BD04 /* AppearancePrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearancePrefsView.swift; sourceTree = ""; }; 0461A38F2163CBAE00C0A807 /* Cache.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Cache.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -584,21 +580,11 @@ 0411610522B457290030A9B7 /* Gallery */ = { isa = PBXGroup; children = ( - 0411610622B457360030A9B7 /* Transitions */, 04D14BAE22B34A2800642648 /* GalleryViewController.swift */, ); path = Gallery; sourceTree = ""; }; - 0411610622B457360030A9B7 /* Transitions */ = { - isa = PBXGroup; - children = ( - 0454DDAE22B462EF00B8BB8E /* GalleryExpandAnimationController.swift */, - 0454DDB022B467AA00B8BB8E /* GalleryShrinkAnimationController.swift */, - ); - path = Transitions; - sourceTree = ""; - }; D61099AC2144B0CC00432DC2 /* Pachyderm */ = { isa = PBXGroup; children = ( @@ -1630,7 +1616,6 @@ D6BC9DB1232C61BC002CA326 /* NotificationsPageViewController.swift in Sources */, D6969E9E240C81B9002843CE /* NSTextAttachment+Emoji.swift in Sources */, D6BC9DB3232D4C07002CA326 /* WellnessPrefsView.swift in Sources */, - 0454DDAF22B462EF00B8BB8E /* GalleryExpandAnimationController.swift in Sources */, D64BC18F23C18B9D000D0238 /* FollowRequestNotificationTableViewCell.swift in Sources */, D693DE5923FE24310061E07D /* InteractivePushTransition.swift in Sources */, D6A3BC8A2321F79B00FD64D5 /* AccountTableViewCell.swift in Sources */, @@ -1664,7 +1649,6 @@ D64BC18823C1640A000D0238 /* PinStatusActivity.swift in Sources */, D6674AEA23341F7600E8DF94 /* AppShortcutItems.swift in Sources */, D646C956213B365700269FB5 /* LargeImageExpandAnimationController.swift in Sources */, - 0454DDB122B467AA00B8BB8E /* GalleryShrinkAnimationController.swift in Sources */, D667E5F82135C3040057A976 /* Mastodon+Equatable.swift in Sources */, D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */, D6B053A623BD2D0C00A066FA /* AssetCollectionViewController.swift in Sources */, diff --git a/Tusker/Extensions/UIViewController+Delegates.swift b/Tusker/Extensions/UIViewController+Delegates.swift index 27e87026..f3c61a4c 100644 --- a/Tusker/Extensions/UIViewController+Delegates.swift +++ b/Tusker/Extensions/UIViewController+Delegates.swift @@ -10,23 +10,17 @@ import UIKit extension UIViewController: UIViewControllerTransitioningDelegate { public func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? { - if let presented = presented as? LargeImageViewController, - presented.sourceInfo?.image != nil { + if let presented = presented as? LargeImageAnimatableViewController, + presented.animationImage != nil { return LargeImageExpandAnimationController() - } else if let presented = presented as? GalleryViewController, - presented.sourcesInfo[presented.startIndex]?.image != nil { - return GalleryExpandAnimationController() } return nil } public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { - if let dismissed = dismissed as? LargeImageViewController, - dismissed.imageForDismissalAnimation() != nil { + if let dismissed = dismissed as? LargeImageAnimatableViewController, + dismissed.animationImage != nil { return LargeImageShrinkAnimationController(interactionController: dismissed.dismissInteractionController) - } else if let dismissed = dismissed as? GalleryViewController, - dismissed.imageForDismissalAnimation() != nil { - return GalleryShrinkAnimationController(interactionController: dismissed.dismissInteractionController) } return nil } @@ -36,10 +30,6 @@ extension UIViewController: UIViewControllerTransitioningDelegate { let interactionController = animator.interactionController, interactionController.inProgress { return interactionController - } else if let animator = animator as? GalleryShrinkAnimationController, - let interactionController = animator.interactionController, - interactionController.inProgress { - return interactionController } return nil } diff --git a/Tusker/Screens/Gallery/GalleryViewController.swift b/Tusker/Screens/Gallery/GalleryViewController.swift index 8c8bc2a2..29cb5c60 100644 --- a/Tusker/Screens/Gallery/GalleryViewController.swift +++ b/Tusker/Screens/Gallery/GalleryViewController.swift @@ -10,10 +10,8 @@ import Pachyderm import AVFoundation import AVKit -class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate { +class GalleryViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, LargeImageAnimatableViewController { - var dismissInteractionController: LargeImageInteractionController? - let attachments: [Attachment] let sourcesInfo: [LargeImageViewController.SourceInfo?] let startIndex: Int @@ -27,6 +25,24 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc } return index } + + var animationSourceInfo: LargeImageViewController.SourceInfo? { sourcesInfo[currentIndex] } + var animationImage: UIImage? { + if let sourceImage = sourcesInfo[currentIndex]?.image { + return sourceImage + } else { + return (pages[currentIndex] as? AttachmentViewController)?.largeImageVC?.image + } + } + var animationGifData: Data? { + let attachment = attachments[currentIndex] + if attachment.url.pathExtension == "gif" { + return ImageCache.attachments.get(attachment.url) + } else { + return nil + } + } + var dismissInteractionController: LargeImageInteractionController? override var prefersStatusBarHidden: Bool { return true @@ -96,14 +112,6 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc vc.player?.play() } } - - func imageForDismissalAnimation() -> UIImage? { - if let sourceImage = sourcesInfo[currentIndex]?.image { - return sourceImage - } else { - return (pages[currentIndex] as? AttachmentViewController)?.largeImageVC?.image - } - } // MARK: - Page View Controller Data Source diff --git a/Tusker/Screens/Gallery/Transitions/GalleryExpandAnimationController.swift b/Tusker/Screens/Gallery/Transitions/GalleryExpandAnimationController.swift deleted file mode 100644 index 03033d9f..00000000 --- a/Tusker/Screens/Gallery/Transitions/GalleryExpandAnimationController.swift +++ /dev/null @@ -1,84 +0,0 @@ -// GalleryExpandAnimationController.swift -// Tusker -// -// Created by Shadowfacts on 6/14/19. -// Copyright © 2019 Shadowfacts. All rights reserved. -// - -import UIKit -import Gifu - -class GalleryExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning { - - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.2 - } - - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - guard let fromVC = transitionContext.viewController(forKey: .from), - let toVC = transitionContext.viewController(forKey: .to) as? GalleryViewController else { - return - } - - let containerView = transitionContext.containerView - containerView.addSubview(toVC.view) - - let finalVCFrame = transitionContext.finalFrame(for: toVC) - guard let sourceInfo = toVC.sourcesInfo[toVC.startIndex], - let image = sourceInfo.image else { - toVC.view.frame = finalVCFrame - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - return - } - - let attachment = toVC.attachments[toVC.startIndex] - - let ratio = image.size.width / image.size.height - var width = finalVCFrame.width - var height = width / ratio - let maxHeight = fromVC.view.bounds.height - fromVC.view.safeAreaInsets.top - fromVC.view.safeAreaInsets.bottom - if height > maxHeight { - let scaleFactor = maxHeight / height - width *= scaleFactor - height = maxHeight - } - let finalFrame = CGRect(x: finalVCFrame.midX - width / 2, y: finalVCFrame.midY - height / 2, width: width, height: height) - - let imageView = GIFImageView(frame: sourceInfo.frame) - imageView.image = image - if attachment.url.pathExtension == "gif", - let data = ImageCache.attachments.get(attachment.url) { - imageView.animate(withGIFData: data) - } - imageView.contentMode = .scaleAspectFill - imageView.layer.cornerRadius = sourceInfo.cornerRadius - imageView.layer.masksToBounds = true - - let blackView = UIView(frame: finalVCFrame) - blackView.backgroundColor = .black - blackView.alpha = 0 - - containerView.addSubview(blackView) - containerView.addSubview(imageView) - - toVC.view.isHidden = true - - let duration = transitionDuration(using: transitionContext) - UIView.animate(withDuration: duration, animations: { - imageView.frame = finalFrame - imageView.layer.cornerRadius = 0 - blackView.alpha = 1 - }, completion: { _ in - toVC.view.frame = finalVCFrame - - toVC.view.isHidden = false - fromVC.view.isHidden = false - blackView.removeFromSuperview() - imageView.removeFromSuperview() - - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) - - } - -} diff --git a/Tusker/Screens/Gallery/Transitions/GalleryShrinkAnimationController.swift b/Tusker/Screens/Gallery/Transitions/GalleryShrinkAnimationController.swift deleted file mode 100644 index d3fdf9c6..00000000 --- a/Tusker/Screens/Gallery/Transitions/GalleryShrinkAnimationController.swift +++ /dev/null @@ -1,84 +0,0 @@ -// GalleryShrinkAnimationController.swift -// Tusker -// -// Created by Shadowfacts on 6/14/19. -// Copyright © 2019 Shadowfacts. All rights reserved. -// - -import UIKit -import Gifu - -class GalleryShrinkAnimationController: NSObject, UIViewControllerAnimatedTransitioning { - - let interactionController: LargeImageInteractionController? - - init(interactionController: LargeImageInteractionController?) { - self.interactionController = interactionController - } - - func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { - return 0.2 - } - - func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - guard let fromVC = transitionContext.viewController(forKey: .from) as? GalleryViewController, - let toVC = transitionContext.viewController(forKey: .to) else { - return - } - - guard let sourceInfo = fromVC.sourcesInfo[fromVC.currentIndex], - let image = fromVC.imageForDismissalAnimation() else { - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - return - } - let originalVCFrame = fromVC.view.frame - - let attachment = fromVC.attachments[fromVC.currentIndex] - - let ratio = image.size.width / image.size.height - var width = originalVCFrame.width - var height = width / ratio - let maxHeight = fromVC.view.bounds.height - fromVC.view.safeAreaInsets.top - fromVC.view.safeAreaInsets.bottom - if height > maxHeight { - let scaleFactor = maxHeight / height - width *= scaleFactor - height = maxHeight - } - let originalFrame = CGRect(x: originalVCFrame.midX - width / 2, y: originalVCFrame.midY - height / 2, width: width, height: height) - - let imageView = GIFImageView(frame: originalFrame) - imageView.image = image - if attachment.url.pathExtension == "gif", - let data = ImageCache.attachments.get(attachment.url) { - imageView.animate(withGIFData: data) - } - imageView.contentMode = .scaleAspectFill - imageView.layer.cornerRadius = 0 - imageView.layer.masksToBounds = true - - let blackView = UIView(frame: originalVCFrame) - blackView.backgroundColor = .black - blackView.alpha = 1 - - let containerView = transitionContext.containerView - containerView.addSubview(toVC.view) - containerView.addSubview(blackView) - containerView.addSubview(imageView) - - let duration = transitionDuration(using: transitionContext) - UIView.animate(withDuration: duration, animations: { - imageView.frame = sourceInfo.frame - imageView.layer.cornerRadius = sourceInfo.cornerRadius - blackView.alpha = 0 - }, completion: { _ in - blackView.removeFromSuperview() - imageView.removeFromSuperview() - - if transitionContext.transitionWasCancelled { - toVC.view.removeFromSuperview() - } - - transitionContext.completeTransition(!transitionContext.transitionWasCancelled) - }) - } -} diff --git a/Tusker/Screens/Large Image/LargeImageViewController.swift b/Tusker/Screens/Large Image/LargeImageViewController.swift index 45890c52..4375ff77 100644 --- a/Tusker/Screens/Large Image/LargeImageViewController.swift +++ b/Tusker/Screens/Large Image/LargeImageViewController.swift @@ -11,11 +11,13 @@ import Pachyderm import Photos import Gifu -class LargeImageViewController: UIViewController, UIScrollViewDelegate { +class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController { typealias SourceInfo = (image: UIImage?, frame: CGRect, cornerRadius: CGFloat) - var sourceInfo: SourceInfo? + var animationSourceInfo: SourceInfo? + var animationImage: UIImage? { animationSourceInfo?.image ?? image } + var animationGifData: Data? { gifData } var dismissInteractionController: LargeImageInteractionController? @IBOutlet weak var scrollView: UIScrollView! @@ -62,7 +64,7 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate { init(image: UIImage, description: String?, sourceInfo: SourceInfo?) { self.image = image self.imageDescription = description - self.sourceInfo = sourceInfo + self.animationSourceInfo = sourceInfo super.init(nibName: "LargeImageViewController", bundle: nil) @@ -127,10 +129,6 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate { closeButtonTrailingConstraint.constant = offset } } - - func imageForDismissalAnimation() -> UIImage? { - return sourceInfo?.image ?? image - } func setControlsVisible(_ controlsVisible: Bool, animated: Bool) { self.controlsVisible = controlsVisible diff --git a/Tusker/Screens/Large Image/Transitions/LargeImageExpandAnimationController.swift b/Tusker/Screens/Large Image/Transitions/LargeImageExpandAnimationController.swift index 049ef9c9..2388a58c 100644 --- a/Tusker/Screens/Large Image/Transitions/LargeImageExpandAnimationController.swift +++ b/Tusker/Screens/Large Image/Transitions/LargeImageExpandAnimationController.swift @@ -9,6 +9,13 @@ import UIKit import Gifu +protocol LargeImageAnimatableViewController: UIViewController { + var animationSourceInfo: LargeImageViewController.SourceInfo? { get } + var animationImage: UIImage? { get } + var animationGifData: Data? { get } + var dismissInteractionController: LargeImageInteractionController? { get } +} + class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTransitioning { func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { @@ -17,7 +24,7 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromVC = transitionContext.viewController(forKey: .from), - let toVC = transitionContext.viewController(forKey: .to) as? LargeImageViewController else { + let toVC = transitionContext.viewController(forKey: .to) as? LargeImageAnimatableViewController else { return } @@ -25,8 +32,8 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra containerView.addSubview(toVC.view) let finalVCFrame = transitionContext.finalFrame(for: toVC) - guard let sourceInfo = toVC.sourceInfo, - let image = sourceInfo.image else { + guard let sourceInfo = toVC.animationSourceInfo, + let image = toVC.animationImage else { toVC.view.frame = finalVCFrame transitionContext.completeTransition(!transitionContext.transitionWasCancelled) return @@ -39,7 +46,7 @@ class LargeImageExpandAnimationController: NSObject, UIViewControllerAnimatedTra let imageView = GIFImageView(frame: sourceInfo.frame) imageView.image = image - if let gifData = toVC.gifData { + if let gifData = toVC.animationGifData { imageView.animate(withGIFData: gifData) } imageView.contentMode = .scaleAspectFill diff --git a/Tusker/Screens/Large Image/Transitions/LargeImageShrinkAnimationController.swift b/Tusker/Screens/Large Image/Transitions/LargeImageShrinkAnimationController.swift index 1aebef1e..6cd042f6 100644 --- a/Tusker/Screens/Large Image/Transitions/LargeImageShrinkAnimationController.swift +++ b/Tusker/Screens/Large Image/Transitions/LargeImageShrinkAnimationController.swift @@ -22,13 +22,13 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { - guard let fromVC = transitionContext.viewController(forKey: .from) as? LargeImageViewController, + guard let fromVC = transitionContext.viewController(forKey: .from) as? LargeImageAnimatableViewController, let toVC = transitionContext.viewController(forKey: .to) else { return } - guard let sourceInfo = fromVC.sourceInfo, - let image = fromVC.imageForDismissalAnimation() else { + guard let sourceInfo = fromVC.animationSourceInfo, + let image = fromVC.animationImage else { transitionContext.completeTransition(!transitionContext.transitionWasCancelled) return } @@ -43,7 +43,7 @@ class LargeImageShrinkAnimationController: NSObject, UIViewControllerAnimatedTra let imageView = GIFImageView(frame: originalFrame) imageView.image = image - if let gifData = fromVC.gifData { + if let gifData = fromVC.animationGifData { imageView.animate(withGIFData: gifData) } imageView.contentMode = .scaleAspectFill