|  |  | @ -101,11 +101,17 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  |         Logger.debug("deinit") |  |  |  |         Logger.debug("deinit") | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var bottomContainer: UIView! | 
			
		
	
		
		
			
				
					
					|  |  |  |     var footerBar: UIToolbar! |  |  |  |     var footerBar: UIToolbar! | 
			
		
	
		
		
			
				
					
					|  |  |  |     var videoPlayBarButton: UIBarButtonItem! |  |  |  |     var videoPlayBarButton: UIBarButtonItem! | 
			
		
	
		
		
			
				
					
					|  |  |  |     var videoPauseBarButton: UIBarButtonItem! |  |  |  |     var videoPauseBarButton: UIBarButtonItem! | 
			
		
	
		
		
			
				
					
					|  |  |  |     var pagerScrollView: UIScrollView! |  |  |  |     var pagerScrollView: UIScrollView! | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // MARK: Caption | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var currentCaptionView: CaptionView! | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var pendingCaptionView: CaptionView! | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     override func viewDidLoad() { |  |  |  |     override func viewDidLoad() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         super.viewDidLoad() |  |  |  |         super.viewDidLoad() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -142,6 +148,10 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  |         // e.g. when getting to media details via message details screen, there's only |  |  |  |         // e.g. when getting to media details via message details screen, there's only | 
			
		
	
		
		
			
				
					
					|  |  |  |         // one "Page" so the bounce doesn't make sense. |  |  |  |         // one "Page" so the bounce doesn't make sense. | 
			
		
	
		
		
			
				
					
					|  |  |  |         pagerScrollView.isScrollEnabled = sliderEnabled |  |  |  |         pagerScrollView.isScrollEnabled = sliderEnabled | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         pagerScrollViewContentOffsetObservation = pagerScrollView.observe(\.contentOffset, options: [.new]) { [weak self] object, change in | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             guard let strongSelf = self else { return } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             strongSelf.pagerScrollView(strongSelf.pagerScrollView, contentOffsetDidChange: change) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         // Views |  |  |  |         // Views | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -152,12 +162,44 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  |         let footerBar = UIToolbar() |  |  |  |         let footerBar = UIToolbar() | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.footerBar = footerBar |  |  |  |         self.footerBar = footerBar | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let captionViewsContainer = UIView() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let kMaxCaptionHeight: CGFloat = ScaleFromIPhone5(300) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         captionViewsContainer.autoSetDimension(.height, toSize: kMaxCaptionHeight, relation: .lessThanOrEqual) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         captionViewsContainer.setContentHuggingHigh() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         captionViewsContainer.setCompressionResistanceHigh() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let currentCaptionView = CaptionView() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.currentCaptionView = currentCaptionView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         captionViewsContainer.addSubview(currentCaptionView) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         currentCaptionView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         currentCaptionView.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         currentCaptionView.setContentHuggingHigh() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         currentCaptionView.setCompressionResistanceHigh() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         currentCaptionView.text = currentItem.caption | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let pendingCaptionView = CaptionView() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.pendingCaptionView = pendingCaptionView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         pendingCaptionView.alpha = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         captionViewsContainer.addSubview(pendingCaptionView) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         pendingCaptionView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .top) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         pendingCaptionView.autoPinEdge(toSuperviewEdge: .top, withInset: 0, relation: .greaterThanOrEqual) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         pendingCaptionView.setContentHuggingHigh() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         pendingCaptionView.setCompressionResistanceHigh() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let bottomContainer = UIView() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.bottomContainer = bottomContainer | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let bottomStack = UIStackView(arrangedSubviews: [captionViewsContainer, footerBar]) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         bottomStack.axis = .vertical | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         bottomContainer.addSubview(bottomStack) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         bottomStack.autoPinEdgesToSuperviewEdges() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.videoPlayBarButton = UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(didPressPlayBarButton)) |  |  |  |         self.videoPlayBarButton = UIBarButtonItem(barButtonSystemItem: .play, target: self, action: #selector(didPressPlayBarButton)) | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.videoPauseBarButton = UIBarButtonItem(barButtonSystemItem: .pause, target: self, action: #selector(didPressPauseBarButton)) |  |  |  |         self.videoPauseBarButton = UIBarButtonItem(barButtonSystemItem: .pause, target: self, action: #selector(didPressPauseBarButton)) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.updateFooterBarButtonItems(isPlayingVideo: true) |  |  |  |         self.updateFooterBarButtonItems(isPlayingVideo: true) | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.view.addSubview(footerBar) |  |  |  |         self.view.addSubview(bottomContainer) | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  |         footerBar.autoPinWidthToSuperview() |  |  |  |         bottomContainer.autoPinWidthToSuperview() | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         bottomContainer.autoPinEdge(toSuperviewEdge: .bottom) | 
			
		
	
		
		
			
				
					
					|  |  |  |         footerBar.autoPin(toBottomLayoutGuideOf: self, withInset: 0) |  |  |  |         footerBar.autoPin(toBottomLayoutGuideOf: self, withInset: 0) | 
			
		
	
		
		
			
				
					
					|  |  |  |         footerBar.autoSetDimension(.height, toSize: kFooterHeight) |  |  |  |         footerBar.autoSetDimension(.height, toSize: kFooterHeight) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -168,6 +210,44 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  |         view.addGestureRecognizer(verticalSwipe) |  |  |  |         view.addGestureRecognizer(verticalSwipe) | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     // MARK: KVO | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var pagerScrollViewContentOffsetObservation: NSKeyValueObservation? | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     func pagerScrollView(_ pagerScrollView: UIScrollView, contentOffsetDidChange change: NSKeyValueObservedChange<CGPoint>) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard let newValue = change.newValue else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             owsFailDebug("newValue was unexpectedly nil") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let width = pagerScrollView.frame.size.width | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard width > 0 else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let ratioComplete = abs((newValue.x - width) / width) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         updatePagerTransition(ratioComplete: ratioComplete) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     func updatePagerTransition(ratioComplete: CGFloat) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if currentCaptionView.text != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             currentCaptionView.alpha = 1 - ratioComplete | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             currentCaptionView.alpha = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         if pendingCaptionView.text != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             pendingCaptionView.alpha = ratioComplete | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             pendingCaptionView.alpha = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         super.viewWillTransition(to: size, with: coordinator) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let isLandscape = size.width > size.height | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.navigationItem.titleView = isLandscape ? nil : self.portraitHeaderView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     override func didReceiveMemoryWarning() { |  |  |  |     override func didReceiveMemoryWarning() { | 
			
		
	
		
		
			
				
					
					|  |  |  |         Logger.info("") |  |  |  |         Logger.info("") | 
			
		
	
		
		
			
				
					
					|  |  |  |         super.didReceiveMemoryWarning() |  |  |  |         super.didReceiveMemoryWarning() | 
			
		
	
	
		
		
			
				
					|  |  | @ -189,32 +269,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     @objc |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     public func didPressAllMediaButton(sender: Any) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         Logger.debug("") |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         currentViewController.stopAnyVideo() |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         guard let mediaGalleryDataSource = self.mediaGalleryDataSource else { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             owsFailDebug("mediaGalleryDataSource was unexpectedly nil") |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |             return |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         mediaGalleryDataSource.showAllMedia(focusedItem: currentItem) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     @objc |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     public func didSwipeView(sender: Any) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         Logger.debug("") |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.dismissSelf(animated: true) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         super.viewWillTransition(to: size, with: coordinator) |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         let isLandscape = size.width > size.height |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |         self.navigationItem.titleView = isLandscape ? nil : self.portraitHeaderView |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  |     private var shouldHideToolbars: Bool = false { |  |  |  |     private var shouldHideToolbars: Bool = false { | 
			
		
	
		
		
			
				
					
					|  |  |  |         didSet { |  |  |  |         didSet { | 
			
		
	
		
		
			
				
					
					|  |  |  |             if (oldValue == shouldHideToolbars) { |  |  |  |             if (oldValue == shouldHideToolbars) { | 
			
		
	
	
		
		
			
				
					|  |  | @ -232,7 +286,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             UIView.animate(withDuration: 0.1) { |  |  |  |             UIView.animate(withDuration: 0.1) { | 
			
		
	
		
		
			
				
					
					|  |  |  |                 self.currentViewController.setShouldHideToolbars(self.shouldHideToolbars) |  |  |  |                 self.currentViewController.setShouldHideToolbars(self.shouldHideToolbars) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 self.footerBar.isHidden = self.shouldHideToolbars |  |  |  |                 self.bottomContainer.isHidden = self.shouldHideToolbars | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
	
		
		
			
				
					|  |  | @ -266,6 +320,26 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // MARK: Actions |  |  |  |     // MARK: Actions | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     @objc | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public func didPressAllMediaButton(sender: Any) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Logger.debug("") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         currentViewController.stopAnyVideo() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         guard let mediaGalleryDataSource = self.mediaGalleryDataSource else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             owsFailDebug("mediaGalleryDataSource was unexpectedly nil") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             return | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         mediaGalleryDataSource.showAllMedia(focusedItem: currentItem) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     @objc | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     public func didSwipeView(sender: Any) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         Logger.debug("") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         self.dismissSelf(animated: true) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     @objc |  |  |  |     @objc | 
			
		
	
		
		
			
				
					
					|  |  |  |     public func didPressDismissButton(_ sender: Any) { |  |  |  |     public func didPressDismissButton(_ sender: Any) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         dismissSelf(animated: true) |  |  |  |         dismissSelf(animated: true) | 
			
		
	
	
		
		
			
				
					|  |  | @ -364,18 +438,31 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |     // MARK: UIPageViewControllerDelegate |  |  |  |     // MARK: UIPageViewControllerDelegate | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var pendingViewController: MediaDetailViewController? | 
			
		
	
		
		
			
				
					
					|  |  |  |     public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { |  |  |  |     public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) { | 
			
		
	
		
		
			
				
					
					|  |  |  |         Logger.debug("") |  |  |  |         Logger.debug("") | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |         assert(pendingViewControllers.count == 1) |  |  |  |         assert(pendingViewControllers.count == 1) | 
			
		
	
		
		
			
				
					
					|  |  |  |         pendingViewControllers.forEach { viewController in |  |  |  |         pendingViewControllers.forEach { viewController in | 
			
		
	
		
		
			
				
					
					|  |  |  |             guard let pendingPage = viewController as? MediaDetailViewController else { |  |  |  |             guard let pendingViewController = viewController as? MediaDetailViewController else { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |                 owsFailDebug("unexpected mediaDetailViewController: \(viewController)") |  |  |  |                 owsFailDebug("unexpected mediaDetailViewController: \(viewController)") | 
			
		
	
		
		
			
				
					
					|  |  |  |                 return |  |  |  |                 return | 
			
		
	
		
		
			
				
					
					|  |  |  |             } |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             self.pendingViewController = pendingViewController | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             CATransaction.begin() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             CATransaction.disableActions() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             if let pendingCaptionText = pendingViewController.galleryItem.caption, pendingCaptionText.count > 0 { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 self.pendingCaptionView.text = pendingCaptionText | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } else { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 self.pendingCaptionView.text = nil | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             self.pendingCaptionView.sizeToFit() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             self.pendingCaptionView.superview?.layoutIfNeeded() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |             CATransaction.commit() | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // Ensure upcoming page respects current toolbar status |  |  |  |             // Ensure upcoming page respects current toolbar status | 
			
		
	
		
		
			
				
					
					|  |  |  |             pendingPage.setShouldHideToolbars(self.shouldHideToolbars) |  |  |  |             pendingViewController.setShouldHideToolbars(self.shouldHideToolbars) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -391,6 +478,20 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |             // Do any cleanup for the no-longer visible view controller |  |  |  |             // Do any cleanup for the no-longer visible view controller | 
			
		
	
		
		
			
				
					
					|  |  |  |             if transitionCompleted { |  |  |  |             if transitionCompleted { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 pendingViewController = nil | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 // This can happen when trying to page past the last (or first) view controller | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 // In that case, we don't want to change the captionView. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 if (previousPage != currentViewController) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     updatePagerTransition(ratioComplete: 1) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     // promote "pending" to "current" caption view. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     let oldCaptionView = self.currentCaptionView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     self.currentCaptionView = self.pendingCaptionView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     self.pendingCaptionView = oldCaptionView | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                     self.pendingCaptionView.text = nil | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |                 } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |                 updateTitle() |  |  |  |                 updateTitle() | 
			
		
	
		
		
			
				
					
					|  |  |  |                 previousPage.zoomOut(animated: false) |  |  |  |                 previousPage.zoomOut(animated: false) | 
			
		
	
		
		
			
				
					
					|  |  |  |                 previousPage.stopAnyVideo() |  |  |  |                 previousPage.stopAnyVideo() | 
			
		
	
	
		
		
			
				
					|  |  | @ -650,3 +751,38 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou | 
			
		
	
		
		
			
				
					
					|  |  |  |         } |  |  |  |         } | 
			
		
	
		
		
			
				
					
					|  |  |  |     } |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | class CaptionView: UIView { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var label: UILabel = UILabel() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     var text: String? { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         get { return label.text } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         set { label.text = newValue } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     override init(frame: CGRect) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         super.init(frame: frame) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         let gradientView = GradientView(from: .clear, to: .black) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         addSubview(gradientView) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         gradientView.autoPinEdgesToSuperviewEdges() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         addSubview(label) | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.font = UIFont.ows_dynamicTypeBody | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.textColor = .white | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // Usually captions are short, but they can be as long as 2k. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // We don't have UI for viewing infinitely large captions, so | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // we do some not-ideal things to broaden the lenght of the | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         // captions we can support. | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.numberOfLines = 0 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.adjustsFontSizeToFitWidth = true | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.minimumScaleFactor = 0.5 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.lineBreakMode = .byTruncatingTail | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         label.autoPinEdgesToSuperviewMargins() | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     required init?(coder aDecoder: NSCoder) { | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |         fatalError("init(coder:) has not been implemented") | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  |     } | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | 
 |