Show captions in gallery page view

pull/1/head
Michael Kirk 7 years ago
parent 1da59dd9b5
commit cfd2e8d9d1

@ -31,6 +31,10 @@ public class MediaGalleryItem: Equatable, Hashable {
return attachmentStream.isImage
}
var caption: String? {
return attachmentStream.caption
}
public typealias AsyncThumbnailBlock = (UIImage) -> Void
func thumbnailImage(async:@escaping AsyncThumbnailBlock) -> UIImage? {
return attachmentStream.thumbnailImageSmall(success: async, failure: {})

@ -101,11 +101,17 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
Logger.debug("deinit")
}
var bottomContainer: UIView!
var footerBar: UIToolbar!
var videoPlayBarButton: UIBarButtonItem!
var videoPauseBarButton: UIBarButtonItem!
var pagerScrollView: UIScrollView!
// MARK: Caption
var currentCaptionView: CaptionView!
var pendingCaptionView: CaptionView!
override func 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
// one "Page" so the bounce doesn't make sense.
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
@ -152,12 +162,44 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
let footerBar = UIToolbar()
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.videoPauseBarButton = UIBarButtonItem(barButtonSystemItem: .pause, target: self, action: #selector(didPressPauseBarButton))
self.updateFooterBarButtonItems(isPlayingVideo: true)
self.view.addSubview(footerBar)
footerBar.autoPinWidthToSuperview()
self.view.addSubview(bottomContainer)
bottomContainer.autoPinWidthToSuperview()
bottomContainer.autoPinEdge(toSuperviewEdge: .bottom)
footerBar.autoPin(toBottomLayoutGuideOf: self, withInset: 0)
footerBar.autoSetDimension(.height, toSize: kFooterHeight)
@ -168,6 +210,44 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
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() {
Logger.info("")
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 {
didSet {
if (oldValue == shouldHideToolbars) {
@ -232,7 +286,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
UIView.animate(withDuration: 0.1) {
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
@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
public func didPressDismissButton(_ sender: Any) {
dismissSelf(animated: true)
@ -364,18 +438,31 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
// MARK: UIPageViewControllerDelegate
var pendingViewController: MediaDetailViewController?
public func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
Logger.debug("")
assert(pendingViewControllers.count == 1)
pendingViewControllers.forEach { viewController in
guard let pendingPage = viewController as? MediaDetailViewController else {
guard let pendingViewController = viewController as? MediaDetailViewController else {
owsFailDebug("unexpected mediaDetailViewController: \(viewController)")
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
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
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()
previousPage.zoomOut(animated: false)
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")
}
}

Loading…
Cancel
Save