session-ios/Session/Conversations/Input View/ExpandingAttachmentsButton.swift

163 lines
7.2 KiB
Swift

// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SessionUIKit
final class ExpandingAttachmentsButton: UIView, InputViewButtonDelegate {
private weak var delegate: ExpandingAttachmentsButtonDelegate?
private var isExpanded = false { didSet { expandOrCollapse() } }
override var isUserInteractionEnabled: Bool {
didSet {
gifButton.isUserInteractionEnabled = isUserInteractionEnabled
documentButton.isUserInteractionEnabled = isUserInteractionEnabled
libraryButton.isUserInteractionEnabled = isUserInteractionEnabled
cameraButton.isUserInteractionEnabled = isUserInteractionEnabled
mainButton.isUserInteractionEnabled = isUserInteractionEnabled
}
}
// MARK: Constraints
private lazy var gifButtonContainerBottomConstraint = gifButtonContainer.pin(.bottom, to: .bottom, of: self)
private lazy var documentButtonContainerBottomConstraint = documentButtonContainer.pin(.bottom, to: .bottom, of: self)
private lazy var libraryButtonContainerBottomConstraint = libraryButtonContainer.pin(.bottom, to: .bottom, of: self)
private lazy var cameraButtonContainerBottomConstraint = cameraButtonContainer.pin(.bottom, to: .bottom, of: self)
// MARK: UI Components
lazy var gifButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_gif_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityIdentifier = "GIF button"
return result
}()
lazy var gifButtonContainer = container(for: gifButton)
lazy var documentButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_document_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityIdentifier = "Documents folder"
return result
}()
lazy var documentButtonContainer = container(for: documentButton)
lazy var libraryButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_roll_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityIdentifier = "Images folder"
return result
}()
lazy var libraryButtonContainer = container(for: libraryButton)
lazy var cameraButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "actionsheet_camera_black"), delegate: self, hasOpaqueBackground: true)
result.accessibilityIdentifier = "Select camera button"
return result
}()
lazy var cameraButtonContainer = container(for: cameraButton)
lazy var mainButton: InputViewButton = {
let result = InputViewButton(icon: #imageLiteral(resourceName: "ic_plus_24"), delegate: self)
result.accessibilityLabel = "accessibility_expanding_attachments_button".localized()
return result
}()
lazy var mainButtonContainer = container(for: mainButton)
// MARK: Lifecycle
init(delegate: ExpandingAttachmentsButtonDelegate?) {
self.delegate = delegate
super.init(frame: CGRect.zero)
setUpViewHierarchy()
}
override init(frame: CGRect) {
preconditionFailure("Use init(delegate:) instead.")
}
required init?(coder: NSCoder) {
preconditionFailure("Use init(delegate:) instead.")
}
private func setUpViewHierarchy() {
backgroundColor = .clear
// GIF button
addSubview(gifButtonContainer)
gifButtonContainer.alpha = 0
// Document button
addSubview(documentButtonContainer)
documentButtonContainer.alpha = 0
// Library button
addSubview(libraryButtonContainer)
libraryButtonContainer.alpha = 0
// Camera button
addSubview(cameraButtonContainer)
cameraButtonContainer.alpha = 0
// Main button
addSubview(mainButtonContainer)
// Constraints
mainButtonContainer.pin(to: self)
gifButtonContainer.center(.horizontal, in: self)
documentButtonContainer.center(.horizontal, in: self)
libraryButtonContainer.center(.horizontal, in: self)
cameraButtonContainer.center(.horizontal, in: self)
[ gifButtonContainerBottomConstraint, documentButtonContainerBottomConstraint, libraryButtonContainerBottomConstraint, cameraButtonContainerBottomConstraint ].forEach {
$0.isActive = true
}
}
// MARK: Animation
private func expandOrCollapse() {
if isExpanded {
mainButton.accessibilityLabel = NSLocalizedString("accessibility_main_button_collapse", comment: "")
let expandedButtonSize = InputViewButton.expandedSize
let spacing: CGFloat = 4
cameraButtonContainerBottomConstraint.constant = -1 * (expandedButtonSize + spacing)
libraryButtonContainerBottomConstraint.constant = -2 * (expandedButtonSize + spacing)
documentButtonContainerBottomConstraint.constant = -3 * (expandedButtonSize + spacing)
gifButtonContainerBottomConstraint.constant = -4 * (expandedButtonSize + spacing)
UIView.animate(withDuration: 0.25) {
[ self.gifButtonContainer, self.documentButtonContainer, self.libraryButtonContainer, self.cameraButtonContainer ].forEach {
$0.alpha = 1
}
self.layoutIfNeeded()
}
} else {
mainButton.accessibilityLabel = NSLocalizedString("accessibility_expanding_attachments_button", comment: "")
[ gifButtonContainerBottomConstraint, documentButtonContainerBottomConstraint, libraryButtonContainerBottomConstraint, cameraButtonContainerBottomConstraint ].forEach {
$0.constant = 0
}
UIView.animate(withDuration: 0.25) {
[ self.gifButtonContainer, self.documentButtonContainer, self.libraryButtonContainer, self.cameraButtonContainer ].forEach {
$0.alpha = 0
}
self.layoutIfNeeded()
}
}
}
// MARK: Interaction
func handleInputViewButtonTapped(_ inputViewButton: InputViewButton) {
if inputViewButton == gifButton { delegate?.handleGIFButtonTapped(); isExpanded = false }
if inputViewButton == documentButton { delegate?.handleDocumentButtonTapped(); isExpanded = false }
if inputViewButton == libraryButton { delegate?.handleLibraryButtonTapped(); isExpanded = false }
if inputViewButton == cameraButton { delegate?.handleCameraButtonTapped(); isExpanded = false }
if inputViewButton == mainButton { isExpanded = !isExpanded }
}
// MARK: Convenience
private func container(for button: InputViewButton) -> UIView {
let result = UIView()
result.addSubview(button)
result.set(.width, to: InputViewButton.expandedSize)
result.set(.height, to: InputViewButton.expandedSize)
button.center(in: result)
return result
}
}
// MARK: - Delegate
protocol ExpandingAttachmentsButtonDelegate: AnyObject {
func handleGIFButtonTapped()
func handleDocumentButtonTapped()
func handleLibraryButtonTapped()
func handleCameraButtonTapped()
}