Minor formatting and code cleanup of attachments

pull/548/head
Morgan Pretty 3 years ago
parent ba1a0a2ac6
commit ab9f2a0c7b

@ -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,20 +46,73 @@ 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: - Properties // MARK: - Properties
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: - Initializers // MARK: - Initializers
@available(*, unavailable, message:"use attachment: constructor instead.") @available(*, unavailable, message:"use attachment: constructor instead.")
@ -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
}
// MARK: - Notifications return navController
@objc func didBecomeActive() {
AssertIsOnMainThread()
updateContents()
} }
// MARK: - Subviews // MARK: - UI
var galleryRailView: GalleryRailView { private let kSpacingBetweenItems: CGFloat = 20
return bottomToolView.galleryRailView
}
var attachmentTextToolbar: AttachmentTextToolbar { public override var prefersStatusBarHidden: Bool { return true }
return bottomToolView.attachmentTextToolbar
}
lazy var bottomToolView: AttachmentApprovalInputAccessoryView = { private 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: - View Lifecycle private lazy var touchInterceptorView: UIView = {
let view: UIView = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.isHidden = true
public override var prefersStatusBarHidden: Bool { let tapGesture = UITapGestureRecognizer(
return true target: self,
} action: #selector(didTapTouchInterceptorView(gesture:))
)
view.addGestureRecognizer(tapGesture)
override public func viewDidLoad() { return view
super.viewDidLoad() }()
self.view.backgroundColor = Colors.navigationBarBackground private lazy var pagerScrollView: UIScrollView? = {
// This is kind of a hack. Since we don't have first class access to the superview's `scrollView`
// we traverse the view hierarchy until we find it.
let pagerScrollView = view.subviews.first { $0 is UIScrollView } as? UIScrollView
assert(pagerScrollView != nil)
// avoid an unpleasant "bounce" which doesn't make sense in the context of a single item. return pagerScrollView
pagerScrollView?.isScrollEnabled = attachmentItems.count > 1 }()
// Bottom Toolbar // MARK: - Lifecycle
galleryRailView.delegate = self
attachmentTextToolbar.attachmentTextToolbarDelegate = self override public func viewDidLoad() {
super.viewDidLoad()
// Navigation self.view.backgroundColor = Colors.navigationBarBackground
let backgroundImage: UIImage = UIImage(color: Colors.navigationBarBackground)
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)
// Avoid an unpleasant "bounce" which doesn't make sense in the context of a single item.
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")
@ -153,35 +235,20 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
self.setCurrentItem(firstItem, direction: .forward, animated: false) self.setCurrentItem(firstItem, direction: .forward, animated: false)
view.addSubview(touchInterceptorView)
// layout immediately to avoid animating the layout process during the transition // layout immediately to avoid animating the layout process during the transition
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
}
// Loki: Set navigation bar background color
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()
} }
@ -198,6 +265,22 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
super.viewWillDisappear(animated) super.viewWillDisappear(animated)
} }
// MARK: - Layout
private func setupLayout() {
touchInterceptorView.autoPinEdgesToSuperviewEdges()
}
// MARK: - Notifications
@objc func didBecomeActive() {
AssertIsOnMainThread()
updateContents()
}
// MARK: - Contents
private func updateContents() { private func updateContents() {
updateNavigationBar() updateNavigationBar()
updateInputAccessory() updateInputAccessory()
@ -207,40 +290,26 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// MARK: - Input Accessory // MARK: - Input Accessory
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: - Navigation Bar // MARK: - Navigation Bar
@ -254,10 +323,18 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
guard !isEditingCaptions else { guard !isEditingCaptions else {
// Hide all navigation bar items while the caption view is open. // Hide all navigation bar items while the caption view is open.
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(
//"Title for 'caption' mode of the attachment approval view."
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()
// Show the caption UI if there's more than one attachment // Show the caption UI if there's more than one attachment
// OR if the attachment already has a caption. // OR if the attachment already has a caption.
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 {
// Mimic a UIBarButtonItem of type .cancel, but with a shadow. // Mimic a UIBarButtonItem of type .cancel, but with a shadow.
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 {
// Mimic a conventional back button, but with a shadow. // Mimic a conventional back button, but with a shadow.
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
// Default back button is 1.5 pixel lower than our extracted image. // Default back button is 1.5 pixel lower than our extracted image.
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
)
)
// Note: using a custom leftBarButtonItem breaks the interactive pop gesture. // Note: using a custom leftBarButtonItem breaks the interactive pop gesture.
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backButton) navigationItem.leftBarButtonItem = UIBarButtonItem(customView: backButton)
} }
} }
// MARK: - Control Visibility
public var shouldHideControls: Bool {
guard let pageViewController = pageViewControllers.first else {
return false
}
return pageViewController.shouldHideControls
}
// MARK: - View Helpers // MARK: - View Helpers
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,29 +448,26 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
return return
} }
UIView.animate(withDuration: 0.2, UIView.animate(
animations: { withDuration: 0.2,
// shrink stack view item until it disappears animations: {
cell.isHidden = true // shrink stack view item until it disappears
cell.isHidden = true
// simultaneously fade out // simultaneously fade out
cell.alpha = 0 cell.alpha = 0
}, },
completion: { _ in completion: { [weak self] _ in
self.attachmentItemCollection.remove(item: attachmentItem) self?.attachmentItemCollection.remove(item: attachmentItem)
self.approvalDelegate?.attachmentApproval?(self, didRemoveAttachment: attachmentItem.attachment)
self.updateMediaRail()
})
}
lazy var pagerScrollView: UIScrollView? = { if let strongSelf: AttachmentApprovalViewController = self {
// This is kind of a hack. Since we don't have first class access to the superview's `scrollView` self?.approvalDelegate?.attachmentApproval?(strongSelf, didRemoveAttachment: attachmentItem.attachment)
// we traverse the view hierarchy until we find it. }
let pagerScrollView = view.subviews.first { $0 is UIScrollView } as? UIScrollView
assert(pagerScrollView != nil)
return pagerScrollView self?.updateMediaRail()
}() }
)
}
// MARK: - UIPageViewControllerDelegate // MARK: - UIPageViewControllerDelegate
@ -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) {
// Toolbar flickers in and out if there are errors // Toolbar flickers in and out if there are errors
// and remains visible momentarily after share extension is dismissed. // and remains visible momentarily after share extension is dismissed.
// It's easiest to just hide it at this point since we're done with it. // It's easiest to just hide it at this point since we're done with it.
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 currentIndex = attachmentItems.firstIndex(of: currentItem) else { guard let currentItem: SignalAttachmentItem = currentItem, let currentIndex = 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)

Loading…
Cancel
Save