diff --git a/Tusker/Screens/Attachment Gallery/GalleryViewController.swift b/Tusker/Screens/Attachment Gallery/GalleryViewController.swift index fe54b177..a0211ba1 100644 --- a/Tusker/Screens/Attachment Gallery/GalleryViewController.swift +++ b/Tusker/Screens/Attachment Gallery/GalleryViewController.swift @@ -99,11 +99,9 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc return vc case .gifv: // Passing the source view to the LargeImageGifvContentView is a crappy workaround for not - // having the video size directly inside the content view. This will break when there + // having the current frame to use as the animationImage. This will break when there // are more than 4 attachments and there is a gifv at index >= 3 (the More... button will show // in place of the fourth attachment, so there aren't source views for the attachments at index >= 3). - // Really, what should happen is the LargeImageGifvContentView should get the size of the video from - // the AVFoundation instead of the source view. // This isn't a priority as only Mastodon converts gifs to gifvs, and Mastodon (in its default configuration, // I don't know about forks) doesn't allow more than four attachments, meaning there will always be a source view. let gifvContentView = LargeImageGifvContentView(attachment: attachment, source: sourceViews[index]!) diff --git a/Tusker/Screens/Large Image/LargeImageContentView.swift b/Tusker/Screens/Large Image/LargeImageContentView.swift index b995755a..dc05fc9b 100644 --- a/Tusker/Screens/Large Image/LargeImageContentView.swift +++ b/Tusker/Screens/Large Image/LargeImageContentView.swift @@ -146,11 +146,9 @@ class LargeImageGifvContentView: GifvAttachmentView, LargeImageContentView { private let asset: AVURLAsset - // The content view needs to supply an intrinsicContentSize for the LargeImageViewController to handle layout/scrolling/zooming correctly + private var videoSize: CGSize? 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) + videoSize ?? CGSize(width: UIView.noIntrinsicMetric, height: UIView.noIntrinsicMetric) } init(attachment: Attachment, source: UIImageView) { @@ -163,6 +161,17 @@ class LargeImageGifvContentView: GifvAttachmentView, LargeImageContentView { self.animationImage = source.image self.player.play() + + Task { + do { + if let track = try await asset.loadTracks(withMediaType: .video).first { + let (size, transform) = try await track.load(.naturalSize, .preferredTransform) + self.videoSize = size.applying(transform) + self.invalidateIntrinsicContentSize() + } + } catch { + } + } } required init?(coder: NSCoder) { diff --git a/Tusker/Screens/Large Image/LargeImageViewController.swift b/Tusker/Screens/Large Image/LargeImageViewController.swift index 45ae7728..2abed9d0 100644 --- a/Tusker/Screens/Large Image/LargeImageViewController.swift +++ b/Tusker/Screens/Large Image/LargeImageViewController.swift @@ -48,6 +48,7 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma private var prevZoomScale: CGFloat? private var isGrayscale = false + private var contentViewSizeObservation: NSKeyValueObservation? var isInteractivelyAnimatingDismissal: Bool = false { didSet { @@ -127,6 +128,9 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma contentViewLeadingConstraint, contentViewTopConstraint, ]) + contentViewSizeObservation = (contentView as UIView).observe(\.bounds, changeHandler: { [unowned self] _, _ in + self.centerImage() + }) } private func setupControls() { @@ -259,8 +263,6 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma } func scrollViewDidZoom(_ scrollView: UIScrollView) { - centerImage() - let prevZoomScale = self.prevZoomScale ?? scrollView.minimumZoomScale if scrollView.zoomScale <= scrollView.minimumZoomScale { setControlsVisible(true, animated: true)