Show controls/description for gifv attachments

See #98
This commit is contained in:
Shadowfacts 2020-06-17 23:33:48 -04:00
parent 66020b7847
commit 1f40cc9928
Signed by: shadowfacts
GPG Key ID: 94A5AB95422746E5
8 changed files with 154 additions and 97 deletions

View File

@ -168,6 +168,7 @@
D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57B321E2910700C3118B /* ComposeStatusReplyView.swift */; }; D67C57B421E2910700C3118B /* ComposeStatusReplyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D67C57B321E2910700C3118B /* ComposeStatusReplyView.swift */; };
D68015402401A6BA00D6103B /* ComposingPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */; }; D68015402401A6BA00D6103B /* ComposingPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */; };
D68015422401A74600D6103B /* MediaPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68015412401A74600D6103B /* MediaPrefsView.swift */; }; D68015422401A74600D6103B /* MediaPrefsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D68015412401A74600D6103B /* MediaPrefsView.swift */; };
D681A29A249AD62D0085E54E /* LargeImageContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681A299249AD62D0085E54E /* LargeImageContentView.swift */; };
D681E4D3246E2AFF0053414F /* MuteConversationActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D2246E2AFF0053414F /* MuteConversationActivity.swift */; }; D681E4D3246E2AFF0053414F /* MuteConversationActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D2246E2AFF0053414F /* MuteConversationActivity.swift */; };
D681E4D5246E2BC30053414F /* UnmuteConversationActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D4246E2BC30053414F /* UnmuteConversationActivity.swift */; }; D681E4D5246E2BC30053414F /* UnmuteConversationActivity.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D4246E2BC30053414F /* UnmuteConversationActivity.swift */; };
D681E4D7246E32290053414F /* StatusActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D6246E32290053414F /* StatusActivityItemSource.swift */; }; D681E4D7246E32290053414F /* StatusActivityItemSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = D681E4D6246E32290053414F /* StatusActivityItemSource.swift */; };
@ -471,6 +472,7 @@
D67C57B321E2910700C3118B /* ComposeStatusReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusReplyView.swift; sourceTree = "<group>"; }; D67C57B321E2910700C3118B /* ComposeStatusReplyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposeStatusReplyView.swift; sourceTree = "<group>"; };
D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposingPrefsView.swift; sourceTree = "<group>"; }; D680153F2401A6BA00D6103B /* ComposingPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComposingPrefsView.swift; sourceTree = "<group>"; };
D68015412401A74600D6103B /* MediaPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPrefsView.swift; sourceTree = "<group>"; }; D68015412401A74600D6103B /* MediaPrefsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaPrefsView.swift; sourceTree = "<group>"; };
D681A299249AD62D0085E54E /* LargeImageContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LargeImageContentView.swift; sourceTree = "<group>"; };
D681E4D2246E2AFF0053414F /* MuteConversationActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteConversationActivity.swift; sourceTree = "<group>"; }; D681E4D2246E2AFF0053414F /* MuteConversationActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MuteConversationActivity.swift; sourceTree = "<group>"; };
D681E4D4246E2BC30053414F /* UnmuteConversationActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnmuteConversationActivity.swift; sourceTree = "<group>"; }; D681E4D4246E2BC30053414F /* UnmuteConversationActivity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnmuteConversationActivity.swift; sourceTree = "<group>"; };
D681E4D6246E32290053414F /* StatusActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityItemSource.swift; sourceTree = "<group>"; }; D681E4D6246E32290053414F /* StatusActivityItemSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatusActivityItemSource.swift; sourceTree = "<group>"; };
@ -942,6 +944,7 @@
D646C954213B364600269FB5 /* Transitions */, D646C954213B364600269FB5 /* Transitions */,
D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */, D6289E83217B795D0003D1D7 /* LargeImageViewController.xib */,
D6C94D862139E62700CB5196 /* LargeImageViewController.swift */, D6C94D862139E62700CB5196 /* LargeImageViewController.swift */,
D681A299249AD62D0085E54E /* LargeImageContentView.swift */,
041160FE22B442870030A9B7 /* LoadingLargeImageViewController.swift */, 041160FE22B442870030A9B7 /* LoadingLargeImageViewController.swift */,
); );
path = "Large Image"; path = "Large Image";
@ -1770,6 +1773,7 @@
D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */, D663626C21361C6700C9CBA2 /* Account+Preferences.swift in Sources */,
D67895C0246870DE00D4CD9E /* LocalAccountAvatarView.swift in Sources */, D67895C0246870DE00D4CD9E /* LocalAccountAvatarView.swift in Sources */,
D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */, D6333B372137838300CE884A /* AttributedString+Helpers.swift in Sources */,
D681A29A249AD62D0085E54E /* LargeImageContentView.swift in Sources */,
D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */, D6DFC69E242C490400ACC392 /* TrackpadScrollGestureRecognizer.swift in Sources */,
D61AC1D8232EA42D00C54D2D /* InstanceTableViewCell.swift in Sources */, D61AC1D8232EA42D00C54D2D /* InstanceTableViewCell.swift in Sources */,
D63F9C68241C4F79004C03CF /* AddAttachmentTableViewCell.swift in Sources */, D63F9C68241C4F79004C03CF /* AddAttachmentTableViewCell.swift in Sources */,

View File

@ -28,8 +28,8 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
var animationSourceView: UIImageView? { sourceViews[currentIndex] } var animationSourceView: UIImageView? { sourceViews[currentIndex] }
var animationImage: UIImage? { var animationImage: UIImage? {
if let page = pages[currentIndex] as? LoadingLargeImageViewController, if let page = pages[currentIndex] as? LargeImageAnimatableViewController,
let image = page.largeImageVC?.image { let image = page.animationImage {
return image return image
} else { } else {
return animationSourceView?.image return animationSourceView?.image
@ -65,18 +65,29 @@ class GalleryViewController: UIPageViewController, UIPageViewControllerDataSourc
self.sourceViews = WeakArray(sourceViews) self.sourceViews = WeakArray(sourceViews)
self.startIndex = startIndex self.startIndex = startIndex
self.pages = attachments.map { self.pages = attachments.enumerated().map { (index, attachment) in
switch $0.kind { switch attachment.kind {
case .image: case .image:
let vc = LoadingLargeImageViewController(attachment: $0) let vc = LoadingLargeImageViewController(attachment: attachment)
vc.shrinkGestureEnabled = false vc.shrinkGestureEnabled = false
return vc return vc
case .video, .audio: case .video, .audio:
let vc = AVPlayerViewController() let vc = AVPlayerViewController()
vc.player = AVPlayer(url: $0.url) vc.player = AVPlayer(url: attachment.url)
return vc return vc
case .gifv: case .gifv:
return GifvAttachmentViewController(attachment: $0) // 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
// 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]!)
let vc = LargeImageViewController(contentView: gifvContentView, description: attachment.description, sourceView: nil)
vc.shrinkGestureEnabled = false
return vc
default: default:
fatalError() fatalError()
} }

View File

@ -0,0 +1,84 @@
//
// LargeImageContentView.swift
// Tusker
//
// Created by Shadowfacts on 6/17/20.
// Copyright © 2020 Shadowfacts. All rights reserved.
//
import UIKit
import Gifu
import Pachyderm
import AVFoundation
protocol LargeImageContentView {
var animationImage: UIImage? { get }
var animationGifData: Data? { get }
var activityItemsForSharing: [Any] { get }
}
class LargeImageImageContentView: UIImageView, GIFAnimatable, LargeImageContentView {
lazy var animator: Animator? = {
return Animator(withDelegate: self)
}()
var animationImage: UIImage? { image! }
let animationGifData: Data?
var activityItemsForSharing: [Any] {
[image!]
}
init(image: UIImage, gifData: Data?) {
self.animationGifData = gifData
super.init(image: image)
contentMode = .scaleAspectFit
if let data = gifData {
self.animate(withGIFData: data)
}
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override public func display(_ layer: CALayer) {
updateImageIfNeeded()
}
}
class LargeImageGifvContentView: GifvAttachmentView, LargeImageContentView {
private(set) var animationImage: UIImage?
var animationGifData: Data? { nil }
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?
[]
}
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
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}

View File

@ -7,22 +7,17 @@
// //
import UIKit import UIKit
import Gifu
class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController { class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeImageAnimatableViewController {
typealias ContentView = UIView & LargeImageContentView
weak var animationSourceView: UIImageView? weak var animationSourceView: UIImageView?
var animationImage: UIImage? { image ?? animationSourceView?.image } var animationImage: UIImage? { contentView.animationImage }
var animationGifData: Data? { gifData } var animationGifData: Data? { contentView.animationGifData }
var dismissInteractionController: LargeImageInteractionController? var dismissInteractionController: LargeImageInteractionController?
@IBOutlet weak var scrollView: UIScrollView! @IBOutlet weak var scrollView: UIScrollView!
@IBOutlet weak var imageView: GIFImageView!
@IBOutlet weak var imageViewLeadingConstraint: NSLayoutConstraint!
@IBOutlet weak var imageViewTrailingConstraint: NSLayoutConstraint!
@IBOutlet weak var imageViewTopConstraint: NSLayoutConstraint!
@IBOutlet weak var imageViewBottomConstraint: NSLayoutConstraint!
@IBOutlet weak var topControlsView: UIView! @IBOutlet weak var topControlsView: UIView!
@IBOutlet weak var topControlsHeightConstraint: NSLayoutConstraint! @IBOutlet weak var topControlsHeightConstraint: NSLayoutConstraint!
@IBOutlet weak var shareButton: UIButton! @IBOutlet weak var shareButton: UIButton!
@ -35,8 +30,10 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
@IBOutlet weak var bottomControlsView: UIView! @IBOutlet weak var bottomControlsView: UIView!
@IBOutlet weak var descriptionLabel: UILabel! @IBOutlet weak var descriptionLabel: UILabel!
var image: UIImage? var contentView: ContentView
var gifData: Data? var contentViewLeadingConstraint: NSLayoutConstraint!
var contentViewTopConstraint: NSLayoutConstraint!
var imageDescription: String? var imageDescription: String?
var initialControlsVisible = true var initialControlsVisible = true
@ -57,10 +54,11 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
return !controlsVisible return !controlsVisible
} }
init(image: UIImage, description: String?, sourceView: UIImageView?) { init(contentView: ContentView, description: String?, sourceView: UIImageView?) {
self.image = image
self.imageDescription = description self.imageDescription = description
self.animationSourceView = sourceView self.animationSourceView = sourceView
self.contentView = contentView
super.init(nibName: "LargeImageViewController", bundle: nil) super.init(nibName: "LargeImageViewController", bundle: nil)
@ -74,16 +72,20 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
contentView.translatesAutoresizingMaskIntoConstraints = false
scrollView.addSubview(contentView)
contentViewLeadingConstraint = contentView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor)
contentViewTopConstraint = contentView.topAnchor.constraint(equalTo: scrollView.topAnchor)
NSLayoutConstraint.activate([
contentViewLeadingConstraint,
contentViewTopConstraint,
])
setControlsVisible(initialControlsVisible, animated: false) setControlsVisible(initialControlsVisible, animated: false)
shareButton.isEnabled = !contentView.activityItemsForSharing.isEmpty
imageView.image = image
if let gifData = gifData {
imageView.animate(withGIFData: gifData)
}
scrollView.delegate = self scrollView.delegate = self
imageView.bounds = CGRect(origin: .zero, size: imageView.image!.size)
if let imageDescription = imageDescription { if let imageDescription = imageDescription {
descriptionLabel.text = imageDescription descriptionLabel.text = imageDescription
} else { } else {
@ -99,23 +101,24 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
doubleTap.numberOfTapsRequired = 2 doubleTap.numberOfTapsRequired = 2
view.addGestureRecognizer(doubleTap) view.addGestureRecognizer(doubleTap)
} }
override func viewDidLayoutSubviews() { override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
// todo: does this need to be in viewDidLayoutSubviews?
// limit the image height to the safe area height, so the image doesn't overlap the top controls // limit the image height to the safe area height, so the image doesn't overlap the top controls
// while zoomed all the way out // while zoomed all the way out
let maxHeight = view.bounds.height - view.safeAreaInsets.top - view.safeAreaInsets.bottom let maxHeight = view.bounds.height - view.safeAreaInsets.top - view.safeAreaInsets.bottom
let heightScale = maxHeight / imageView.bounds.height let heightScale = maxHeight / contentView.intrinsicContentSize.height
let widthScale = view.bounds.width / imageView.bounds.width let widthScale = view.bounds.width / contentView.intrinsicContentSize.width
let minScale = min(widthScale, heightScale) let minScale = min(widthScale, heightScale)
scrollView.minimumZoomScale = minScale scrollView.minimumZoomScale = minScale
scrollView.zoomScale = minScale scrollView.zoomScale = minScale
scrollView.maximumZoomScale = minScale >= 1 ? minScale + 2 : 2 scrollView.maximumZoomScale = minScale >= 1 ? minScale + 2 : 2
centerImage() centerImage()
// todo: does this need to be in viewDidLayoutSubviews?
if view.safeAreaInsets.top == 44 { if view.safeAreaInsets.top == 44 {
// running on iPhone X style notched device // running on iPhone X style notched device
let notchWidth: CGFloat = 209 let notchWidth: CGFloat = 209
@ -147,7 +150,7 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
} }
func viewForZooming(in scrollView: UIScrollView) -> UIView? { func viewForZooming(in scrollView: UIScrollView) -> UIView? {
return imageView return contentView
} }
func scrollViewDidZoom(_ scrollView: UIScrollView) { func scrollViewDidZoom(_ scrollView: UIScrollView) {
@ -163,18 +166,18 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
} }
func centerImage() { func centerImage() {
let yOffset = max(0, (view.bounds.size.height - imageView.frame.height) / 2) let yOffset = max(0, (view.bounds.size.height - contentView.frame.height) / 2)
imageViewTopConstraint.constant = yOffset contentViewTopConstraint.constant = yOffset
let xOffset = max(0, (view.bounds.size.width - imageView.frame.width) / 2) let xOffset = max(0, (view.bounds.size.width - contentView.frame.width) / 2)
imageViewLeadingConstraint.constant = xOffset contentViewLeadingConstraint.constant = xOffset
} }
func zoomRectFor(scale: CGFloat, center: CGPoint) -> CGRect { func zoomRectFor(scale: CGFloat, center: CGPoint) -> CGRect {
var zoomRect = CGRect.zero var zoomRect = CGRect.zero
zoomRect.size.width = imageView.frame.width / scale zoomRect.size.width = contentView.frame.width / scale
zoomRect.size.height = imageView.frame.height / scale zoomRect.size.height = contentView.frame.height / scale
let newCenter = scrollView.convert(center, to: imageView) let newCenter = scrollView.convert(center, to: contentView)
zoomRect.origin.x = newCenter.x - (zoomRect.width / 2) zoomRect.origin.x = newCenter.x - (zoomRect.width / 2)
zoomRect.origin.y = newCenter.y - (zoomRect.height / 2) zoomRect.origin.y = newCenter.y - (zoomRect.height / 2)
return zoomRect return zoomRect
@ -225,11 +228,8 @@ class LargeImageViewController: UIViewController, UIScrollViewDelegate, LargeIma
} }
@IBAction func sharePressed(_ sender: Any) { @IBAction func sharePressed(_ sender: Any) {
guard let image = image else { return } let activityVC = UIActivityViewController(activityItems: contentView.activityItemsForSharing, applicationActivities: nil)
let activityVC = UIActivityViewController(activityItems: [image], applicationActivities: nil) activityVC.popoverPresentationController?.sourceView = shareButton
if let presentationController = activityVC.presentationController as? UIPopoverPresentationController {
presentationController.sourceView = shareButton
}
present(activityVC, animated: true) present(activityVC, animated: true)
} }

View File

@ -14,9 +14,6 @@
<outlet property="closeButtonTopConstraint" destination="ImD-2H-0XK" id="DUe-b1-a2N"/> <outlet property="closeButtonTopConstraint" destination="ImD-2H-0XK" id="DUe-b1-a2N"/>
<outlet property="closeButtonTrailingConstraint" destination="JFe-ig-3Ic" id="cWO-Rr-y3F"/> <outlet property="closeButtonTrailingConstraint" destination="JFe-ig-3Ic" id="cWO-Rr-y3F"/>
<outlet property="descriptionLabel" destination="eo5-fc-RV8" id="vrW-RJ-y5k"/> <outlet property="descriptionLabel" destination="eo5-fc-RV8" id="vrW-RJ-y5k"/>
<outlet property="imageView" destination="qcn-1t-3sS" id="Q01-G2-y1c"/>
<outlet property="imageViewLeadingConstraint" destination="bI3-V8-M70" id="nIe-xI-E9u"/>
<outlet property="imageViewTopConstraint" destination="tfL-hp-2I2" id="EDV-RO-pTe"/>
<outlet property="scrollView" destination="Skj-xq-AgQ" id="TFb-zF-m1b"/> <outlet property="scrollView" destination="Skj-xq-AgQ" id="TFb-zF-m1b"/>
<outlet property="shareButton" destination="vhp-0u-Q0S" id="JZS-K9-4w9"/> <outlet property="shareButton" destination="vhp-0u-Q0S" id="JZS-K9-4w9"/>
<outlet property="shareButtonLeadingConstraint" destination="MJx-2r-p0k" id="Dn5-Eg-Pid"/> <outlet property="shareButtonLeadingConstraint" destination="MJx-2r-p0k" id="Dn5-Eg-Pid"/>
@ -31,19 +28,9 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" ambiguous="YES" minimumZoomScale="0.25" maximumZoomScale="2" translatesAutoresizingMaskIntoConstraints="NO" id="Skj-xq-AgQ"> <scrollView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" minimumZoomScale="0.25" maximumZoomScale="2" translatesAutoresizingMaskIntoConstraints="NO" id="Skj-xq-AgQ">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<subviews>
<imageView contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" ambiguous="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qcn-1t-3sS" customClass="GIFImageView" customModule="Gifu">
<rect key="frame" x="0.0" y="-10" width="375" height="647"/>
<gestureRecognizers/>
</imageView>
</subviews>
<gestureRecognizers/> <gestureRecognizers/>
<constraints>
<constraint firstItem="qcn-1t-3sS" firstAttribute="leading" secondItem="Skj-xq-AgQ" secondAttribute="leading" id="bI3-V8-M70"/>
<constraint firstItem="qcn-1t-3sS" firstAttribute="top" secondItem="Skj-xq-AgQ" secondAttribute="top" id="tfL-hp-2I2"/>
</constraints>
</scrollView> </scrollView>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kHo-B9-R7a"> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kHo-B9-R7a">
<rect key="frame" x="0.0" y="0.0" width="375" height="36"/> <rect key="frame" x="0.0" y="0.0" width="375" height="36"/>

View File

@ -36,8 +36,8 @@ class LoadingLargeImageViewController: UIViewController, LargeImageAnimatableVie
var shrinkGestureEnabled = true var shrinkGestureEnabled = true
weak var animationSourceView: UIImageView? weak var animationSourceView: UIImageView?
var animationImage: UIImage? { largeImageVC?.image ?? animationSourceView?.image } var animationImage: UIImage? { largeImageVC?.animationImage ?? animationSourceView?.image }
var animationGifData: Data? { largeImageVC?.gifData } var animationGifData: Data? { largeImageVC?.animationGifData }
var dismissInteractionController: LargeImageInteractionController? var dismissInteractionController: LargeImageInteractionController?
override var prefersStatusBarHidden: Bool { override var prefersStatusBarHidden: Bool {
@ -108,12 +108,12 @@ 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, sourceView: animationSourceView) let gifData = url.pathExtension == "gif" ? data : nil
let imageView = LargeImageImageContentView(image: image, gifData: gifData)
largeImageVC = LargeImageViewController(contentView: imageView, description: imageDescription, sourceView: animationSourceView)
largeImageVC!.initialControlsVisible = initialControlsVisible largeImageVC!.initialControlsVisible = initialControlsVisible
largeImageVC!.shrinkGestureEnabled = false largeImageVC!.shrinkGestureEnabled = false
if url.pathExtension == "gif" {
largeImageVC!.gifData = data
}
embedChild(largeImageVC!) embedChild(largeImageVC!)
} }

View File

@ -36,14 +36,6 @@ protocol TuskerNavigationDelegate: class {
func reply(to statusID: String, mentioningAcct: String?) func reply(to statusID: String, mentioningAcct: String?)
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController
func largeImage(gifData: Data, description: String?, sourceView: UIImageView) -> LargeImageViewController
func showLargeImage(_ image: UIImage, description: String?, animatingFrom sourceView: UIImageView)
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIImageView)
func loadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) -> LoadingLargeImageViewController func loadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) -> LoadingLargeImageViewController
func showLoadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView) func showLoadingLargeImage(url: URL, cache: ImageCache, description: String?, animatingFrom sourceView: UIImageView)
@ -150,27 +142,6 @@ extension TuskerNavigationDelegate where Self: UIViewController {
vc.presentationController?.delegate = compose vc.presentationController?.delegate = compose
present(vc, animated: true) present(vc, animated: true)
} }
func largeImage(_ image: UIImage, description: String?, sourceView: UIImageView) -> LargeImageViewController {
let vc = LargeImageViewController(image: image, description: description, sourceView: sourceView)
vc.transitioningDelegate = self
return vc
}
func largeImage(gifData: Data, description: String?, sourceView: UIImageView) -> LargeImageViewController {
let vc = LargeImageViewController(image: UIImage(data: gifData)!, description: description, sourceView: sourceView)
vc.transitioningDelegate = self
vc.gifData = gifData
return vc
}
func showLargeImage(_ image: UIImage, description: String?, animatingFrom sourceView: UIImageView) {
present(largeImage(image, description: description, sourceView: sourceView), animated: true)
}
func showLargeImage(gifData: Data, description: String?, animatingFrom sourceView: UIImageView) {
present(largeImage(gifData: gifData, description: description, sourceView: sourceView), animated: true)
}
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)

View File

@ -19,8 +19,8 @@ class GifvAttachmentView: UIView {
layer as! AVPlayerLayer layer as! AVPlayerLayer
} }
private let item: AVPlayerItem let item: AVPlayerItem
private let player: AVPlayer let player: AVPlayer
init(asset: AVAsset, gravity: AVLayerVideoGravity) { init(asset: AVAsset, gravity: AVLayerVideoGravity) {
item = AVPlayerItem(asset: asset) item = AVPlayerItem(asset: asset)