merge
This commit is contained in:
commit
52d108f8d8
@ -272,6 +272,7 @@
|
||||
AAE7270E24AC8B9300A3ED0E /* HeadersH2CaretLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */; };
|
||||
AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */; };
|
||||
AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */; };
|
||||
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */; };
|
||||
BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */; };
|
||||
BB1D17E0244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */; };
|
||||
BB1D17E2244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */; };
|
||||
@ -583,6 +584,8 @@
|
||||
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */; };
|
||||
EAA0CFB1275E823A00D65EB0 /* HideFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */; };
|
||||
EAA0CFB3275E831E00D65EB0 /* DisableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */; };
|
||||
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */; };
|
||||
EAB14BC327D9378D0012AB2C /* RuleAnyModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */; };
|
||||
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; };
|
||||
EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
@ -855,6 +858,7 @@
|
||||
AAE7270D24AC8B9300A3ED0E /* HeadersH2CaretLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2CaretLink.swift; sourceTree = "<group>"; };
|
||||
AAE96FA125341F6A0037A989 /* ListStoreLocatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocatorModel.swift; sourceTree = "<group>"; };
|
||||
AAE96FA425341F7D0037A989 /* ListStoreLocator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListStoreLocator.swift; sourceTree = "<group>"; };
|
||||
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationController+Extension.swift"; sourceTree = "<group>"; };
|
||||
BB105858248DEFF60069D008 /* UICollectionViewLeftAlignedLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UICollectionViewLeftAlignedLayout.swift; sourceTree = "<group>"; };
|
||||
BB1D17DF244EAA30001D2002 /* ListDeviceComplexButtonMediumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMediumModel.swift; sourceTree = "<group>"; };
|
||||
BB1D17E1244EAA46001D2002 /* ListDeviceComplexButtonMedium.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListDeviceComplexButtonMedium.swift; sourceTree = "<group>"; };
|
||||
@ -1167,6 +1171,8 @@
|
||||
EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormFieldEffectProtocol.swift; sourceTree = "<group>"; };
|
||||
EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleCompareModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = "<group>"; };
|
||||
EABFC151276913E800E78B40 /* FormLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelModel.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
@ -1212,12 +1218,14 @@
|
||||
children = (
|
||||
011D95A4240455DC000E3791 /* FormGroupRule.swift */,
|
||||
011D958424042432000E3791 /* RulesProtocol.swift */,
|
||||
011D959A240451E3000E3791 /* RuleRequiredModel.swift */,
|
||||
011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */,
|
||||
EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */,
|
||||
EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */,
|
||||
011D959E240453A1000E3791 /* RuleAllValueChangedModel.swift */,
|
||||
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
|
||||
011D959A240451E3000E3791 /* RuleRequiredModel.swift */,
|
||||
011D95A2240453F8000E3791 /* RuleRegexModel.swift */,
|
||||
011D959C2404536F000E3791 /* RuleAnyValueChangedModel.swift */,
|
||||
0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */,
|
||||
011D95A0240453D0000E3791 /* RuleEqualsModel.swift */,
|
||||
0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */,
|
||||
);
|
||||
name = Rules;
|
||||
@ -1529,6 +1537,15 @@
|
||||
path = Miscellaneous;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
AFE4A1D427DFBB2700C458D0 /* NavigationController */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
D2B18B93236214AD00A9AEDC /* NavigationController.swift */,
|
||||
AFE4A1D527DFBB6F00C458D0 /* UINavigationController+Extension.swift */,
|
||||
);
|
||||
path = NavigationController;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
D202AFE2242A5F1400E5BEDF /* Extensions */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
@ -2066,9 +2083,9 @@
|
||||
D29DF11921E68467003B2FB9 /* Containers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
AFE4A1D427DFBB2700C458D0 /* NavigationController */,
|
||||
0ABD1369237B18EE0081388D /* Views */,
|
||||
D29DF2B621E7BE66003B2FB9 /* SplitViewController */,
|
||||
D2B18B93236214AD00A9AEDC /* NavigationController.swift */,
|
||||
);
|
||||
path = Containers;
|
||||
sourceTree = "<group>";
|
||||
@ -2631,6 +2648,7 @@
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
||||
D2ED27FC254B0E0300A1C293 /* MVMCoreAlertObject+Swift.swift in Sources */,
|
||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||
AFE4A1D627DFBB6F00C458D0 /* UINavigationController+Extension.swift in Sources */,
|
||||
AAC23FAD24D92A0D009208DF /* ListThreeColumnSpeedTestModel.swift in Sources */,
|
||||
BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */,
|
||||
01F2C20527C81F9700DC3D36 /* SubNavSwipeAnimator.swift in Sources */,
|
||||
@ -2669,6 +2687,7 @@
|
||||
D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */,
|
||||
D2B18B7F2360913400A9AEDC /* Control.swift in Sources */,
|
||||
D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */,
|
||||
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */,
|
||||
011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */,
|
||||
BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */,
|
||||
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */,
|
||||
@ -2872,6 +2891,7 @@
|
||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
||||
323AC96C24C837FF00F8E4C4 /* ListThreeColumnBillChanges.swift in Sources */,
|
||||
EAB14BC327D9378D0012AB2C /* RuleAnyModelProtocol.swift in Sources */,
|
||||
0A0FEC7825D42A8500AF2548 /* BaseItemPickerEntryFieldModel.swift in Sources */,
|
||||
D28A837923C7D5BC00DFE4FC /* PageModelProtocol.swift in Sources */,
|
||||
D2351C7C24A4D4C3007DF0BC /* ListRightVariableToggleAllTextAndLinks.swift in Sources */,
|
||||
|
||||
@ -38,29 +38,6 @@ import UIKit
|
||||
// Default dimensions of the DigitBox
|
||||
static let size: CGSize = CGSize(width: 39, height: 44)
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public override var showError: Bool {
|
||||
get { super.showError }
|
||||
set (error) {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self = self else { return }
|
||||
|
||||
self.borderStrokeColor = error ? .mvmOrange : .mvmCoolGray3
|
||||
|
||||
let barHeight: CGFloat = self.showError ? 4 : 1
|
||||
self.bottomBar?.frame = CGRect(x: 0, y: self.bounds.height - barHeight, width: self.bounds.width, height: barHeight)
|
||||
self.bottomBar?.backgroundColor = self.showError ? UIColor.mvmOrange.cgColor : UIColor.mvmBlack.cgColor
|
||||
|
||||
self.setNeedsDisplay()
|
||||
self.layoutIfNeeded()
|
||||
}
|
||||
super.showError = error
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Delegate
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -105,7 +105,7 @@ import UIKit
|
||||
super.isLocked = locked
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override var placeholder: String? {
|
||||
get {
|
||||
var string = ""
|
||||
@ -311,7 +311,6 @@ import UIKit
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc override func startEditing() {
|
||||
|
||||
selectedDigitBox?.isSelected = true
|
||||
selectedDigitBox?.digitField.becomeFirstResponder()
|
||||
}
|
||||
@ -328,7 +327,6 @@ import UIKit
|
||||
}
|
||||
|
||||
@objc public override func dismissFieldInput(_ sender: Any?) {
|
||||
|
||||
digitBoxes.forEach {
|
||||
if $0.isSelected {
|
||||
$0.digitField.resignFirstResponder()
|
||||
@ -398,7 +396,6 @@ extension DigitEntryField {
|
||||
digitEntryModel?.text = text
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
@ -411,9 +408,9 @@ extension DigitEntryField {
|
||||
}
|
||||
|
||||
@objc public func textFieldDidBeginEditing(_ textField: UITextField) {
|
||||
|
||||
digitBoxes.forEach {
|
||||
if $0.digitField === textField {
|
||||
startEditing()
|
||||
selectedDigitBox = $0
|
||||
$0.isSelected = true
|
||||
return
|
||||
@ -429,15 +426,15 @@ extension DigitEntryField {
|
||||
}
|
||||
|
||||
@objc public func textFieldDidEndEditing(_ textField: UITextField) {
|
||||
|
||||
// There should only be one digitBox to deselect.
|
||||
selectedDigitBox?.isSelected = false
|
||||
selectedDigitBox = nil
|
||||
|
||||
if !switchFieldsAutomatically && validateWhenDoneEditing {
|
||||
validateText()
|
||||
endInputing()
|
||||
}
|
||||
|
||||
|
||||
proprietorTextDelegate?.textFieldDidEndEditing?(textField)
|
||||
}
|
||||
|
||||
|
||||
@ -94,9 +94,9 @@ import Foundation
|
||||
return text
|
||||
}
|
||||
|
||||
public func setValidity(_ valid: Bool, rule: RulesProtocol) {
|
||||
public func setValidity(_ valid: Bool, errorMessage: String?) {
|
||||
|
||||
if let fieldKey = fieldKey, let ruleErrorMessage = rule.errorMessage?[fieldKey] {
|
||||
if let ruleErrorMessage = errorMessage, fieldKey != nil {
|
||||
self.errorMessage = ruleErrorMessage
|
||||
}
|
||||
|
||||
|
||||
@ -349,7 +349,6 @@ import UIKit
|
||||
}
|
||||
|
||||
open func pageShown() {
|
||||
guard self as? MVMCoreViewManagerProtocol == nil else { return }
|
||||
// Update split view properties if this is the current detail controller.
|
||||
if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() {
|
||||
MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(bottomProgress() ?? 0)
|
||||
|
||||
@ -186,7 +186,7 @@ extension UIColor {
|
||||
//--------------------------------------------------
|
||||
|
||||
/// HEX: #F6F6F6
|
||||
public static let mvmCoolGray1 = UIColor.assetColor(named: "coolGray1")
|
||||
@objc public static let mvmCoolGray1 = UIColor.assetColor(named: "coolGray1")
|
||||
|
||||
/// HEX: #D8DADA
|
||||
public static let mvmCoolGray3 = UIColor.assetColor(named: "coolGray3")
|
||||
|
||||
@ -23,7 +23,7 @@ import UIKit
|
||||
MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController
|
||||
MVMCoreNavigationHandler.shared()?.navigationController = navigationController
|
||||
MVMCoreNavigationHandler.shared()?.addDelegate(navigationController)
|
||||
NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: NavigationItemModel())
|
||||
navigationController.setNavigationBarUI(with: NavigationItemModel())
|
||||
return navigationController
|
||||
}
|
||||
|
||||
@ -34,79 +34,6 @@ import UIKit
|
||||
return navigationController
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation item.
|
||||
public static func setNavigationItem(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) {
|
||||
viewController.navigationItem.title = navigationItemModel.title
|
||||
viewController.navigationItem.accessibilityLabel = navigationItemModel.title
|
||||
viewController.navigationItem.hidesBackButton = navigationItemModel.hidesSystemBackButton
|
||||
viewController.navigationItem.leftItemsSupplementBackButton = !navigationItemModel.hidesSystemBackButton
|
||||
setNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
setNavigationTitleView(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation buttons.
|
||||
public static func setNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, viewController: UIViewController) {
|
||||
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
|
||||
var leftItems: [UIBarButtonItem] = []
|
||||
if navigationItemModel.hidesSystemBackButton,
|
||||
navigationItemModel.alwaysShowBackButton != false {
|
||||
if let backButtonModel = navigationItemModel.backButton,
|
||||
MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 || navigationItemModel.alwaysShowBackButton ?? false {
|
||||
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
if let leftItemModels = navigationItemModel.additionalLeftButtons {
|
||||
for item in leftItemModels {
|
||||
leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
viewController.navigationItem.leftBarButtonItems = leftItems.count > 0 ? leftItems : nil
|
||||
|
||||
var rightItems: [UIBarButtonItem] = []
|
||||
if let rightItemModels = navigationItemModel.additionalRightButtons {
|
||||
for item in rightItemModels {
|
||||
rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
}
|
||||
viewController.navigationItem.rightBarButtonItems = rightItems.count > 0 ? rightItems : nil
|
||||
}
|
||||
|
||||
static func getNavigationBarShadowImage(for navigationItemModel: NavigationItemModelProtocol) -> UIImage? {
|
||||
guard let thickness = navigationItemModel.line?.thickness,
|
||||
let backgroundColor = navigationItemModel.line?.backgroundColor else { return nil }
|
||||
return backgroundColor.uiColor.image(CGSize(width: thickness, height: thickness))
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation bar ui, except for the buttons.
|
||||
public static func setNavigationBarUI(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
|
||||
let navigationBar = navigationController.navigationBar
|
||||
let font = MFStyler.fontBoldBodySmall(false)
|
||||
let backgroundColor = navigationItemModel.backgroundColor?.uiColor
|
||||
let tint = navigationItemModel.tintColor.uiColor
|
||||
navigationBar.tintColor = tint
|
||||
|
||||
let appearance = UINavigationBarAppearance()
|
||||
appearance.configureWithOpaqueBackground()
|
||||
appearance.titleTextAttributes = [NSAttributedString.Key.font: font,
|
||||
NSAttributedString.Key.foregroundColor: tint];
|
||||
appearance.backgroundColor = backgroundColor
|
||||
appearance.titleTextAttributes.updateValue(tint, forKey: .foregroundColor)
|
||||
appearance.shadowColor = navigationItemModel.line?.backgroundColor?.uiColor ?? .clear
|
||||
appearance.shadowImage = getNavigationBarShadowImage(for: navigationItemModel)?.withRenderingMode(.alwaysTemplate)
|
||||
navigationBar.standardAppearance = appearance
|
||||
navigationBar.scrollEdgeAppearance = appearance
|
||||
|
||||
navigationController.setNavigationBarHidden(navigationItemModel.hidden, animated: true)
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation titleView.
|
||||
public static func setNavigationTitleView(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
|
||||
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
|
||||
if let titleViewModel = navigationItemModel?.titleView, let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) {
|
||||
viewController.navigationItem.titleView = molecule
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience function to return the navigation model of the lowest controller traversing managers if applicable.
|
||||
public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? {
|
||||
return (viewController as? PageProtocol)?.pageModel?.navigationBar
|
||||
@ -146,8 +73,8 @@ extension NavigationController: MVMCoreViewManagerProtocol {
|
||||
if isDisplayed(viewController: viewController),
|
||||
let topViewController = topViewController,
|
||||
let model = getNavigationModel(from: viewController) {
|
||||
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController)
|
||||
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model)
|
||||
setNavigationItem(with: model, for: topViewController)
|
||||
setNavigationBarUI(with: model)
|
||||
}
|
||||
manager?.newDataReceived?(in: viewController)
|
||||
}
|
||||
@ -155,7 +82,7 @@ extension NavigationController: MVMCoreViewManagerProtocol {
|
||||
public func willDisplay(_ viewController: UIViewController) {
|
||||
if let topViewController = topViewController,
|
||||
let model = getNavigationModel(from: viewController) {
|
||||
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: topViewController)
|
||||
setNavigationItem(with: model, for: topViewController)
|
||||
}
|
||||
manager?.willDisplay?(viewController)
|
||||
}
|
||||
@ -163,7 +90,7 @@ extension NavigationController: MVMCoreViewManagerProtocol {
|
||||
public func displayedViewController(_ viewController: UIViewController) {
|
||||
if isDisplayed(viewController: viewController),
|
||||
let model = getNavigationModel(from: viewController) {
|
||||
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model)
|
||||
setNavigationBarUI(with: model)
|
||||
}
|
||||
manager?.displayedViewController?(viewController)
|
||||
}
|
||||
@ -174,7 +101,7 @@ extension NavigationController: MVMCorePresentationDelegateProtocol {
|
||||
guard self == navigationController,
|
||||
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController),
|
||||
let model = getNavigationModel(from: newViewController) else { return }
|
||||
Self.setNavigationItem(navigationController: self, navigationItemModel: model, viewController: viewController)
|
||||
setNavigationItem(with: model, for: viewController)
|
||||
}
|
||||
|
||||
public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) {
|
||||
@ -190,7 +117,7 @@ extension NavigationController: MVMCorePresentationDelegateProtocol {
|
||||
guard self == navigationController,
|
||||
let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
|
||||
if let model = getNavigationModel(from: newViewController) {
|
||||
Self.setNavigationBarUI(navigationController: self, navigationItemModel: model)
|
||||
setNavigationBarUI(with: model)
|
||||
}
|
||||
manager?.displayedViewController?(newViewController)
|
||||
if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
|
||||
@ -0,0 +1,87 @@
|
||||
//
|
||||
// UINavigationController+Extension.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Scott Pfeil on 3/14/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
public extension UINavigationController {
|
||||
|
||||
/// Convenience function for setting the navigation item.
|
||||
func setNavigationItem(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
|
||||
viewController.navigationItem.title = model.title
|
||||
viewController.navigationItem.accessibilityLabel = model.title
|
||||
viewController.navigationItem.hidesBackButton = model.hidesSystemBackButton
|
||||
viewController.navigationItem.leftItemsSupplementBackButton = !model.hidesSystemBackButton
|
||||
setNavigationButtons(with: model, for: viewController)
|
||||
setNavigationTitleView(with: model, for: viewController)
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation buttons.
|
||||
func setNavigationButtons(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
|
||||
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
|
||||
var leftItems: [UIBarButtonItem] = []
|
||||
if model.hidesSystemBackButton,
|
||||
model.alwaysShowBackButton != false {
|
||||
if let backButtonModel = model.backButton,
|
||||
MVMCoreNavigationHandler.shared()?.getViewControllers(for: self)?.count ?? 0 > 1 || model.alwaysShowBackButton ?? false {
|
||||
leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
if let leftItemModels = model.additionalLeftButtons {
|
||||
for item in leftItemModels {
|
||||
leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
}
|
||||
}
|
||||
viewController.navigationItem.leftBarButtonItems = leftItems.count > 0 ? leftItems : nil
|
||||
|
||||
var rightItems: [UIBarButtonItem] = []
|
||||
if let rightItemModels = model.additionalRightButtons {
|
||||
for item in rightItemModels {
|
||||
rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
|
||||
}
|
||||
}
|
||||
viewController.navigationItem.rightBarButtonItems = rightItems.count > 0 ? rightItems : nil
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation titleView.
|
||||
func setNavigationTitleView(with model: NavigationItemModelProtocol, for viewController: UIViewController) {
|
||||
let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
|
||||
if let titleViewModel = model.titleView,
|
||||
let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) {
|
||||
viewController.navigationItem.titleView = molecule
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a ShadowImage based on the line property of NavigationItemModelProtocol
|
||||
func getNavigationBarShadowImage(for navigationItemModel: NavigationItemModelProtocol) -> UIImage? {
|
||||
guard let thickness = navigationItemModel.line?.thickness,
|
||||
let backgroundColor = navigationItemModel.line?.backgroundColor else { return nil }
|
||||
return backgroundColor.uiColor.image(CGSize(width: thickness, height: thickness))
|
||||
}
|
||||
|
||||
/// Convenience function for setting the navigation bar ui
|
||||
func setNavigationBarUI(with model: NavigationItemModelProtocol) {
|
||||
let navigationBar = navigationBar
|
||||
let font = MFStyler.fontBoldBodySmall(false)
|
||||
let backgroundColor = model.backgroundColor?.uiColor
|
||||
let tint = model.tintColor.uiColor
|
||||
navigationBar.tintColor = tint
|
||||
|
||||
let appearance = UINavigationBarAppearance()
|
||||
appearance.configureWithOpaqueBackground()
|
||||
appearance.titleTextAttributes = [NSAttributedString.Key.font: font,
|
||||
NSAttributedString.Key.foregroundColor: tint];
|
||||
appearance.backgroundColor = backgroundColor
|
||||
appearance.titleTextAttributes.updateValue(tint, forKey: .foregroundColor)
|
||||
appearance.shadowColor = model.line?.backgroundColor?.uiColor ?? .clear
|
||||
appearance.shadowImage = getNavigationBarShadowImage(for: model)?.withRenderingMode(.alwaysTemplate)
|
||||
navigationBar.standardAppearance = appearance
|
||||
navigationBar.scrollEdgeAppearance = appearance
|
||||
|
||||
setNavigationBarHidden(model.hidden, animated: true)
|
||||
}
|
||||
}
|
||||
@ -13,18 +13,13 @@ import UIKit
|
||||
public extension MVMCoreUISplitViewController {
|
||||
|
||||
/// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol.
|
||||
static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
|
||||
guard let splitView = MVMCoreUISplitViewController.main(),
|
||||
navigationController == splitView.navigationController,
|
||||
viewController == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() else {
|
||||
func setNavigationBar(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
|
||||
guard navigationController == self.navigationController,
|
||||
viewController == getCurrentDetailViewController() else {
|
||||
/// Not the split view navigation controller, skip split functions.
|
||||
return
|
||||
}
|
||||
splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel)
|
||||
}
|
||||
|
||||
/// Sets the navigation item for the view controller based on the model and splitview controller
|
||||
private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
|
||||
|
||||
setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
|
||||
setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
|
||||
|
||||
@ -122,7 +117,7 @@ public extension MVMCoreUISplitViewController {
|
||||
guard let navigationController = navigationController,
|
||||
navigationController.isDisplayed(viewController: viewController),
|
||||
let model = navigationController.getNavigationModel(from: viewController) else { return }
|
||||
set(for: viewController, navigationController: navigationController, navigationItemModel: model)
|
||||
setNavigationBar(for: viewController, navigationController: navigationController, navigationItemModel: model)
|
||||
guard !(topAlertView?.overridingStatusBar() ?? false) else { return }
|
||||
setStatusBarForCurrentViewController()
|
||||
}
|
||||
|
||||
@ -29,3 +29,19 @@ public extension FormFieldProtocol {
|
||||
|
||||
var baseValue: AnyHashable? { nil }
|
||||
}
|
||||
|
||||
public class FormFieldValidity{
|
||||
public var fieldKey: String
|
||||
public var valid: Bool = true
|
||||
public var errorMessages: [String] = []
|
||||
|
||||
public init(_ fieldKey: String){
|
||||
self.fieldKey = fieldKey
|
||||
}
|
||||
|
||||
public func addError(message: String?){
|
||||
if let message = message {
|
||||
self.errorMessages.append(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -10,5 +10,5 @@
|
||||
import Foundation
|
||||
|
||||
public protocol FormRuleWatcherFieldProtocol {
|
||||
func setValidity(_ valid: Bool, rule: RulesProtocol)
|
||||
func setValidity(_ valid: Bool, errorMessage: String?)
|
||||
}
|
||||
|
||||
@ -133,11 +133,10 @@ import MVMCore
|
||||
let tuple = group.validate(fields)
|
||||
|
||||
//set the validity for the fields
|
||||
group.rules.forEach { rule in
|
||||
for formKey in rule.fields {
|
||||
guard let formField = fields[formKey] as? FormRuleWatcherFieldProtocol,
|
||||
let fieldValidity = tuple.fieldValidity[formKey] else { continue }
|
||||
formField.setValidity(fieldValidity, rule: rule)
|
||||
fields.forEach { (key: String, value: FormFieldProtocol) in
|
||||
if let formField = value as? FormRuleWatcherFieldProtocol,
|
||||
let fieldValidity = tuple.fieldValidity[key] {
|
||||
formField.setValidity(fieldValidity.valid, errorMessage: fieldValidity.errorMessages.last)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -0,0 +1,45 @@
|
||||
//
|
||||
// RuleAnyModelProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 3/9/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// RuleAnyModelProtocol was abstracted to 1 place since this code was currently
|
||||
/// duplicated in 2 classes.
|
||||
/// This protocol should be used for the rules that need to Loop through all of the fields
|
||||
/// and if ANY formField's isValid == TRUE, the Rule is then TRUE
|
||||
public protocol RuleAnyModelProtocol: RulesProtocol{}
|
||||
|
||||
extension RuleAnyModelProtocol {
|
||||
|
||||
/// Overriding the RulesProtocol default implementation
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: FormFieldValidity]) -> (valid: Bool, fieldValidity: [String: FormFieldValidity]) {
|
||||
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
|
||||
var fieldValidity = isValid(formField)
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity.valid, fieldValidity {
|
||||
fieldValidity = false
|
||||
}
|
||||
|
||||
// If TRUE the RULE is TRUE, even if there are many fields to check.
|
||||
if fieldValidity {
|
||||
return (true, previousFieldValidity)
|
||||
}
|
||||
}
|
||||
|
||||
// if the rule breaks all fields should be set to false
|
||||
fields.forEach { (formKey) in
|
||||
previousFieldValidity[formKey]?.valid = false
|
||||
previousFieldValidity[formKey]?.addError(message: errorMessage?[formKey])
|
||||
}
|
||||
return (valid: false, fieldValidity: previousFieldValidity)
|
||||
}
|
||||
|
||||
}
|
||||
@ -8,8 +8,7 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
public class RuleAnyRequiredModel: RulesProtocol {
|
||||
public class RuleAnyRequiredModel: RuleAnyModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -37,27 +36,4 @@ public class RuleAnyRequiredModel: RulesProtocol {
|
||||
return false
|
||||
}
|
||||
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: Bool]) -> (valid: Bool, fieldValidity: [String: Bool]) {
|
||||
|
||||
var previousValidity: [String: Bool] = [:]
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
|
||||
var fieldValidity = isValid(formField)
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity, fieldValidity {
|
||||
fieldValidity = false
|
||||
}
|
||||
|
||||
if fieldValidity {
|
||||
return (fieldValidity, previousValidity)
|
||||
}
|
||||
}
|
||||
|
||||
// if the rule breaks all fields should be set to false
|
||||
fields.forEach { (formKey) in
|
||||
previousValidity[formKey] = false
|
||||
}
|
||||
return (valid: false, fieldValidity: previousValidity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,8 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public class RuleAnyValueChangedModel: RulesProtocol {
|
||||
public class RuleAnyValueChangedModel: RuleAnyModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -27,26 +26,4 @@ public class RuleAnyValueChangedModel: RulesProtocol {
|
||||
public func isValid(_ formField: FormFieldProtocol) -> Bool {
|
||||
return formField.baseValue != formField.formFieldValue()
|
||||
}
|
||||
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: Bool]) -> (valid: Bool, fieldValidity: [String: Bool]) {
|
||||
var previousValidity: [String: Bool] = [:]
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
var fieldValidity = isValid(formField)
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity, fieldValidity {
|
||||
fieldValidity = false
|
||||
}
|
||||
|
||||
if fieldValidity {
|
||||
return (true, previousValidity)
|
||||
}
|
||||
}
|
||||
|
||||
// if the rule breaks all fields should be set to false
|
||||
fields.forEach { (formKey) in
|
||||
previousValidity[formKey] = false
|
||||
}
|
||||
return (valid: false, fieldValidity: previousValidity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,55 @@
|
||||
//
|
||||
// RuleCompareModelProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 3/9/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// RuleCompareModelProtocol is meant to be used for rules that compare
|
||||
/// 2 FormField's values. It is up to the Implementing class to determine what
|
||||
/// occurs within the "compare" method that is required. This can be anything
|
||||
/// that returns a Bool. More than likley it will be a <,>, <=, =>, == comparison.
|
||||
public protocol RuleCompareModelProtocol: RulesProtocol {
|
||||
associatedtype CompareType
|
||||
func compare(lhs: CompareType?, rhs: CompareType?) -> Bool
|
||||
}
|
||||
|
||||
extension RuleCompareModelProtocol {
|
||||
|
||||
/// This overrides the RulesProtocol default implementation to then use your class implementation's "compare" method.
|
||||
/// A requirement of this rule is that the fields array contains at least 2 fieldKeys and it will pull out these formFields with ONLY
|
||||
/// the first 2 keys to send to the compare method your class will be implementing.
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: FormFieldValidity]) -> (valid: Bool, fieldValidity: [String: FormFieldValidity]) {
|
||||
var valid = false
|
||||
|
||||
guard fields.count > 1, let firstFormField = fieldMolecules[fields[0]],
|
||||
let secondFormField = fieldMolecules[fields[1]] else {
|
||||
return (valid: true, previousFieldValidity)
|
||||
}
|
||||
|
||||
let result = compare(lhs: firstFormField.formFieldValue() as? CompareType, rhs: secondFormField.formFieldValue() as? CompareType)
|
||||
|
||||
let formKey = fields[1]
|
||||
|
||||
//only check the 2nd value
|
||||
if result {
|
||||
valid = true
|
||||
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity.valid, valid {
|
||||
valid = false
|
||||
}
|
||||
previousFieldValidity[formKey]?.valid = valid
|
||||
|
||||
} else { //false
|
||||
previousFieldValidity[formKey]?.valid = valid
|
||||
previousFieldValidity[formKey]?.addError(message: errorMessage?[formKey])
|
||||
}
|
||||
|
||||
return (valid: valid, fieldValidity: previousFieldValidity)
|
||||
|
||||
}
|
||||
}
|
||||
@ -9,7 +9,7 @@
|
||||
import Foundation
|
||||
|
||||
|
||||
public class RuleEqualsIgnoreCaseModel: RulesProtocol {
|
||||
public class RuleEqualsIgnoreCaseModel: RuleCompareModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -27,35 +27,12 @@ public class RuleEqualsIgnoreCaseModel: RulesProtocol {
|
||||
public func isValid(_ formField: FormFieldProtocol) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: Bool]) -> (valid: Bool, fieldValidity: [String: Bool]) {
|
||||
var valid = false
|
||||
var compareText: String?
|
||||
|
||||
var previousValidity: [String: Bool] = [:]
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
|
||||
guard let compareString = compareText else {
|
||||
compareText = formField.formFieldValue() as? String
|
||||
continue
|
||||
}
|
||||
|
||||
if let fieldValue = formField.formFieldValue() as? String,
|
||||
compareString.caseInsensitiveCompare(fieldValue) == .orderedSame {
|
||||
valid = true
|
||||
|
||||
var fieldValidity = valid
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity, fieldValidity {
|
||||
fieldValidity = false
|
||||
}
|
||||
previousValidity[formKey] = valid
|
||||
break
|
||||
}
|
||||
|
||||
previousValidity[formKey] = valid
|
||||
|
||||
///RuleCompareModelProtocol Method
|
||||
public func compare(lhs: String?, rhs: String?) -> Bool {
|
||||
guard let rhs = rhs else {
|
||||
return false
|
||||
}
|
||||
return (valid: valid, fieldValidity: previousValidity)
|
||||
return lhs?.caseInsensitiveCompare(rhs) == .orderedSame
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,8 +8,7 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
public class RuleEqualsModel: RulesProtocol {
|
||||
public class RuleEqualsModel: RuleCompareModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -27,33 +26,10 @@ public class RuleEqualsModel: RulesProtocol {
|
||||
public func isValid(_ formField: FormFieldProtocol) -> Bool {
|
||||
return false
|
||||
}
|
||||
|
||||
public func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: Bool]) -> (valid: Bool, fieldValidity: [String: Bool]) {
|
||||
var valid = true
|
||||
var compareValue: AnyHashable?
|
||||
var previousValidity: [String: Bool] = [:]
|
||||
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
|
||||
if compareValue == nil {
|
||||
compareValue = formField.formFieldValue()
|
||||
continue
|
||||
}
|
||||
|
||||
if compareValue != formField.formFieldValue() {
|
||||
valid = false
|
||||
previousValidity[formKey] = valid
|
||||
break
|
||||
} else {
|
||||
var fieldValidity = valid
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity, fieldValidity {
|
||||
fieldValidity = false
|
||||
}
|
||||
previousValidity[formKey] = valid
|
||||
}
|
||||
}
|
||||
return (valid: valid, fieldValidity: previousValidity)
|
||||
|
||||
///RuleCompareModelProtocol Method
|
||||
public func compare(lhs: AnyHashable?, rhs: AnyHashable?) -> Bool {
|
||||
return lhs == rhs
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ public protocol RulesProtocol: ModelProtocol {
|
||||
func isValid(_ formField: FormFieldProtocol) -> Bool
|
||||
|
||||
// Validates the rule and returns the result.
|
||||
func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: Bool]) -> (valid: Bool, fieldValidity: [String: Bool])
|
||||
func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: FormFieldValidity]) -> (valid: Bool, fieldValidity: [String: FormFieldValidity])
|
||||
}
|
||||
|
||||
public extension RulesProtocol {
|
||||
@ -42,21 +42,30 @@ public extension RulesProtocol {
|
||||
static var categoryName: String { "\(RulesProtocol.self)" }
|
||||
|
||||
// Individual rule can override the function to validate based on the rule type.
|
||||
func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: Bool]) -> (valid: Bool, fieldValidity: [String: Bool]) {
|
||||
func validate(_ fieldMolecules: [String: FormFieldProtocol],_ previousFieldValidity: [String: FormFieldValidity]) -> (valid: Bool, fieldValidity: [String: FormFieldValidity]) {
|
||||
var valid = true
|
||||
var previousValidity: [String: Bool] = [:]
|
||||
for formKey in fields {
|
||||
guard let formField = fieldMolecules[formKey] else { continue }
|
||||
|
||||
//check the field isValid
|
||||
var fieldValidity = isValid(formField)
|
||||
|
||||
//add the error message if it exists
|
||||
if fieldValidity == false {
|
||||
previousFieldValidity[formKey]?.addError(message: errorMessage?[formKey])
|
||||
}
|
||||
|
||||
// If past rule is invalid for a field, the current rule should not flip the validity of a field
|
||||
if let validity = previousFieldValidity[formKey], !validity, fieldValidity {
|
||||
if let validity = previousFieldValidity[formKey], !validity.valid, fieldValidity {
|
||||
fieldValidity = false
|
||||
}
|
||||
//set the valid for the field
|
||||
previousFieldValidity[formKey]?.valid = fieldValidity
|
||||
|
||||
//set the full validity
|
||||
valid = valid && fieldValidity
|
||||
previousValidity[formKey] = fieldValidity
|
||||
}
|
||||
return (valid: valid, fieldValidity: previousValidity)
|
||||
return (valid: valid, fieldValidity: previousFieldValidity)
|
||||
}
|
||||
}
|
||||
|
||||
@ -73,16 +82,16 @@ public extension RulesContainerProtocol {
|
||||
/// - Returns: Tuple(valid, fieldValidity)
|
||||
/// - valid: bool for all rules
|
||||
/// - fieldValidity: accumulation of all fieldKey: valid
|
||||
func validate(_ fields: [String: FormFieldProtocol]) -> (valid: Bool, fieldValidity: [String:Bool] ) {
|
||||
func validate(_ fields: [String: FormFieldProtocol]) -> (valid: Bool, fieldValidity: [String:FormFieldValidity]) {
|
||||
// Validate each rule.
|
||||
var valid = true
|
||||
var previousValidity: [String: Bool] = [:]
|
||||
var previousValidity: [String: FormFieldValidity] = [:]
|
||||
fields.keys.forEach { key in
|
||||
previousValidity[key] = FormFieldValidity(key)
|
||||
}
|
||||
for rule in self.rules {
|
||||
//validate the rule against the fields
|
||||
let tuple = rule.validate(fields, previousValidity)
|
||||
|
||||
//merge the fieldValidity
|
||||
previousValidity = previousValidity.merging(tuple.fieldValidity) { (_, new) in new }
|
||||
valid = valid && tuple.valid
|
||||
}
|
||||
return (valid: valid, fieldValidity: previousValidity)
|
||||
|
||||
@ -111,7 +111,7 @@ open class SubNavManagerController: ViewController, MVMCoreViewManagerProtocol,
|
||||
}
|
||||
|
||||
open override func pageShown() {
|
||||
super.pageShown()
|
||||
// Currently not calling super until we can decouple page shown logics for managers.
|
||||
hideNavigationBarLine(true)
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user