mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			203 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Swift
		
	
			
		
		
	
	
			203 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Swift
		
	
| //
 | |
| //  Copyright (c) 2019 Open Whisper Systems. All rights reserved.
 | |
| //
 | |
| 
 | |
| import Foundation
 | |
| import UIKit
 | |
| import SessionUIKit
 | |
| 
 | |
| protocol AttachmentApprovalInputAccessoryViewDelegate: class {
 | |
|     func attachmentApprovalInputUpdateMediaRail()
 | |
|     func attachmentApprovalInputStartEditingCaptions()
 | |
|     func attachmentApprovalInputStopEditingCaptions()
 | |
| }
 | |
| 
 | |
| // MARK: -
 | |
| 
 | |
| class AttachmentApprovalInputAccessoryView: UIView {
 | |
| 
 | |
|     weak var delegate: AttachmentApprovalInputAccessoryViewDelegate?
 | |
| 
 | |
|     let attachmentTextToolbar: AttachmentTextToolbar
 | |
|     let attachmentCaptionToolbar: AttachmentCaptionToolbar
 | |
|     let galleryRailView: GalleryRailView
 | |
|     let currentCaptionLabel = UILabel()
 | |
|     let currentCaptionWrapper = UIView()
 | |
| 
 | |
|     var isEditingMediaMessage: Bool {
 | |
|         return attachmentTextToolbar.textView.isFirstResponder
 | |
|     }
 | |
| 
 | |
|     private var isEditingCaptions: Bool = false
 | |
|     private var currentAttachmentItem: SignalAttachmentItem?
 | |
| 
 | |
|     let kGalleryRailViewHeight: CGFloat = 72
 | |
| 
 | |
|     required init() {
 | |
|         attachmentTextToolbar = AttachmentTextToolbar()
 | |
|         attachmentCaptionToolbar = AttachmentCaptionToolbar()
 | |
| 
 | |
|         galleryRailView = GalleryRailView()
 | |
|         galleryRailView.scrollFocusMode = .keepWithinBounds
 | |
|         galleryRailView.autoSetDimension(.height, toSize: kGalleryRailViewHeight)
 | |
| 
 | |
|         super.init(frame: .zero)
 | |
| 
 | |
|         createContents()
 | |
|     }
 | |
| 
 | |
|     required init?(coder aDecoder: NSCoder) {
 | |
|         fatalError("init(coder:) has not been implemented")
 | |
|     }
 | |
| 
 | |
|     private func createContents() {
 | |
|         // Specifying auto-resizing mask and an intrinsic content size allows proper
 | |
|         // sizing when used as an input accessory view.
 | |
|         self.autoresizingMask = .flexibleHeight
 | |
|         self.translatesAutoresizingMaskIntoConstraints = false
 | |
|         self.backgroundColor = .clear
 | |
| 
 | |
|         preservesSuperviewLayoutMargins = true
 | |
| 
 | |
|         // Use a background view that extends below the keyboard to avoid animation glitches.
 | |
|         let backgroundView = UIView()
 | |
|         backgroundView.backgroundColor = isLightMode ? UIColor.black.withAlphaComponent(0.2) : UIColor.black.withAlphaComponent(0.6)
 | |
|         addSubview(backgroundView)
 | |
|         backgroundView.autoPinEdgesToSuperviewEdges()
 | |
| 
 | |
|         currentCaptionLabel.textColor = .white
 | |
|         currentCaptionLabel.font = .systemFont(ofSize: Values.mediumFontSize)
 | |
|         currentCaptionLabel.numberOfLines = 5
 | |
|         currentCaptionLabel.lineBreakMode = .byWordWrapping
 | |
| 
 | |
|         currentCaptionWrapper.isUserInteractionEnabled = true
 | |
|         currentCaptionWrapper.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(captionTapped)))
 | |
|         currentCaptionWrapper.addSubview(currentCaptionLabel)
 | |
|         currentCaptionLabel.autoPinEdgesToSuperviewMargins()
 | |
| 
 | |
|         attachmentCaptionToolbar.attachmentCaptionToolbarDelegate = self
 | |
| 
 | |
|         let stackView = UIStackView(arrangedSubviews: [currentCaptionWrapper, attachmentCaptionToolbar, galleryRailView, attachmentTextToolbar])
 | |
|         stackView.axis = .vertical
 | |
| 
 | |
|         addSubview(stackView)
 | |
|         stackView.autoPinEdge(toSuperviewEdge: .top)
 | |
|         stackView.autoPinEdge(toSuperviewEdge: .leading)
 | |
|         stackView.autoPinEdge(toSuperviewEdge: .trailing)
 | |
|         // We pin to the superview's _margin_.  Otherwise the notch breaks
 | |
|         // the layout if you hide the keyboard in the simulator (or if the
 | |
|         // user uses an external keyboard).
 | |
|         stackView.autoPinEdge(toSuperviewMargin: .bottom)
 | |
|     }
 | |
| 
 | |
|     // MARK: - Events
 | |
| 
 | |
|     @objc func captionTapped(sender: UIGestureRecognizer) {
 | |
|         guard sender.state == .recognized else {
 | |
|             return
 | |
|         }
 | |
|         delegate?.attachmentApprovalInputStartEditingCaptions()
 | |
|     }
 | |
| 
 | |
|     // MARK: 
 | |
| 
 | |
|     private var shouldHideControls = false
 | |
| 
 | |
|     private func updateContents() {
 | |
|         var hasCurrentCaption = false
 | |
|         if let currentAttachmentItem = currentAttachmentItem,
 | |
|             let captionText = currentAttachmentItem.captionText {
 | |
|             hasCurrentCaption = captionText.count > 0
 | |
| 
 | |
|             attachmentCaptionToolbar.textView.text = captionText
 | |
|             currentCaptionLabel.text = captionText
 | |
|         } else {
 | |
|             attachmentCaptionToolbar.textView.text = nil
 | |
|             currentCaptionLabel.text = nil
 | |
|         }
 | |
| 
 | |
|         attachmentCaptionToolbar.isHidden = !isEditingCaptions
 | |
|         currentCaptionWrapper.isHidden = isEditingCaptions || !hasCurrentCaption
 | |
|         attachmentTextToolbar.isHidden = isEditingCaptions
 | |
| 
 | |
|         updateFirstResponder()
 | |
| 
 | |
|         layoutSubviews()
 | |
|     }
 | |
| 
 | |
|     private func updateFirstResponder() {
 | |
|         if (shouldHideControls) {
 | |
|             if attachmentCaptionToolbar.textView.isFirstResponder {
 | |
|                 attachmentCaptionToolbar.textView.resignFirstResponder()
 | |
|             } else if attachmentTextToolbar.textView.isFirstResponder {
 | |
|                 attachmentTextToolbar.textView.resignFirstResponder()
 | |
|             }
 | |
|         } else if (isEditingCaptions) {
 | |
|             // While editing captions, the keyboard should always remain visible.
 | |
|             if !attachmentCaptionToolbar.textView.isFirstResponder {
 | |
|                 attachmentCaptionToolbar.textView.becomeFirstResponder()
 | |
|             }
 | |
|         } else {
 | |
|             if attachmentCaptionToolbar.textView.isFirstResponder {
 | |
|                 attachmentCaptionToolbar.textView.resignFirstResponder()
 | |
|             }
 | |
|         }
 | |
|         // NOTE: We don't automatically make attachmentTextToolbar.textView
 | |
|         // first responder;
 | |
|     }
 | |
| 
 | |
|     public func update(isEditingCaptions: Bool,
 | |
|                        currentAttachmentItem: SignalAttachmentItem?,
 | |
|                        shouldHideControls: Bool) {
 | |
|         // De-bounce
 | |
|         guard self.isEditingCaptions != isEditingCaptions ||
 | |
|             self.currentAttachmentItem != currentAttachmentItem ||
 | |
|             self.shouldHideControls != shouldHideControls else {
 | |
| 
 | |
|                 updateFirstResponder()
 | |
|                 return
 | |
|         }
 | |
| 
 | |
|         self.isEditingCaptions = isEditingCaptions
 | |
|         self.currentAttachmentItem = currentAttachmentItem
 | |
|         self.shouldHideControls = shouldHideControls
 | |
| 
 | |
|         updateContents()
 | |
|     }
 | |
| 
 | |
|     // MARK: 
 | |
| 
 | |
|     override var intrinsicContentSize: CGSize {
 | |
|         get {
 | |
|             // Since we have `self.autoresizingMask = UIViewAutoresizingFlexibleHeight`, we must specify
 | |
|             // an intrinsicContentSize. Specifying CGSize.zero causes the height to be determined by autolayout.
 | |
|             return CGSize.zero
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     public var hasFirstResponder: Bool {
 | |
|         return (isFirstResponder ||
 | |
|             attachmentCaptionToolbar.textView.isFirstResponder ||
 | |
|             attachmentTextToolbar.textView.isFirstResponder)
 | |
|     }
 | |
| }
 | |
| 
 | |
| // MARK: -
 | |
| 
 | |
| extension AttachmentApprovalInputAccessoryView: AttachmentCaptionToolbarDelegate {
 | |
|     public func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar) {
 | |
|         guard let currentAttachmentItem = currentAttachmentItem else {
 | |
|             owsFailDebug("Missing currentAttachmentItem.")
 | |
|             return
 | |
|         }
 | |
| 
 | |
|         currentAttachmentItem.attachment.captionText = attachmentCaptionToolbar.textView.text
 | |
| 
 | |
|         delegate?.attachmentApprovalInputUpdateMediaRail()
 | |
|     }
 | |
| 
 | |
|     public func attachmentCaptionToolbarDidComplete() {
 | |
|         delegate?.attachmentApprovalInputStopEditingCaptions()
 | |
|     }
 | |
| }
 |