251 lines
9.9 KiB
Swift
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)
|
|
})
|
|
}
|
|
}
|