225 lines
7.2 KiB
Swift
225 lines
7.2 KiB
Swift
//
|
|
// ModelViewController.swift
|
|
// VDSSample
|
|
//
|
|
// Created by Matt Bruce on 8/15/22.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import Combine
|
|
import VDS
|
|
|
|
public class BaseViewController: UIViewController, Initable {
|
|
deinit {
|
|
print("\(Self.self) deinit")
|
|
}
|
|
|
|
private let edgeSpacing = 16.0
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Combine Properties
|
|
//--------------------------------------------------
|
|
public var subscribers = Set<AnyCancellable>()
|
|
|
|
//--------------------------------------------------
|
|
// 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 contentView: UIView = {
|
|
return UIView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
}
|
|
}()
|
|
|
|
public var formStackView: UIStackView = {
|
|
return UIStackView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
$0.alignment = .fill
|
|
$0.distribution = .fill
|
|
$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 = 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
|
|
}
|
|
|
|
private let scrollViewController = ScrollViewController()
|
|
|
|
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) {
|
|
view.translatesAutoresizingMaskIntoConstraints = false
|
|
contentTopView.addSubview(view)
|
|
view.pinToSuperView(.init(top: edgeSpacing, left: edgeSpacing, bottom: edgeSpacing, right: edgeSpacing))
|
|
}
|
|
|
|
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 = Label().with {
|
|
$0.text = label
|
|
$0.textStyle = .bodyLarge
|
|
}
|
|
|
|
formRow.addArrangedSubview(label)
|
|
formRow.addArrangedSubview(view)
|
|
|
|
if let stackView {
|
|
stackView.addArrangedSubview(formRow)
|
|
} else {
|
|
formStackView.addArrangedSubview(formRow)
|
|
}
|
|
|
|
if let pickerViewable = view as? any PickerViewable {
|
|
pickerViewable.scrollToBottom = { [weak self] in self?.scrollToBottom() }
|
|
}
|
|
}
|
|
|
|
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 }
|
|
}
|