// // ModelViewController.swift // VDSSample // // Created by Matt Bruce on 8/15/22. // import Foundation import UIKit import Combine import VDS public class ModelViewController: UIViewController, ModelHandlerable, Initable { deinit { print("\(Self.self) deinit") } //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- @Published public var model: ModelType = ModelType() public var modelPublisher: Published.Publisher { $model } public var subscribers = Set() //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- private var initialSetupPerformed = false @Proxy(\.model.surface) open var surface: Surface @Proxy(\.model.disabled) open var disabled: Bool //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(nibName: nil, bundle: nil) initialSetup() set(with: model) } public required init(with model: ModelType) { super.init(nibName: nil, bundle: nil) initialSetup() set(with: model) } public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nil, bundle: nil) initialSetup() } public required init?(coder: NSCoder) { super.init(coder: coder) initialSetup() } //-------------------------------------------------- // MARK: - Setup //-------------------------------------------------- public func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true setupUpdateView() setup() } } open func setup() {} open func shouldUpdateView(viewModel: ModelType) -> Bool { true } open func updateView(viewModel: ModelType) {} } public class ModelScrollViewController: UIViewController, ModelHandlerable, Initable { deinit { print("\(Self.self) deinit") } //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- @Published public var model: ModelType = ModelType() public var modelPublisher: Published.Publisher { $model } public var subscribers = Set() //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- private var initialSetupPerformed = false @Proxy(\.model.surface) open var surface: Surface @Proxy(\.model.disabled) open var disabled: Bool //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(nibName: nil, bundle: nil) initialSetup() set(with: model) } public required init(with model: ModelType) { super.init(nibName: nil, bundle: nil) initialSetup() set(with: model) } public override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { super.init(nibName: nil, bundle: nil) initialSetup() } public required init?(coder: NSCoder) { super.init(coder: coder) initialSetup() } //-------------------------------------------------- // MARK: - Setup //-------------------------------------------------- public func initialSetup() { if !initialSetupPerformed { initialSetupPerformed = true setupUpdateView() setup() } } public var picker = UIPickerView() public var contentStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.alignment = .fill $0.distribution = .fillProportionally $0.axis = .vertical } }() public var formStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.alignment = .fill $0.distribution = .fillProportionally $0.axis = .vertical $0.spacing = 10 } }() public var contentTopView: UIView = { return UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } }() public var contentBottomView: UIView = { return UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } }() open override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .white embed(scrollViewController) scrollViewController.scrollView.alwaysBounceVertical = true scrollViewController.contentView = contentStackView contentStackView.addArrangedSubview(contentTopView) contentStackView.addArrangedSubview(contentBottomView) contentBottomView.addSubview(formStackView) formStackView.translatesAutoresizingMaskIntoConstraints = false formStackView.topAnchor.constraint(equalTo: contentBottomView.topAnchor, constant: 16).isActive = true formStackView.leadingAnchor.constraint(equalTo: contentBottomView.leadingAnchor, constant: 16).isActive = true formStackView.trailingAnchor.constraint(equalTo: contentBottomView.trailingAnchor, constant: -16).isActive = true formStackView.bottomAnchor.constraint(equalTo: contentBottomView.bottomAnchor, constant: -150).isActive = true view.addSubview(picker) picker.translatesAutoresizingMaskIntoConstraints = false picker.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true picker.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true picker.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true picker.isHidden = true } private let scrollViewController = ScrollViewController() private func embed(_ viewController: UIViewController) { addChild(viewController) view.addSubview(viewController.view) viewController.view.translatesAutoresizingMaskIntoConstraints = false viewController.view.topAnchor.constraint(equalTo: view.topAnchor).isActive = true viewController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true viewController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true viewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true viewController.didMove(toParent: self) } open func addContentTopView(view: UIView) { contentTopView.addSubview(view) view.leadingAnchor.constraint(equalTo: contentTopView.leadingAnchor, constant: 16).isActive = true view.trailingAnchor.constraint(equalTo: contentTopView.trailingAnchor, constant: -16).isActive = true view.topAnchor.constraint(equalTo: contentTopView.topAnchor, constant: 20).isActive = true view.bottomAnchor.constraint(equalTo: contentTopView.bottomAnchor, constant: -20).isActive = true } open func addFormRow(label: String, view: UIView, stackView: UIStackView? = nil) { let formRow = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.alignment = .fill $0.distribution = .fillEqually $0.axis = .horizontal $0.spacing = 5 } let label = UILabel().with { $0.text = label } formRow.addArrangedSubview(label) formRow.addArrangedSubview(view) if let stackView { stackView.addArrangedSubview(formRow) } else { formStackView.addArrangedSubview(formRow) } } open func setup() {} open func shouldUpdateView(viewModel: ModelType) -> Bool { true } open func updateView(viewModel: ModelType) {} }