// // ModelViewController.swift // VDSSample // // Created by Matt Bruce on 8/15/22. // import Foundation import UIKit import Combine import VDS public class FormSection: UIStackView { public override init(frame: CGRect) { super.init(frame: frame) translatesAutoresizingMaskIntoConstraints = false alignment = .fill distribution = .fill axis = .vertical spacing = 10 } public convenience init() { self.init(frame: .zero) } required init(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } @discardableResult open func addFormRow(label: String, view: UIView) -> UIView { let formRow = UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.alignment = .fill $0.distribution = .fillEqually $0.axis = .horizontal $0.spacing = 5 } let label = Label().with { $0.text = label $0.textStyle = .bodyLarge } formRow.addArrangedSubview(label) formRow.addArrangedSubview(view) addArrangedSubview(formRow) return formRow } } public class BaseViewController: UIViewController, Initable { deinit { print("\(Self.self) deinit") } private let edgeSpacing = 16.0 //-------------------------------------------------- // MARK: - Combine Properties //-------------------------------------------------- public var subscribers = Set() //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- private var initialSetupPerformed = false //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(nibName: nil, bundle: nil) initialSetup() } 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() { overrideUserInterfaceStyle = .light if !initialSetupPerformed { initialSetupPerformed = true setup() contentTopView.backgroundColor = Surface.light.color surfacePickerSelectorView.scrollToBottom = { [weak self] in self?.scrollToBottom()} } } public lazy var surfacePickerSelectorView = { SurfacePickerSelectorView(picker: self.picker) }() public var picker: UIPickerView = { return UIPickerView().with { $0.backgroundColor = .white $0.translatesAutoresizingMaskIntoConstraints = false } }() public var component = Component() lazy var debugViewSwitch = Toggle().with{ $0.onChange = { [weak self] sender in self?.component.debugBorder(show: sender.isOn, color: .blue) } } public var contentView: UIView = { return UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false } }() public var formStackView = FormSection() 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 = contentView let spacerView = UIView().with{ $0.translatesAutoresizingMaskIntoConstraints = false } contentView.addSubview(contentTopView) contentView.addSubview(contentBottomView) contentView.addSubview(spacerView) contentBottomView.addSubview(formStackView) contentTopView.pinTop(edgeSpacing) contentTopView.pinLeading(edgeSpacing) contentTopView.pinTrailing(edgeSpacing) contentBottomView.pinTop(contentTopView.bottomAnchor, edgeSpacing) contentBottomView.pinLeading(edgeSpacing) contentBottomView.pinTrailing(edgeSpacing) spacerView .pinTop(contentBottomView.bottomAnchor, 100) .pinLeading() .pinTrailing() .pinBottom() formStackView.pinToSuperView() view.addSubview(picker) picker.pinBottom() picker.pinLeading() picker.pinTrailing() picker.isHidden = true setupForm() } private let scrollViewController = ScrollViewController() public func setupForm() { addFormRow(label: "Show Bounds", view: .makeWrapper(for: debugViewSwitch)) } public func scrollToBottom() { let bottomOffset = CGPoint(x: 0, y: scrollViewController.scrollView.contentSize.height - scrollViewController.scrollView.bounds.height + scrollViewController.scrollView.contentInset.bottom) scrollViewController.scrollView.setContentOffset(bottomOffset, animated: true) } private func embed(_ viewController: UIViewController) { addChild(viewController) view.addSubview(viewController.view) viewController.view.translatesAutoresizingMaskIntoConstraints = false viewController.view.pinToSuperView() viewController.didMove(toParent: self) } open func addContentTopView(view: UIView, edgeSpacing: CGFloat = 16.0) { view.translatesAutoresizingMaskIntoConstraints = false contentTopView.addSubview(view) view.pinToSuperView(.init(top: edgeSpacing, left: edgeSpacing, bottom: edgeSpacing, right: edgeSpacing)) } open func append(section: FormSection) { formStackView.addArrangedSubview(section) } @discardableResult open func addFormRow(label: String, view: UIView) -> UIView { let view = formStackView.addFormRow(label: label, view: view) if let pickerViewable = view as? any PickerViewable { pickerViewable.scrollToBottom = { [weak self] in self?.scrollToBottom() } } return view } open func setup() { if let textFields = allTextFields() { for textField in textFields { if textField.isNumeric { let keypadToolbar: UIToolbar = UIToolbar() // add a done button to the numberpad keypadToolbar.items=[ UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: self, action: nil), UIBarButtonItem(title: "Done", style: UIBarButtonItem.Style.done, target: textField, action: #selector(UITextField.resignFirstResponder)) ] keypadToolbar.sizeToFit() // add a toolbar with a done button above the number pad textField.inputAccessoryView = keypadToolbar textField.keyboardType = .numberPad } textField.returnKeyType = .done textField .publisher(for: .editingDidEndOnExit) .sink { textField in textField.resignFirstResponder() } .store(in: &subscribers) } } } open func updateView() { //print("\(Self.self) updateView()") } open func allTextFields() -> [TextField]? { nil } }