// // TooltipAlertViewController.swift // VDS // // Created by Matt Bruce on 4/14/23. // import Foundation import UIKit import Combine import VDSColorTokens open class TooltipAlertViewController: UIViewController, Surfaceable { /// Set of Subscribers for any Publishers for this Control public var subscribers = Set() //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var onClickSubscriber: AnyCancellable? { willSet { if let onClickSubscriber { onClickSubscriber.cancel() } } } private var scrollView = UIScrollView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.backgroundColor = .clear } private let modalView = View().with { $0.layer.cornerRadius = 8 } private let containerView = View() private var line = Line().with { instance in instance.lineViewColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsLowcontrastOnlight, VDSColor.elementsLowcontrastOndark).eraseToAnyColorable() } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var surface: Surface = .light { didSet { updateView() }} open var titleText: String = "" { didSet { updateView() }} open var titleLabel = Label().with { label in label.textStyle = .boldTitleMedium } open var contentText: String = "" { didSet { updateView() }} open var contentLabel = Label().with { label in label.textStyle = .bodyLarge } open var closeButtonText: String = "Close" { didSet { updateView() }} open lazy var closeButton: UIButton = { let button = UIButton(type: .system) button.backgroundColor = .clear button.setTitle("Close", for: .normal) button.titleLabel?.font = TextStyle.bodyLarge.font button.translatesAutoresizingMaskIntoConstraints = false return button }() //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- private let containerViewBackgroundColorConfiguration = SurfaceColorConfiguration().with { instance in instance.lightColor = .white instance.darkColor = .black } private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryDark, VDSColor.backgroundPrimaryLight) private let closeButtonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) private let containerViewInset = VDSLayout.Spacing.space4X.value //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- open override func viewDidLoad() { super.viewDidLoad() isModalInPresentation = true setup() } open func setup() { //left-right swipe view.publisher(for: UISwipeGestureRecognizer().with{ $0.direction = .right }) .sink { [weak self] swipe in guard let self else { return } self.dismiss(animated: true, completion: nil) }.store(in: &subscribers) //tapping in background view.publisher(for: UITapGestureRecognizer().with{ $0.numberOfTapsRequired = 1 }) .sink { [weak self] swipe in guard let self else { return } self.dismiss(animated: true, completion: nil) }.store(in: &subscribers) //clicking button onClickSubscriber = closeButton.publisher(for: .touchUpInside) .sink {[weak self] button in guard let self else { return } self.dismiss(animated: true, completion: nil) } containerView.addSubview(titleLabel) containerView.addSubview(contentLabel) scrollView.addSubview(containerView) modalView.addSubview(scrollView) modalView.addSubview(line) modalView.addSubview(closeButton) view.addSubview(modalView) // Activate constraints NSLayoutConstraint.activate([ // Constraints for the floating modal view modalView.centerXAnchor.constraint(equalTo: view.centerXAnchor), modalView.centerYAnchor.constraint(equalTo: view.centerYAnchor), modalView.widthAnchor.constraint(equalToConstant: 296), modalView.heightAnchor.constraint(greaterThanOrEqualToConstant: 96), modalView.heightAnchor.constraint(lessThanOrEqualToConstant: 312), // Constraints for the scroll view scrollView.topAnchor.constraint(equalTo: modalView.topAnchor), scrollView.leadingAnchor.constraint(equalTo: modalView.leadingAnchor), scrollView.trailingAnchor.constraint(equalTo: modalView.trailingAnchor), scrollView.bottomAnchor.constraint(equalTo: line.topAnchor), // Constraints for the container view containerView.topAnchor.constraint(equalTo: scrollView.topAnchor, constant: containerViewInset), containerView.bottomAnchor.constraint(equalTo: scrollView.bottomAnchor, constant: -containerViewInset), containerView.leadingAnchor.constraint(equalTo: scrollView.leadingAnchor, constant: containerViewInset), containerView.trailingAnchor.constraint(equalTo: scrollView.trailingAnchor, constant: -containerViewInset), containerView.widthAnchor.constraint(equalTo: scrollView.widthAnchor, constant: -(containerViewInset * 2)), containerView.heightAnchor.constraint(greaterThanOrEqualTo: scrollView.heightAnchor, constant: -(containerViewInset * 2)), line.leadingAnchor.constraint(equalTo: modalView.leadingAnchor), line.trailingAnchor.constraint(equalTo: modalView.trailingAnchor), closeButton.topAnchor.constraint(equalTo: line.bottomAnchor), closeButton.leadingAnchor.constraint(equalTo: modalView.leadingAnchor), closeButton.trailingAnchor.constraint(equalTo: modalView.trailingAnchor), closeButton.bottomAnchor.constraint(equalTo: modalView.bottomAnchor), closeButton.heightAnchor.constraint(equalToConstant: 44.0), // Constraints on labels titleLabel.topAnchor.constraint(equalTo: containerView.topAnchor), titleLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), titleLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), contentLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: VDSLayout.Spacing.space2X.value), contentLabel.leadingAnchor.constraint(equalTo: containerView.leadingAnchor), contentLabel.trailingAnchor.constraint(equalTo: containerView.trailingAnchor), contentLabel.bottomAnchor.constraint(equalTo: containerView.bottomAnchor), ]) } open func updateView() { view.backgroundColor = backgroundColorConfiguration.getColor(self).withAlphaComponent(0.3) modalView.backgroundColor = containerViewBackgroundColorConfiguration.getColor(self) scrollView.indicatorStyle = surface == .light ? .black : .white titleLabel.surface = surface contentLabel.surface = surface line.surface = surface titleLabel.text = titleText contentLabel.text = contentText titleLabel.sizeToFit() contentLabel.sizeToFit() let closeButtonTextColor = closeButtonTextColorConfiguration.getColor(self) closeButton.setTitleColor(closeButtonTextColor, for: .normal) closeButton.setTitleColor(closeButtonTextColor, for: .highlighted) closeButton.setTitle(closeButtonText, for: .normal) } }