Files
2023-03-10 11:23:56 +03:00

251 lines
9.9 KiB
Swift

//
// CommonControllerModal.swift
// Wallet
//
// Created by Igor on 9.02.2021.
//
import UIKit
extension UIViewController {
private struct Values {
static var image = "image"
static var text = "text"
}
@IBInspectable var image: UIImage? {
get { Common.Runtime.object(self, key: &Values.image) }
set { Common.Runtime.set(self, value: newValue, key: &Values.image) }
}
@IBInspectable var text: String? {
get { Common.Runtime.object(self, key: &Values.text) }
set { Common.Runtime.set(self, value: newValue, key: &Values.text) }
}
}
class CommonControllerPopup: UIViewController {
@IBOutlet weak var contentView: UIView!
@IBOutlet private weak var alphaView: UIView!
@IBOutlet private weak var stackView: UIStackView!
@IBOutlet private weak var offset: NSLayoutConstraint!
@IBOutlet weak var bottomHeight: NSLayoutConstraint!
@IBOutlet private weak var titleLbl: UILabel!
@IBOutlet private weak var textLbl: UILabel!
@IBOutlet private weak var imgView: UIImageView!
@IBOutlet private weak var imgViewWidth: NSLayoutConstraint!
@IBOutlet private weak var imgViewHeight: NSLayoutConstraint!
@IBOutlet private weak var contentLeft: NSLayoutConstraint!
@IBOutlet private weak var contentWidth: NSLayoutConstraint!
@IBOutlet private weak var contentRight: NSLayoutConstraint!
@IBOutlet private weak var contentTop: NSLayoutConstraint!
@IBOutlet private weak var contentHeight: NSLayoutConstraint!
@IBOutlet private weak var contentBottom: NSLayoutConstraint!
@IBOutlet private weak var contentScrollVew: UIScrollView!
@IBOutlet private weak var contentStackView: UIStackView!
@IBOutlet private weak var contentOffsetView: UIView!
@IBOutlet private weak var panIndicator: UIView!
private let contentViewController: UIViewController?
private var willPresent = true
private let completion: (() -> Void)?
private let contentScrollIsEnabled: Bool
var muteCompletion = false
init(contentViewController: UIViewController, contentScrollIsEnabled: Bool, completion: (() -> Void)? = nil) {
contentViewController.view.backgroundColor = .clear
self.completion = completion
self.contentScrollIsEnabled = contentScrollIsEnabled
self.contentViewController = contentViewController
super.init(nibName: "CommonControllerPopup", bundle: nil)
self.loadViewIfNeeded()
self.modalPresentationStyle = .custom
self.transitioningDelegate = self
self.addChild(contentViewController)
self.alphaView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onHide)))
self.stackView.superview?.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(onPan(_:))))
self.contentStackView.addArrangedSubview(contentViewController.view)
self.update()
}
init(
image: UIImage? = nil,
title: String? = nil,
text: String? = nil,
views: [UIView],
spacing: CGFloat,
completion: (() -> Void)? = nil
) {
self.contentViewController = nil
self.contentScrollIsEnabled = true
self.completion = completion
super.init(nibName: "CommonControllerPopup", bundle: nil)
self.loadViewIfNeeded()
self.title = title
self.text = text
self.image = image
self.modalPresentationStyle = .custom
self.transitioningDelegate = self
self.alphaView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(onHide)))
self.stackView.superview?.addGestureRecognizer(UIPanGestureRecognizer(target: self, action: #selector(onPan(_:))))
views.forEach { contentStackView.addArrangedSubview($0) }
self.contentLeft.constant = 12
self.contentWidth.constant = -24
self.contentRight.constant = 12
self.contentStackView.spacing = spacing
self.update()
}
init(
views: [UIView],
spacing: CGFloat = 0,
leftSpace: CGFloat? = nil,
rightSpace: CGFloat? = nil,
topSpace: CGFloat? = nil,
bottomSpace: CGFloat? = nil
) {
self.contentViewController = nil
self.contentScrollIsEnabled = false
self.completion = nil
super.init(nibName: "CommonControllerPopup", bundle: nil)
self.loadViewIfNeeded()
self.modalPresentationStyle = .custom
self.transitioningDelegate = self
self.panIndicator.isHidden = true
views.forEach { contentStackView.addArrangedSubview($0) }
if let leftSpace = leftSpace,
let rightSpace = rightSpace {
self.contentLeft.constant = leftSpace
self.contentWidth.constant = -(leftSpace + rightSpace)
self.contentRight.constant = rightSpace
}
if let topSpace = topSpace,
let bottomSpace = bottomSpace {
self.contentTop.constant = topSpace - spacing
self.contentHeight.constant = topSpace + bottomSpace - spacing
self.contentBottom.constant = bottomSpace - spacing
}
self.contentStackView.spacing = spacing
self.update()
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
self.contentScrollVew.isScrollEnabled = self.contentScrollIsEnabled ? self.contentScrollVew.frame.height < contentStackView.frame.height : false
}
private func update() {
if let image = contentViewController?.image ?? image {
self.imgView.image = image
self.imgViewWidth.constant = image.size.width
self.imgViewHeight.constant = image.size.height
self.imgView.superview?.isHidden = false
} else {
self.imgView.superview?.isHidden = true
}
if let title = contentViewController?.title ?? title {
self.titleLbl.superview?.isHidden = false
self.titleLbl.attributedText = title.localized.attributed(style: .bold, size: 28, color: Asset.textCoal.color)
} else {
self.titleLbl.superview?.isHidden = true
}
if let text = contentViewController?.text ?? text {
self.textLbl.superview?.isHidden = false
self.textLbl.attributedText = text.localized.attributed(style: .regular, size: 14, color: Asset.textGranite.color)
} else {
self.textLbl.superview?.isHidden = true
}
self.contentOffsetView.isHidden = (titleLbl.attributedText?.string.isEmpty ?? true) && (textLbl.attributedText?.string.isEmpty ?? true)
self.stackView.layoutIfNeeded()
self.view.frame = UIScreen.main.bounds
self.view.layoutIfNeeded()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.children
.reversed()
.forEach { $0.removeFromParent() }
if self.muteCompletion { return }
self.completion?()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
Alert.refresh()
}
@objc private func onHide() {
self.dismiss(animated: true)
}
private var point: CGPoint!
@objc private func onPan(_ pan: UIPanGestureRecognizer) {
switch pan.state {
case .began:
self.point = pan.location(in: view)
case .changed:
let new = pan.location(in: view)
self.offset.constant += self.point.y - new.y
if self.offset.constant > -self.bottomHeight.constant {
self.offset.constant = -self.bottomHeight.constant
}
self.view.layoutIfNeeded()
self.point = new
case .ended, .cancelled:
if self.offset.constant < -self.stackView.frame.height/2 {
self.dismiss(animated: true)
} else {
self.offset.constant = -self.bottomHeight.constant
UIView.animate(withDuration: Animation.medium) { self.view.layoutIfNeeded() }
}
default: break
}
}
}
extension CommonControllerPopup: UIViewControllerTransitioningDelegate {
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
self.willPresent = false
return self
}
func animationController(
forPresented presented: UIViewController,
presenting: UIViewController,
source: UIViewController
) -> UIViewControllerAnimatedTransitioning? { self }
}
extension CommonControllerPopup: UIViewControllerAnimatedTransitioning {
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { 0.2 }
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
let presentView = self.willPresent ? transitionContext.viewController(forKey: .to)!.view! : transitionContext.viewController(forKey: .from)!.view!
if self.willPresent {
transitionContext.containerView.addSubview(presentView)
self.offset.constant = -self.stackView.frame.height
self.view.layoutIfNeeded()
}
presentView.frame = view.bounds
self.alphaView.alpha = self.willPresent ? 0 : 1
self.offset.constant = self.willPresent ? -self.bottomHeight.constant : -self.stackView.frame.height
UIView.animate(withDuration: transitionDuration(using: transitionContext), animations: {
self.alphaView.alpha = self.willPresent ? 1 : 0
self.view.layoutIfNeeded()
}, completion: { (success) in
if !self.willPresent {
presentView.removeFromSuperview()
}
transitionContext.completeTransition(success)
})
}
}