@ -10,17 +10,25 @@ import SessionUIKit
import CoreServices
import CoreServices
@objc
@objc
public protocol AttachmentApprovalViewControllerDelegate : class {
public protocol AttachmentApprovalViewControllerDelegate : AnyObject {
func attachmentApproval ( _ attachmentApproval : AttachmentApprovalViewController ,
func attachmentApproval (
didApproveAttachments attachments : [ SignalAttachment ] , messageText : String ? )
_ attachmentApproval : AttachmentApprovalViewController ,
didApproveAttachments attachments : [ SignalAttachment ] ,
messageText : String ?
)
func attachmentApprovalDidCancel ( _ attachmentApproval : AttachmentApprovalViewController )
func attachmentApprovalDidCancel ( _ attachmentApproval : AttachmentApprovalViewController )
func attachmentApproval ( _ attachmentApproval : AttachmentApprovalViewController ,
func attachmentApproval (
didChangeMessageText newMessageText : String ? )
_ attachmentApproval : AttachmentApprovalViewController ,
didChangeMessageText newMessageText : String ?
)
@objc
@objc
optional func attachmentApproval ( _ attachmentApproval : AttachmentApprovalViewController , didRemoveAttachment attachment : SignalAttachment )
optional func attachmentApproval (
_ attachmentApproval : AttachmentApprovalViewController ,
didRemoveAttachment attachment : SignalAttachment
)
@objc
@objc
optional func attachmentApprovalDidTapAddMore ( _ attachmentApproval : AttachmentApprovalViewController )
optional func attachmentApprovalDidTapAddMore ( _ attachmentApproval : AttachmentApprovalViewController )
@ -38,19 +46,72 @@ public enum AttachmentApprovalViewControllerMode: UInt {
@objc
@objc
public class AttachmentApprovalViewController : UIPageViewController , UIPageViewControllerDataSource , UIPageViewControllerDelegate {
public class AttachmentApprovalViewController : UIPageViewController , UIPageViewControllerDataSource , UIPageViewControllerDelegate {
@objc public enum Mode : UInt {
case modal
case sharedNavigation
}
// MARK: - P r o p e r t i e s
// MARK: - P r o p e r t i e s
private let mode : AttachmentApprovalViewControllerMode
private let mode : Mode
private let isAddMoreVisible : Bool
private let isAddMoreVisible : Bool
public weak var approvalDelegate : AttachmentApprovalViewControllerDelegate ?
public weak var approvalDelegate : AttachmentApprovalViewControllerDelegate ?
public var isEditingCaptions = false {
public var isEditingCaptions = false {
didSet {
didSet { updateContents ( ) }
updateContents ( )
}
let attachmentItemCollection : AttachmentItemCollection
var attachmentItems : [ SignalAttachmentItem ] {
return attachmentItemCollection . attachmentItems
}
var attachments : [ SignalAttachment ] {
return attachmentItems . map { ( attachmentItem ) in
autoreleasepool {
return self . processedAttachment ( forAttachmentItem : attachmentItem )
}
}
}
}
}
public var pageViewControllers : [ AttachmentPrepViewController ] ? {
return viewControllers ? . compactMap { $0 as ? AttachmentPrepViewController }
}
public var currentPageViewController : AttachmentPrepViewController ? {
return pageViewControllers ? . first
}
var currentItem : SignalAttachmentItem ? {
get { return currentPageViewController ? . attachmentItem }
set { setCurrentItem ( newValue , direction : . forward , animated : false ) }
}
private var cachedPages : [ SignalAttachmentItem : AttachmentPrepViewController ] = [ : ]
public var shouldHideControls : Bool {
guard let pageViewController : AttachmentPrepViewController = pageViewControllers ? . first else {
return false
}
return pageViewController . shouldHideControls
}
override public var inputAccessoryView : UIView ? {
bottomToolView . layoutIfNeeded ( )
return bottomToolView
}
override public var canBecomeFirstResponder : Bool {
return ! shouldHideControls
}
public var messageText : String ? {
get { return bottomToolView . attachmentTextToolbar . messageText }
set { bottomToolView . attachmentTextToolbar . messageText = newValue }
}
// MARK: - I n i t i a l i z e r s
// MARK: - I n i t i a l i z e r s
@ -59,29 +120,34 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
notImplemented ( )
notImplemented ( )
}
}
let kSpacingBetweenItems : CGFloat = 20
@objc
@objc
required public init ( mode : AttachmentApprovalViewControllerMode ,
required public init (
attachments : [ SignalAttachment ] ) {
mode : Mode ,
attachments : [ SignalAttachment ]
) {
assert ( attachments . count > 0 )
assert ( attachments . count > 0 )
self . mode = mode
self . mode = mode
let attachmentItems = attachments . map { SignalAttachmentItem ( attachment : $0 ) }
let attachmentItems = attachments . map { SignalAttachmentItem ( attachment : $0 ) }
self . isAddMoreVisible = mode = = . sharedNavigation
self . isAddMoreVisible = ( mode = = . sharedNavigation )
self . attachmentItemCollection = AttachmentItemCollection ( attachmentItems : attachmentItems , isAddMoreVisible : isAddMoreVisible )
self . attachmentItemCollection = AttachmentItemCollection ( attachmentItems : attachmentItems , isAddMoreVisible : isAddMoreVisible )
let options : [ UIPageViewController . OptionsKey : Any ] = [ . interPageSpacing : kSpacingBetweenItems ]
super . init (
super . init ( transitionStyle : . scroll ,
transitionStyle : . scroll ,
navigationOrientation : . horizontal ,
navigationOrientation : . horizontal ,
options : options )
options : [
. interPageSpacing : kSpacingBetweenItems
]
)
self . dataSource = self
self . dataSource = self
self . delegate = self
self . delegate = self
NotificationCenter . default . addObserver ( self ,
NotificationCenter . default . addObserver (
selector : #selector ( didBecomeActive ) ,
self ,
name : NSNotification . Name . OWSApplicationDidBecomeActive ,
selector : #selector ( didBecomeActive ) ,
object : nil )
name : . OWSApplicationDidBecomeActive ,
object : nil
)
}
}
deinit {
deinit {
@ -89,62 +155,78 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
}
@objc
@objc
public class func wrappedInNavController ( attachments : [ SignalAttachment ] , approvalDelegate : AttachmentApprovalViewControllerDelegate ) -> OWSNavigationController {
public class func wrappedInNavController (
attachments : [ SignalAttachment ] ,
approvalDelegate : AttachmentApprovalViewControllerDelegate
) -> OWSNavigationController {
let vc = AttachmentApprovalViewController ( mode : . modal , attachments : attachments )
let vc = AttachmentApprovalViewController ( mode : . modal , attachments : attachments )
vc . approvalDelegate = approvalDelegate
vc . approvalDelegate = approvalDelegate
let navController = OWSNavigationController ( rootViewController : vc )
let navController = OWSNavigationController ( rootViewController : vc )
navController . ows_prefersStatusBarHidden = true
navController . ows_prefersStatusBarHidden = true
return navController
return navController
}
}
// MARK: - N o t i f i c a t i o n s
// MARK: - U I
@objc func didBecomeActive ( ) {
private let kSpacingBetweenItems : CGFloat = 20
AssertIsOnMainThread ( )
public override var prefersStatusBarHidden : Bool { return true }
updateContents ( )
}
private lazy var bottomToolView : AttachmentApprovalInputAccessoryView = {
// MARK: - S u b v i e w s
var galleryRailView : GalleryRailView {
return bottomToolView . galleryRailView
}
var attachmentTextToolbar : AttachmentTextToolbar {
return bottomToolView . attachmentTextToolbar
}
lazy var bottomToolView : AttachmentApprovalInputAccessoryView = {
let bottomToolView = AttachmentApprovalInputAccessoryView ( )
let bottomToolView = AttachmentApprovalInputAccessoryView ( )
bottomToolView . delegate = self
bottomToolView . delegate = self
bottomToolView . attachmentTextToolbar . attachmentTextToolbarDelegate = self
bottomToolView . galleryRailView . delegate = self
return bottomToolView
return bottomToolView
} ( )
} ( )
lazy var touchInterceptorView = UIView ( )
private var galleryRailView : GalleryRailView { return bottomToolView . galleryRailView }
// MARK: - V i e w L i f e c y c l e
private lazy var touchInterceptorView : UIView = {
let view : UIView = UIView ( )
view . translatesAutoresizingMaskIntoConstraints = false
view . isHidden = true
let tapGesture = UITapGestureRecognizer (
target : self ,
action : #selector ( didTapTouchInterceptorView ( gesture : ) )
)
view . addGestureRecognizer ( tapGesture )
return view
} ( )
public override var prefersStatusBarHidden : Bool {
private lazy var pagerScrollView : UIScrollView ? = {
return true
// T h i s i s k i n d o f a h a c k . S i n c e w e d o n ' t h a v e f i r s t c l a s s a c c e s s t o t h e s u p e r v i e w ' s ` s c r o l l V i e w `
}
// w e t r a v e r s e t h e v i e w h i e r a r c h y u n t i l w e f i n d i t .
let pagerScrollView = view . subviews . first { $0 is UIScrollView } as ? UIScrollView
assert ( pagerScrollView != nil )
return pagerScrollView
} ( )
// MARK: - L i f e c y c l e
override public func viewDidLoad ( ) {
override public func viewDidLoad ( ) {
super . viewDidLoad ( )
super . viewDidLoad ( )
self . view . backgroundColor = Colors . navigationBarBackground
self . view . backgroundColor = Colors . navigationBarBackground
// a v o i d a n u n p l e a s a n t " b o u n c e " w h i c h d o e s n ' t m a k e s e n s e i n t h e c o n t e x t o f a s i n g l e i t e m .
let backgroundImage : UIImage = UIImage ( color : Colors . navigationBarBackground )
pagerScrollView ? . isScrollEnabled = attachmentItems . count > 1
// B o t t o m T o o l b a r
galleryRailView . delegate = self
attachmentTextToolbar . attachmentTextToolbarDelegate = self
// N a v i g a t i o n
self . navigationItem . title = nil
self . navigationItem . title = nil
self . navigationController ? . navigationBar . setBackgroundImage ( UIImage ( ) , for : . default )
self . navigationController ? . navigationBar . shadowImage = UIImage ( )
self . navigationController ? . navigationBar . isTranslucent = false
self . navigationController ? . navigationBar . barTintColor = Colors . navigationBarBackground
( self . navigationController ? . navigationBar as ? OWSNavigationBar ) ? . respectsTheme = true
self . navigationController ? . navigationBar . backgroundColor = Colors . navigationBarBackground
self . navigationController ? . navigationBar . setBackgroundImage ( backgroundImage , for : . default )
// A v o i d a n u n p l e a s a n t " b o u n c e " w h i c h d o e s n ' t m a k e s e n s e i n t h e c o n t e x t o f a s i n g l e i t e m .
pagerScrollView ? . isScrollEnabled = ( attachmentItems . count > 1 )
guard let firstItem = attachmentItems . first else {
guard let firstItem = attachmentItems . first else {
owsFailDebug ( " firstItem was unexpectedly nil " )
owsFailDebug ( " firstItem was unexpectedly nil " )
@ -152,36 +234,21 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
}
self . setCurrentItem ( firstItem , direction : . forward , animated : false )
self . setCurrentItem ( firstItem , direction : . forward , animated : false )
view . addSubview ( touchInterceptorView )
// l a y o u t i m m e d i a t e l y t o a v o i d a n i m a t i n g t h e l a y o u t p r o c e s s d u r i n g t h e t r a n s i t i o n
// l a y o u t i m m e d i a t e l y t o a v o i d a n i m a t i n g t h e l a y o u t p r o c e s s d u r i n g t h e t r a n s i t i o n
self . currentPageViewController . view . layoutIfNeeded ( )
UIView . performWithoutAnimation {
self . currentPageViewController ? . view . layoutIfNeeded ( )
}
view . addSubview ( touchInterceptorView )
setupLayout ( )
touchInterceptorView . autoPinEdgesToSuperviewEdges ( )
touchInterceptorView . isHidden = true
let tapGesture = UITapGestureRecognizer ( target : self , action : #selector ( didTapTouchInterceptorView ( gesture : ) ) )
touchInterceptorView . addGestureRecognizer ( tapGesture )
}
}
override public func viewWillAppear ( _ animated : Bool ) {
override public func viewWillAppear ( _ animated : Bool ) {
Logger . debug ( " " )
Logger . debug ( " " )
super . viewWillAppear ( animated )
super . viewWillAppear ( animated )
guard let navigationBar = navigationController ? . navigationBar as ? OWSNavigationBar else {
owsFailDebug ( " navigationBar was nil or unexpected class " )
return
}
// L o k i : S e t n a v i g a t i o n b a r b a c k g r o u n d c o l o r
navigationBar . setBackgroundImage ( UIImage ( ) , for : UIBarMetrics . default )
navigationBar . shadowImage = UIImage ( )
navigationBar . isTranslucent = false
navigationBar . barTintColor = Colors . navigationBarBackground
navigationBar . respectsTheme = true
navigationBar . backgroundColor = Colors . navigationBarBackground
let backgroundImage = UIImage ( color : Colors . navigationBarBackground )
navigationBar . setBackgroundImage ( backgroundImage , for : . default )
updateContents ( )
updateContents ( )
}
}
@ -197,7 +264,23 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
Logger . debug ( " " )
Logger . debug ( " " )
super . viewWillDisappear ( animated )
super . viewWillDisappear ( animated )
}
}
// MARK: - L a y o u t
private func setupLayout ( ) {
touchInterceptorView . autoPinEdgesToSuperviewEdges ( )
}
// MARK: - N o t i f i c a t i o n s
@objc func didBecomeActive ( ) {
AssertIsOnMainThread ( )
updateContents ( )
}
// MARK: - C o n t e n t s
private func updateContents ( ) {
private func updateContents ( ) {
updateNavigationBar ( )
updateNavigationBar ( )
updateInputAccessory ( )
updateInputAccessory ( )
@ -207,40 +290,26 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// MARK: - I n p u t A c c e s s o r y
// MARK: - I n p u t A c c e s s o r y
override public var inputAccessoryView : UIView ? {
bottomToolView . layoutIfNeeded ( )
return bottomToolView
}
override public var canBecomeFirstResponder : Bool {
return ! shouldHideControls
}
public func updateInputAccessory ( ) {
public func updateInputAccessory ( ) {
var currentPageViewController : AttachmentPrepViewController ?
var currentPageViewController : AttachmentPrepViewController ?
if pageViewControllers . count = = 1 {
currentPageViewController = pageViewControllers . first
if pageViewControllers ? . count = = 1 {
currentPageViewController = pageViewControllers ? . first
}
}
let currentAttachmentItem : SignalAttachmentItem ? = currentPageViewController ? . attachmentItem
let currentAttachmentItem : SignalAttachmentItem ? = currentPageViewController ? . attachmentItem
let hasPresentedView = self . presentedViewController != nil
let hasPresentedView = ( self . presentedViewController != nil )
let isToolbarFirstResponder = bottomToolView . hasFirstResponder
let isToolbarFirstResponder = bottomToolView . hasFirstResponder
if ! shouldHideControls , ! isFirstResponder , ! hasPresentedView , ! isToolbarFirstResponder {
if ! shouldHideControls , ! isFirstResponder , ! hasPresentedView , ! isToolbarFirstResponder {
becomeFirstResponder ( )
becomeFirstResponder ( )
}
}
bottomToolView . update ( isEditingCaptions : isEditingCaptions ,
bottomToolView . update (
currentAttachmentItem : currentAttachmentItem ,
isEditingCaptions : isEditingCaptions ,
shouldHideControls : shouldHideControls )
currentAttachmentItem : currentAttachmentItem ,
}
shouldHideControls : shouldHideControls
)
public var messageText : String ? {
get {
return attachmentTextToolbar . messageText
}
set {
attachmentTextToolbar . messageText = newValue
}
}
}
// MARK: - N a v i g a t i o n B a r
// MARK: - N a v i g a t i o n B a r
@ -254,10 +323,18 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
guard ! isEditingCaptions else {
guard ! isEditingCaptions else {
// H i d e a l l n a v i g a t i o n b a r i t e m s w h i l e t h e c a p t i o n v i e w i s o p e n .
// H i d e a l l n a v i g a t i o n b a r i t e m s w h i l e t h e c a p t i o n v i e w i s o p e n .
self . navigationItem . leftBarButtonItem = UIBarButtonItem ( title : NSLocalizedString ( " ATTACHMENT_APPROVAL_CAPTION_TITLE " , comment : " Title for 'caption' mode of the attachment approval view. " ) , style : . plain , target : nil , action : nil )
self . navigationItem . leftBarButtonItem = UIBarButtonItem (
// " T i t l e f o r ' c a p t i o n ' m o d e o f t h e a t t a c h m e n t a p p r o v a l v i e w . "
let doneButton = navigationBarButton ( imageName : " image_editor_checkmark_full " ,
title : " ATTACHMENT_APPROVAL_CAPTION_TITLE " . localized ( ) ,
selector : #selector ( didTapCaptionDone ( sender : ) ) )
style : . plain ,
target : nil ,
action : nil
)
let doneButton = navigationBarButton (
imageName : " image_editor_checkmark_full " ,
selector : #selector ( didTapCaptionDone ( sender : ) )
)
let navigationBarItems = [ doneButton ]
let navigationBarItems = [ doneButton ]
updateNavigationBar ( navigationBarItems : navigationBarItems )
updateNavigationBar ( navigationBarItems : navigationBarItems )
return
return
@ -265,29 +342,23 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
var navigationBarItems = [ UIView ] ( )
var navigationBarItems = [ UIView ] ( )
if let viewControllers = viewControllers ,
if viewControllers ? . count = = 1 , let firstViewController : AttachmentPrepViewController = viewControllers ? . first as ? AttachmentPrepViewController {
viewControllers . count = = 1 ,
let firstViewController = viewControllers . first as ? AttachmentPrepViewController {
navigationBarItems = firstViewController . navigationBarItems ( )
navigationBarItems = firstViewController . navigationBarItems ( )
// S h o w t h e c a p t i o n U I i f t h e r e ' s m o r e t h a n o n e a t t a c h m e n t
// S h o w t h e c a p t i o n U I i f t h e r e ' s m o r e t h a n o n e a t t a c h m e n t
// O R i f t h e a t t a c h m e n t a l r e a d y h a s a c a p t i o n .
// O R i f t h e a t t a c h m e n t a l r e a d y h a s a c a p t i o n .
let attachmentCount = attachmentItemCollection . count
if attachmentItemCollection . count > 0 , ( firstViewController . attachmentItem . captionText ? . count ? ? 0 ) > 0 {
var shouldShowCaptionUI = attachmentCount > 0
let captionButton = navigationBarButton (
if let captionText = firstViewController . attachmentItem . captionText , captionText . count > 0 {
imageName : " image_editor_caption " ,
shouldShowCaptionUI = true
selector : #selector ( didTapCaption ( sender : ) )
}
)
if shouldShowCaptionUI {
let captionButton = navigationBarButton ( imageName : " image_editor_caption " ,
selector : #selector ( didTapCaption ( sender : ) ) )
navigationBarItems . append ( captionButton )
navigationBarItems . append ( captionButton )
}
}
}
}
updateNavigationBar ( navigationBarItems : navigationBarItems )
updateNavigationBar ( navigationBarItems : navigationBarItems )
let hasCancel = ( mode != . sharedNavigation )
if mode != . sharedNavigation {
if hasCancel {
// M i m i c a U I B a r B u t t o n I t e m o f t y p e . c a n c e l , b u t w i t h a s h a d o w .
// M i m i c a U I B a r B u t t o n I t e m o f t y p e . c a n c e l , b u t w i t h a s h a d o w .
let cancelButton = OWSButton ( title : CommonStrings . cancelButton ) { [ weak self ] in
let cancelButton = OWSButton ( title : CommonStrings . cancelButton ) { [ weak self ] in
self ? . cancelPressed ( )
self ? . cancelPressed ( )
@ -300,10 +371,11 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
}
cancelButton . sizeToFit ( )
cancelButton . sizeToFit ( )
navigationItem . leftBarButtonItem = UIBarButtonItem ( customView : cancelButton )
navigationItem . leftBarButtonItem = UIBarButtonItem ( customView : cancelButton )
} else {
}
else {
// M i m i c a c o n v e n t i o n a l b a c k b u t t o n , b u t w i t h a s h a d o w .
// M i m i c a c o n v e n t i o n a l b a c k b u t t o n , b u t w i t h a s h a d o w .
let isRTL = CurrentAppContext ( ) . isRTL
let isRTL = CurrentAppContext ( ) . isRTL
let imageName = isRTL ? " NavBarBackRTL " : " NavBarBack "
let imageName = ( isRTL ? " NavBarBackRTL " : " NavBarBack " )
let backButton = OWSButton ( imageName : imageName , tintColor : Colors . text ) { [ weak self ] in
let backButton = OWSButton ( imageName : imageName , tintColor : Colors . text ) { [ weak self ] in
self ? . navigationController ? . popViewController ( animated : true )
self ? . navigationController ? . popViewController ( animated : true )
}
}
@ -328,40 +400,44 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// D e f a u l t b a c k b u t t o n i s 1 . 5 p i x e l l o w e r t h a n o u r e x t r a c t e d i m a g e .
// D e f a u l t b a c k b u t t o n i s 1 . 5 p i x e l l o w e r t h a n o u r e x t r a c t e d i m a g e .
let kTopInsetPadding : CGFloat = 1.5
let kTopInsetPadding : CGFloat = 1.5
backButton . imageEdgeInsets = UIEdgeInsets ( top : kTopInsetPadding , left : kExtraLeftPadding , bottom : 0 , right : 0 )
backButton . imageEdgeInsets = UIEdgeInsets (
top : kTopInsetPadding ,
left : kExtraLeftPadding ,
bottom : 0 ,
right : 0
)
var backImageSize = CGSize . zero
var backImageSize = CGSize . zero
if let backImage = UIImage ( named : imageName ) {
if let backImage = UIImage ( named : imageName ) {
backImageSize = backImage . size
backImageSize = backImage . size
} else {
}
else {
owsFailDebug ( " Missing backImage. " )
owsFailDebug ( " Missing backImage. " )
}
}
backButton . frame = CGRect ( origin : . zero , size : CGSize ( width : backImageSize . width + kExtraRightPadding ,
backButton . frame = CGRect (
height : backImageSize . height + kExtraHeightPadding ) )
origin : . zero ,
size : CGSize (
width : backImageSize . width + kExtraRightPadding ,
height : backImageSize . height + kExtraHeightPadding
)
)
// N o t e : u s i n g a c u s t o m l e f t B a r B u t t o n I t e m b r e a k s t h e i n t e r a c t i v e p o p g e s t u r e .
// N o t e : u s i n g a c u s t o m l e f t B a r B u t t o n I t e m b r e a k s t h e i n t e r a c t i v e p o p g e s t u r e .
navigationItem . leftBarButtonItem = UIBarButtonItem ( customView : backButton )
navigationItem . leftBarButtonItem = UIBarButtonItem ( customView : backButton )
}
}
}
}
// MARK: - C o n t r o l V i s i b i l i t y
public var shouldHideControls : Bool {
guard let pageViewController = pageViewControllers . first else {
return false
}
return pageViewController . shouldHideControls
}
// MARK: - V i e w H e l p e r s
// MARK: - V i e w H e l p e r s
func remove ( attachmentItem : SignalAttachmentItem ) {
func remove ( attachmentItem : SignalAttachmentItem ) {
if attachmentItem = = currentItem {
if attachmentItem = = currentItem {
if let nextItem = attachmentItemCollection . itemAfter ( item : attachmentItem ) {
if let nextItem = attachmentItemCollection . itemAfter ( item : attachmentItem ) {
setCurrentItem ( nextItem , direction : . forward , animated : true )
setCurrentItem ( nextItem , direction : . forward , animated : true )
} else if let prevItem = attachmentItemCollection . itemBefore ( item : attachmentItem ) {
}
else if let prevItem = attachmentItemCollection . itemBefore ( item : attachmentItem ) {
setCurrentItem ( prevItem , direction : . reverse , animated : true )
setCurrentItem ( prevItem , direction : . reverse , animated : true )
} else {
}
else {
owsFailDebug ( " removing last item shouldn't be possible because rail should not be visible " )
owsFailDebug ( " removing last item shouldn't be possible because rail should not be visible " )
return
return
}
}
@ -372,30 +448,27 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
return
return
}
}
UIView . animate ( withDuration : 0.2 ,
UIView . animate (
animations : {
withDuration : 0.2 ,
// s h r i n k s t a c k v i e w i t e m u n t i l i t d i s a p p e a r s
animations : {
cell . isHidden = true
// s h r i n k s t a c k v i e w i t e m u n t i l i t d i s a p p e a r s
cell . isHidden = true
// s i m u l t a n e o u s l y f a d e o u t
cell . alpha = 0
// s i m u l t a n e o u s l y f a d e o u t
} ,
cell . alpha = 0
completion : { _ in
} ,
self . attachmentItemCollection . remove ( item : attachmentItem )
completion : { [ weak self ] _ in
self . approvalDelegate ? . attachmentApproval ? ( self , didRemoveAttachment : attachmentItem . attachment )
self ? . attachmentItemCollection . remove ( item : attachmentItem )
self . updateMediaRail ( )
} )
if let strongSelf : AttachmentApprovalViewController = self {
self ? . approvalDelegate ? . attachmentApproval ? ( strongSelf , didRemoveAttachment : attachmentItem . attachment )
}
self ? . updateMediaRail ( )
}
)
}
}
lazy var pagerScrollView : UIScrollView ? = {
// T h i s i s k i n d o f a h a c k . S i n c e w e d o n ' t h a v e f i r s t c l a s s a c c e s s t o t h e s u p e r v i e w ' s ` s c r o l l V i e w `
// w e t r a v e r s e t h e v i e w h i e r a r c h y u n t i l w e f i n d i t .
let pagerScrollView = view . subviews . first { $0 is UIScrollView } as ? UIScrollView
assert ( pagerScrollView != nil )
return pagerScrollView
} ( )
// MARK: - U I P a g e V i e w C o n t r o l l e r D e l e g a t e
// MARK: - U I P a g e V i e w C o n t r o l l e r D e l e g a t e
public func pageViewController ( _ pageViewController : UIPageViewController , willTransitionTo pendingViewControllers : [ UIViewController ] ) {
public func pageViewController ( _ pageViewController : UIPageViewController , willTransitionTo pendingViewControllers : [ UIViewController ] ) {
@ -440,10 +513,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
}
let currentItem = currentViewController . attachmentItem
let currentItem = currentViewController . attachmentItem
guard let previousItem = attachmentItem ( before : currentItem ) else {
guard let previousItem = attachmentItem ( before : currentItem ) else { return nil }
return nil
}
guard let previousPage : AttachmentPrepViewController = buildPage ( item : previousItem ) else {
guard let previousPage : AttachmentPrepViewController = buildPage ( item : previousItem ) else {
return nil
return nil
}
}
@ -460,10 +530,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
}
}
let currentItem = currentViewController . attachmentItem
let currentItem = currentViewController . attachmentItem
guard let nextItem = attachmentItem ( after : currentItem ) else {
guard let nextItem = attachmentItem ( after : currentItem ) else { return nil }
return nil
}
guard let nextPage : AttachmentPrepViewController = buildPage ( item : nextItem ) else {
guard let nextPage : AttachmentPrepViewController = buildPage ( item : nextItem ) else {
return nil
return nil
}
}
@ -471,38 +538,19 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
return nextPage
return nextPage
}
}
public var currentPageViewController : AttachmentPrepViewController {
return pageViewControllers . first !
}
public var pageViewControllers : [ AttachmentPrepViewController ] {
return super . viewControllers ! . map { $0 as ! AttachmentPrepViewController }
}
@objc
@objc
public override func setViewControllers ( _ viewControllers : [ UIViewController ] ? , direction : UIPageViewController . NavigationDirection , animated : Bool , completion : ( ( Bool ) -> Void ) ? = nil ) {
public override func setViewControllers ( _ viewControllers : [ UIViewController ] ? , direction : UIPageViewController . NavigationDirection , animated : Bool , completion : ( ( Bool ) -> Void ) ? = nil ) {
super . setViewControllers ( viewControllers ,
super . setViewControllers (
direction : direction ,
viewControllers ,
animated : animated ) { [ weak self ] ( finished ) in
direction : direction ,
if let completion = completion {
animated : animated
completion ( finished )
) { [ weak self ] finished in
}
completion ? ( finished )
self ? . updateContents ( )
self ? . updateContents ( )
}
}
}
}
var currentItem : SignalAttachmentItem ! {
get {
return currentPageViewController . attachmentItem
}
set {
setCurrentItem ( newValue , direction : . forward , animated : false )
}
}
private var cachedPages : [ SignalAttachmentItem : AttachmentPrepViewController ] = [ : ]
private func buildPage ( item : SignalAttachmentItem ) -> AttachmentPrepViewController ? {
private func buildPage ( item : SignalAttachmentItem ) -> AttachmentPrepViewController ? {
if let cachedPage = cachedPages [ item ] {
if let cachedPage = cachedPages [ item ] {
Logger . debug ( " cache hit. " )
Logger . debug ( " cache hit. " )
return cachedPage
return cachedPage
@ -516,8 +564,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
return viewController
return viewController
}
}
private func setCurrentItem ( _ item : SignalAttachmentItem , direction : UIPageViewController . NavigationDirection , animated isAnimated : Bool ) {
private func setCurrentItem ( _ item : SignalAttachmentItem ? , direction : UIPageViewController . NavigationDirection , animated isAnimated : Bool ) {
guard let page = self . buildPage ( item : item ) else {
guard let item: SignalAttachmentItem = item , let page = self . buildPage ( item : item ) else {
owsFailDebug ( " unexpectedly unable to build new page " )
owsFailDebug ( " unexpectedly unable to build new page " )
return
return
}
}
@ -536,42 +584,34 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
let cellViewBuilder : ( GalleryRailItem ) -> GalleryRailCellView = { [ weak self ] railItem in
let cellViewBuilder : ( GalleryRailItem ) -> GalleryRailCellView = { [ weak self ] railItem in
switch railItem {
switch railItem {
case is AddMoreRailItem :
case is AddMoreRailItem :
return GalleryRailCellView ( )
return GalleryRailCellView ( )
case is SignalAttachmentItem :
let cell = ApprovalRailCellView ( )
case is SignalAttachmentItem :
cell . approvalRailCellDelegate = self
let cell = ApprovalRailCellView ( )
return cell
cell . approvalRailCellDelegate = self
default :
return cell
owsFailDebug ( " unexpted rail item type: \( railItem ) " )
return GalleryRailCellView ( )
default :
owsFailDebug ( " unexpted rail item type: \( railItem ) " )
return GalleryRailCellView ( )
}
}
}
}
galleryRailView . configureCellViews ( itemProvider : attachmentItemCollection ,
galleryRailView . configureCellViews (
focusedItem : currentItem ,
itemProvider : attachmentItemCollection ,
cellViewBuilder : cellViewBuilder )
focusedItem : currentItem ,
cellViewBuilder : cellViewBuilder
)
if isAddMoreVisible {
if isAddMoreVisible {
galleryRailView . isHidden = false
galleryRailView . isHidden = false
} else if attachmentItemCollection . attachmentItems . count > 1 {
}
else if attachmentItemCollection . attachmentItems . count > 1 {
galleryRailView . isHidden = false
galleryRailView . isHidden = false
} else {
galleryRailView . isHidden = true
}
}
}
else {
galleryRailView . isHidden = true
let attachmentItemCollection : AttachmentItemCollection
var attachmentItems : [ SignalAttachmentItem ] {
return attachmentItemCollection . attachmentItems
}
var attachments : [ SignalAttachment ] {
return attachmentItems . map { ( attachmentItem ) in
autoreleasepool {
return self . processedAttachment ( forAttachmentItem : attachmentItem )
}
}
}
}
}
@ -596,18 +636,24 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
return attachmentItem . attachment
return attachmentItem . attachment
}
}
var dataUTI = kUTTypeImage as String
var dataUTI = kUTTypeImage as String
guard let dstData : Data = {
let maybeDstData : Data ? = {
let isLossy : Bool = attachmentItem . attachment . mimeType . caseInsensitiveCompare ( OWSMimeTypeImageJpeg ) = = . orderedSame
let isLossy : Bool = (
attachmentItem . attachment . mimeType . caseInsensitiveCompare ( OWSMimeTypeImageJpeg ) = = . orderedSame
)
if isLossy {
if isLossy {
dataUTI = kUTTypeJPEG as String
dataUTI = kUTTypeJPEG as String
return dstImage . jpegData ( compressionQuality : 0.9 )
return dstImage . jpegData ( compressionQuality : 0.9 )
} else {
}
else {
dataUTI = kUTTypePNG as String
dataUTI = kUTTypePNG as String
return dstImage . pngData ( )
return dstImage . pngData ( )
}
}
} ( ) else {
} ( )
owsFailDebug ( " Could not export for output. " )
return attachmentItem . attachment
guard let dstData : Data = maybeDstData else {
owsFailDebug ( " Could not export for output. " )
return attachmentItem . attachment
}
}
guard let dataSource = DataSourceValue . dataSource ( with : dstData , utiType : dataUTI ) else {
guard let dataSource = DataSourceValue . dataSource ( with : dstData , utiType : dataUTI ) else {
owsFailDebug ( " Could not prepare data source for output. " )
owsFailDebug ( " Could not prepare data source for output. " )
@ -693,18 +739,18 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
extension AttachmentApprovalViewController : AttachmentTextToolbarDelegate {
extension AttachmentApprovalViewController : AttachmentTextToolbarDelegate {
func attachmentTextToolbarDidBeginEditing ( _ attachmentTextToolbar : AttachmentTextToolbar ) {
func attachmentTextToolbarDidBeginEditing ( _ attachmentTextToolbar : AttachmentTextToolbar ) {
currentPageViewController .setAttachmentViewScale ( . compact , animated : true )
currentPageViewController ? .setAttachmentViewScale ( . compact , animated : true )
}
}
func attachmentTextToolbarDidEndEditing ( _ attachmentTextToolbar : AttachmentTextToolbar ) {
func attachmentTextToolbarDidEndEditing ( _ attachmentTextToolbar : AttachmentTextToolbar ) {
currentPageViewController .setAttachmentViewScale ( . fullsize , animated : true )
currentPageViewController ? .setAttachmentViewScale ( . fullsize , animated : true )
}
}
func attachmentTextToolbarDidTapSend ( _ attachmentTextToolbar : AttachmentTextToolbar ) {
func attachmentTextToolbarDidTapSend ( _ attachmentTextToolbar : AttachmentTextToolbar ) {
// T o o l b a r f l i c k e r s i n a n d o u t i f t h e r e a r e e r r o r s
// T o o l b a r f l i c k e r s i n a n d o u t i f t h e r e a r e e r r o r s
// a n d r e m a i n s v i s i b l e m o m e n t a r i l y a f t e r s h a r e e x t e n s i o n i s d i s m i s s e d .
// a n d r e m a i n s v i s i b l e m o m e n t a r i l y a f t e r s h a r e e x t e n s i o n i s d i s m i s s e d .
// I t ' s e a s i e s t t o j u s t h i d e i t a t t h i s p o i n t s i n c e w e ' r e d o n e w i t h i t .
// I t ' s e a s i e s t t o j u s t h i d e i t a t t h i s p o i n t s i n c e w e ' r e d o n e w i t h i t .
currentPageViewController .shouldAllowAttachmentViewResizing = false
currentPageViewController ? .shouldAllowAttachmentViewResizing = false
attachmentTextToolbar . isUserInteractionEnabled = false
attachmentTextToolbar . isUserInteractionEnabled = false
attachmentTextToolbar . isHidden = true
attachmentTextToolbar . isHidden = true
@ -769,7 +815,7 @@ extension AttachmentApprovalViewController: GalleryRailViewDelegate {
return
return
}
}
guard let currentI ndex = attachmentItems . firstIndex ( of : currentItem ) else {
guard let currentI tem: SignalAttachmentItem = currentItem , let currentI ndex = attachmentItems . firstIndex ( of : currentItem ) else {
owsFailDebug ( " currentIndex was unexpectedly nil " )
owsFailDebug ( " currentIndex was unexpectedly nil " )
return
return
}
}
@ -779,7 +825,7 @@ extension AttachmentApprovalViewController: GalleryRailViewDelegate {
return
return
}
}
let direction : UIPageViewController . NavigationDirection = currentIndex < targetIndex ? . forward : . reverse
let direction : UIPageViewController . NavigationDirection = ( currentIndex < targetIndex ? . forward : . reverse )
self . setCurrentItem ( targetItem , direction : direction , animated : true )
self . setCurrentItem ( targetItem , direction : direction , animated : true )
}
}
@ -787,12 +833,6 @@ extension AttachmentApprovalViewController: GalleryRailViewDelegate {
// MARK: -
// MARK: -
enum KeyboardScenario {
case hidden , editingMessage , editingCaption
}
// MARK: -
extension AttachmentApprovalViewController : ApprovalRailCellViewDelegate {
extension AttachmentApprovalViewController : ApprovalRailCellViewDelegate {
func approvalRailCellView ( _ approvalRailCellView : ApprovalRailCellView , didRemoveItem attachmentItem : SignalAttachmentItem ) {
func approvalRailCellView ( _ approvalRailCellView : ApprovalRailCellView , didRemoveItem attachmentItem : SignalAttachmentItem ) {
remove ( attachmentItem : attachmentItem )
remove ( attachmentItem : attachmentItem )