@ -168,44 +168,7 @@ protocol MediaGalleryDataSourceDelegate: class {
func mediaGalleryDataSource ( _ mediaGalleryDataSource : MediaGalleryDataSource , deletedSections : IndexSet , deletedItems : [ IndexPath ] )
}
@objc
class MediaGalleryViewController : OWSNavigationController , MediaGalleryDataSource , MediaTileViewControllerDelegate {
private var pageViewController : MediaPageViewController ?
private let uiDatabaseConnection : YapDatabaseConnection
private let editingDatabaseConnection : YapDatabaseConnection
private let mediaGalleryFinder : OWSMediaGalleryFinder
private var initialDetailItem : MediaGalleryItem ?
private let thread : TSThread
private let options : MediaGalleryOption
// w e s t a r t w i t h a s m a l l r a n g e s i z e f o r q u i c k l o a d i n g .
private let fetchRangeSize : UInt = 10
deinit {
Logger . debug ( " deinit " )
}
@objc
init ( thread : TSThread , uiDatabaseConnection : YapDatabaseConnection , options : MediaGalleryOption = [ ] ) {
self . thread = thread
assert ( uiDatabaseConnection . isInLongLivedReadTransaction ( ) )
self . uiDatabaseConnection = uiDatabaseConnection
self . editingDatabaseConnection = OWSPrimaryStorage . shared ( ) . newDatabaseConnection ( )
self . options = options
self . mediaGalleryFinder = OWSMediaGalleryFinder ( thread : thread )
super . init ( nibName : nil , bundle : nil )
self . setValue ( OWSNavigationBar ( ) , forKey : " navigationBar " )
super . setupNavbar ( )
}
required init ? ( coder aDecoder : NSCoder ) {
notImplemented ( )
}
class MediaGalleryNavigationController : OWSNavigationController {
// MARK: V i e w L i f e C y c l e
@ -215,6 +178,9 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
UIViewController . attemptRotationToDeviceOrientation ( )
}
var presentationView : UIImageView !
var retainUntilDismissed : MediaGallery ?
// H A C K : T h o u g h w e d o n ' t h a v e a n i n p u t a c c e s s o r y v i e w , t h e V C w e a r e p r e s e n t e d a b o v e ( C o n v e r s a t i o n V C ) d o e s .
// I f t h e a p p i s b a c k g r o u n d e d a n d t h e n f o r e g r o u n d e d , w h e n O W S W i n d o w M a n a g e r c a l l s m a i n W i n d o w . m a k e K e y A n d V i s i b l e
// t h e C o n v e r s a t i o n V C ' s i n p u t A c c e s s o r y V i e w w i l l a p p e a r * a b o v e * u s u n l e s s w e ' d p r e v i o u s l y b e c o m e f i r s t r e s p o n d e r .
@ -256,6 +222,52 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
presentationView . contentMode = . scaleAspectFit
}
// MARK: O r i e n t a t i o n
public override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return . allButUpsideDown
}
}
@objc
class MediaGallery : NSObject , MediaGalleryDataSource , MediaTileViewControllerDelegate {
@objc
weak public var navigationController : MediaGalleryNavigationController !
private var pageViewController : MediaPageViewController ?
private let uiDatabaseConnection : YapDatabaseConnection
private let editingDatabaseConnection : YapDatabaseConnection
private let mediaGalleryFinder : OWSMediaGalleryFinder
private var initialDetailItem : MediaGalleryItem ?
private let thread : TSThread
private let options : MediaGalleryOption
// w e s t a r t w i t h a s m a l l r a n g e s i z e f o r q u i c k l o a d i n g .
private let fetchRangeSize : UInt = 10
deinit {
Logger . debug ( " " )
}
@objc
init ( thread : TSThread , uiDatabaseConnection : YapDatabaseConnection , options : MediaGalleryOption = [ ] ) {
self . thread = thread
assert ( uiDatabaseConnection . isInLongLivedReadTransaction ( ) )
self . uiDatabaseConnection = uiDatabaseConnection
self . editingDatabaseConnection = OWSPrimaryStorage . shared ( ) . newDatabaseConnection ( )
self . options = options
self . mediaGalleryFinder = OWSMediaGalleryFinder ( thread : thread )
let navController = MediaGalleryNavigationController ( )
self . navigationController = navController
super . init ( )
navController . retainUntilDismissed = self
}
// MARK: P r e s e n t / D i s m i s s
private var currentItem : MediaGalleryItem {
@ -263,7 +275,6 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
}
private var replacingView : UIView ?
private var presentationView : UIImageView !
private var presentationViewConstraints : [ NSLayoutConstraint ] = [ ]
// T O D O r e n a m e t o r e p l a c i n g O r i g i n R e c t
@ -294,7 +305,7 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
self . addDataSourceDelegate ( pageViewController )
self . pageViewController = pageViewController
self . setViewControllers ( [ pageViewController ] , animated : false )
navigationController . setViewControllers ( [ pageViewController ] , animated : false )
self . replacingView = replacingView
@ -302,13 +313,13 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
self . originRect = convertedRect
// l o a d V i e w h a s n ' t n e c e s s a r i l y b e e n c a l l e d y e t .
self . loadViewIfNeeded ( )
navigationController . loadViewIfNeeded ( )
self . presentationView . image = initialDetailItem . attachmentStream . thumbnailImageLarge ( success : { [ weak self ] ( image ) in
navigationController . presentationView . image = initialDetailItem . attachmentStream . thumbnailImageLarge ( success : { [ weak self ] ( image ) in
guard let strongSelf = self else {
return
}
strongSelf . presentationView. image = image
strongSelf . navigationController. presentationView. image = image
} , failure : {
Logger . warn ( " Could not load presentation image. " )
} )
@ -316,8 +327,8 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
self . applyInitialMediaViewConstraints ( )
// R e s t o r e p r e s e n t a t i o n V i e w . a l p h a i n c a s e a p r e v i o u s d i s m i s s l e f t u s i n a b a d s t a t e .
self . setNavigationBarHidden ( false , animated : false )
self . presentationView . alpha = 1
navigationController . setNavigationBarHidden ( false , animated : false )
navigationController . presentationView . alpha = 1
// W e w a n t t o a n i m a t e t h e t a p p e d m e d i a f r o m i t ' s p o s i t i o n i n t h e p r e v i o u s V C
// t o i t ' s r e s t i n g p l a c e i n t h e c e n t e r o f t h i s v i e w c o n t r o l l e r .
@ -330,7 +341,7 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
// 2 . F o r V i d e o v i e w s , t h e A V P l a y e r L a y e r c o n t e n t d o e s n o t s c a l e w i t h t h e p r e s e n t a t i o n a n i m a t i o n . S o y o u i n s t e a d g e t a f u l l s c a l e
// v i d e o , w h e r e i n o n l y t h e c r o p p i n g i s a n i m a t e d .
// U s i n g a s i m p l e i m a g e v i e w a l l o w s u s t o a d d r e s s b o t h t h e s e p r o b l e m s r e l a t i v e l y e a s i l y .
self . view . alpha = 0.0
navigationController . view . alpha = 0.0
guard let detailView = pageViewController . view else {
owsFailDebug ( " detailView was unexpectedly nil " )
@ -339,23 +350,23 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
// A t t h i s p o i n t o u r m e d i a v i e w s h o u l d b e o v e r l a y e d p e r f e c t l y
// b y o u r p r e s e n t a t i o n V i e w . S w a p p i n g t h e m o u t s h o u l d b e i m p e r c e p t i b l e .
self . presentationView . isHidden = false
navigationController . presentationView . isHidden = false
// W e d o n ' t h i d e t h e p a g e V i e w C o n t r o l l e r e n t i r e l y - e . g . w e w a n t t h e t o o l b a r s t o f a d e i n .
pageViewController . currentViewController . view . isHidden = true
detailView . backgroundColor = . clear
self . view . backgroundColor = . clear
navigationController . view . backgroundColor = . clear
self . presentationView . layer . cornerRadius = kOWSMessageCellCornerRadius_Small
navigationController . presentationView . layer . cornerRadius = kOWSMessageCellCornerRadius_Small
fromViewController . present ( self , animated : false ) {
fromViewController . present ( navigationController , animated : false ) {
// 1 . F a d e i n t h e e n t i r e v i e w .
UIView . animate ( withDuration : 0.1 ) {
self . replacingView ? . alpha = 0.0
self . view. alpha = 1.0
self . navigationController. view. alpha = 1.0
}
self . presentationView. superview ? . layoutIfNeeded ( )
self . navigationController. presentationView. superview ? . layoutIfNeeded ( )
self . applyFinalMediaViewConstraints ( )
// 2 . A n i m a t e i m a g e V i e w f r o m i t ' s i n i t i a l p o s i t i o n , w h i c h s h o u l d m a t c h w h e r e i t w a s
@ -366,20 +377,20 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
options : . curveEaseOut ,
animations : {
self . presentationView. layer . cornerRadius = 0
self . presentationView. superview ? . layoutIfNeeded ( )
self . navigationController. presentationView. layer . cornerRadius = 0
self . navigationController. presentationView. superview ? . layoutIfNeeded ( )
// f a d e o u t c o n t e n t b e h i n d t h e p a g e V i e w C o n t r o l l e r
// a n d b e h i n d t h e p r e s e n t a t i o n v i e w
self . view. backgroundColor = Theme . backgroundColor
self . navigationController. view. backgroundColor = Theme . backgroundColor
} ,
completion : { ( _ : Bool ) in
// A t t h i s p o i n t o u r p r e s e n t a t i o n v i e w s h o u l d b e o v e r l a y e d p e r f e c t l y
// w i t h o u r m e d i a v i e w . S w a p p i n g t h e m o u t s h o u l d b e i m p e r c e p t i b l e .
pageViewController . currentViewController . view . isHidden = false
self . presentationView. isHidden = true
self . navigationController. presentationView. isHidden = true
self . view. isUserInteractionEnabled = true
self . navigationController. view. isUserInteractionEnabled = true
pageViewController . wasPresented ( )
@ -390,7 +401,7 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
//
// W e d o n ' t n e e d t o d o t h i s w h e n p u s h i n g V C s o n t o t h e S i g n a l s N a v i g a t i o n C o n t r o l l e r - o n l y w h e n
// p r e s e n t i n g d i r e c t l y f r o m C o n v e r s a t i o n V C .
_ = self . becomeFirstResponder( )
_ = self . navigationController. becomeFirstResponder( )
} )
}
}
@ -426,7 +437,7 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
} else {
// I f f r o m c o n v e r s a t i o n v i e w
mediaTileViewController . focusedItem = focusedItem
self . pushViewController ( mediaTileViewController , animated : true )
navigationController . pushViewController ( mediaTileViewController , animated : true )
}
}
@ -459,7 +470,7 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
guard let pageViewController = self . pageViewController else {
owsFailDebug ( " pageViewController was unexpectedly nil " )
self . dismiss( animated : true )
self . navigationController. dismiss( animated : true )
return
}
@ -468,32 +479,32 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
pageViewController . willBePresentedAgain ( )
// T O D O f a n c y z o o m a n i m a t i o n
self . popViewController( animated : true )
self . navigationController. popViewController( animated : true )
}
}
public func dismissMediaDetailViewController ( _ mediaPageViewController : MediaPageViewController , animated isAnimated : Bool , completion : ( ( ) -> Void ) ? ) {
self . view . isUserInteractionEnabled = false
navigationController . view . isUserInteractionEnabled = false
UIApplication . shared . isStatusBarHidden = false
guard let detailView = mediaPageViewController . view else {
owsFailDebug ( " detailView was unexpectedly nil " )
self . presentingViewController? . dismiss ( animated : false , completion : completion )
self . navigationController. presentingViewController? . dismiss ( animated : false , completion : completion )
return
}
mediaPageViewController . currentViewController . view . isHidden = true
self . presentationView . isHidden = false
navigationController . presentationView . isHidden = false
// M o v e t h e p r e s e n t a t i o n V i e w b a c k t o i t ' s i n i t i a l p o s i t i o n , i . e . w h e r e
// i t s i t s o n t h e s c r e e n i n t h e c o n v e r s a t i o n v i e w .
let changedItems = currentItem != self . initialDetailItem
if changedItems {
self . presentationView . image = currentItem . attachmentStream . thumbnailImageLarge ( success : { [ weak self ] ( image ) in
navigationController . presentationView . image = currentItem . attachmentStream . thumbnailImageLarge ( success : { [ weak self ] ( image ) in
guard let strongSelf = self else {
return
}
strongSelf . presentationView. image = image
strongSelf . navigationController. presentationView. image = image
} , failure : {
Logger . warn ( " Could not load presentation image. " )
} )
@ -508,14 +519,14 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
options : . curveEaseOut ,
animations : {
// M o v e b a c k o v e r i t ' s o r i g i n a l l o c a t i o n
self . presentationView. superview ? . layoutIfNeeded ( )
self . navigationController. presentationView. superview ? . layoutIfNeeded ( )
detailView . alpha = 0
if changedItems {
self . presentationView. alpha = 0
self . navigationController. presentationView. alpha = 0
} else {
self . presentationView. layer . cornerRadius = kOWSMessageCellCornerRadius_Small
self . navigationController. presentationView. layer . cornerRadius = kOWSMessageCellCornerRadius_Small
}
} ,
completion : { ( _ : Bool ) in
@ -532,24 +543,24 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
animations : {
guard let replacingView = self . replacingView else {
owsFailDebug ( " replacingView was unexpectedly nil " )
self . presentingViewController? . dismiss ( animated : false , completion : completion )
self . navigationController. presentingViewController? . dismiss ( animated : false , completion : completion )
return
}
// f a d e o u t c o n t e n t a n d t o o l b a r s
self . view. alpha = 0.0
self . navigationController. view. alpha = 0.0
replacingView . alpha = 1.0
} ,
completion : { ( _ : Bool ) in
self . presentingViewController? . dismiss ( animated : false , completion : completion )
self . navigationController. presentingViewController? . dismiss ( animated : false , completion : completion )
} )
} else {
guard let replacingView = self . replacingView else {
owsFailDebug ( " replacingView was unexpectedly nil " )
self . presentingViewController ? . dismiss ( animated : false , completion : completion )
navigationController . presentingViewController ? . dismiss ( animated : false , completion : completion )
return
}
replacingView . alpha = 1.0
self . presentingViewController ? . dismiss ( animated : false , completion : completion )
navigationController . presentingViewController ? . dismiss ( animated : false , completion : completion )
}
}
@ -564,17 +575,17 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
return
}
guard let presentationSuperview = self . presentationView . superview else {
guard let presentationSuperview = navigationController . presentationView . superview else {
owsFailDebug ( " presentationView.superview was unexpectedly nil " )
return
}
let convertedRect : CGRect = presentationSuperview . convert ( originRect , from : UIApplication . shared . keyWindow )
self . presentationViewConstraints += self . presentationView . autoSetDimensions ( to : convertedRect . size )
self . presentationViewConstraints += navigationController . presentationView . autoSetDimensions ( to : convertedRect . size )
self . presentationViewConstraints += [
self . presentationView . autoPinEdge ( toSuperviewEdge : . top , withInset : convertedRect . origin . y ) ,
self . presentationView . autoPinEdge ( toSuperviewEdge : . left , withInset : convertedRect . origin . x )
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . top , withInset : convertedRect . origin . y ) ,
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . left , withInset : convertedRect . origin . x )
]
}
@ -585,10 +596,10 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
}
self . presentationViewConstraints = [
self . presentationView . autoPinEdge ( toSuperviewEdge : . leading ) ,
self . presentationView . autoPinEdge ( toSuperviewEdge : . top ) ,
self . presentationView . autoPinEdge ( toSuperviewEdge : . trailing ) ,
self . presentationView . autoPinEdge ( toSuperviewEdge : . bottom )
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . leading ) ,
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . top ) ,
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . trailing ) ,
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . bottom )
]
}
@ -599,9 +610,9 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
}
self . presentationViewConstraints += [
self . presentationView . autoPinEdge ( toSuperviewEdge : . leading ) ,
self . presentationView . autoPinEdge ( toSuperviewEdge : . trailing ) ,
self . presentationView . autoPinEdge ( . top , to : . bottom , of : self . view )
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . leading ) ,
navigationController . presentationView . autoPinEdge ( toSuperviewEdge : . trailing ) ,
navigationController . presentationView . autoPinEdge ( . top , to : . bottom , of : self . navigationController . view )
]
}
@ -918,10 +929,4 @@ class MediaGalleryViewController: OWSNavigationController, MediaGalleryDataSourc
}
return Int ( count ) - deletedMessages . count
}
// MARK: O r i e n t a t i o n
public override var supportedInterfaceOrientations : UIInterfaceOrientationMask {
return . allButUpsideDown
}
}