vds_ios_sample/VDSSample/ViewControllers/BaseViewController.swift
Matt Bruce de9243b4fa updated base viewcontroller
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2023-06-17 09:25:23 -05:00

278 lines
9.0 KiB
Swift

//
// ModelViewController.swift
// VDSSample
//
// Created by Matt Bruce on 8/15/22.
//
import Foundation
import UIKit
import Combine
import VDS
public class FormSection: UIStackView {
public var title: String? {
didSet {
if let title {
titleLabel.text = title
titleLabel.isHidden = false
} else {
titleLabel.isHidden = true
}
}
}
private var titleLabel = Label().with { $0.isHidden = true; $0.textStyle = .boldBodyLarge }
public override init(frame: CGRect) {
super.init(frame: frame)
translatesAutoresizingMaskIntoConstraints = false
alignment = .fill
distribution = .fill
axis = .vertical
spacing = 10
addArrangedSubview(titleLabel)
}
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<Component: UIView>: 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
}
}
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?.showDebug(show: sender.isOn)
}
}
open func showDebug(show: Bool) {
self.component.debugBorder(show: show, color: .blue)
}
public var formStackView = FormSection()
lazy var stackView = UIStackView().with {
$0.axis = .vertical
$0.distribution = .fill
$0.alignment = .fill
$0.spacing = 0
$0.translatesAutoresizingMaskIntoConstraints = false
}
let bottomScrollView = UIScrollView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
public var contentTopView = UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
public var contentBottomView = UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
open override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let spacerView = UIView().with{
$0.translatesAutoresizingMaskIntoConstraints = false
}
let top = UIView.makeWrapper(for: contentTopView, edgeSpacing: 16, isTrailing: false)
// Add the top and bottom views to the stack view
stackView.addArrangedSubview(top)
stackView.addArrangedSubview(bottomScrollView)
// Add the stack view to the view controller's view
view.addSubview(stackView)
// Pin the stack view to the edges of the view controller's view
NSLayoutConstraint.activate([
stackView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
stackView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
stackView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
stackView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor)
])
bottomScrollView.addSubview(contentBottomView)
// Pin the content view to the edges of the scroll view
NSLayoutConstraint.activate([
contentBottomView.leadingAnchor.constraint(equalTo: bottomScrollView.leadingAnchor),
contentBottomView.trailingAnchor.constraint(equalTo: bottomScrollView.trailingAnchor),
contentBottomView.topAnchor.constraint(equalTo: bottomScrollView.topAnchor),
contentBottomView.bottomAnchor.constraint(equalTo: bottomScrollView.bottomAnchor),
contentBottomView.widthAnchor.constraint(equalTo: bottomScrollView.widthAnchor)
])
contentBottomView.addSubview(formStackView)
formStackView.pinToSuperView(.init(top: 0, left: 16, bottom: 0, right: edgeSpacing))
view.addSubview(picker)
picker.pinBottom()
picker.pinLeading()
picker.pinTrailing()
picker.isHidden = true
setupForm()
}
public func setupForm() {
addFormRow(label: "Show Bounds", view: .makeWrapper(for: debugViewSwitch))
}
public func scrollToBottom() {
let bottomOffset = CGPoint(x: 0, y: bottomScrollView.contentSize.height - bottomScrollView.bounds.height + bottomScrollView.contentInset.bottom)
bottomScrollView.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 {
return formStackView.addFormRow(label: label, view: 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 }
}