diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 2f9e8526..5b09bfb8 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -196,6 +196,7 @@ D22D1F47220496A30077CEC0 /* MVMCoreUISwitch.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */; }; D22D1F562204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */; }; + D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22D8392241C27B100D3DF69 /* TemplateModel.swift */; }; D243859923A16B1800332775 /* Container.swift in Sources */ = {isa = PBXBuildFile; fileRef = D243859823A16B1800332775 /* Container.swift */; }; D256E9932412880000360572 /* Header.swift in Sources */ = {isa = PBXBuildFile; fileRef = D256E9922412880000360572 /* Header.swift */; }; D260105323CEA61600764D80 /* ToggleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D260105223CEA61600764D80 /* ToggleModel.swift */; }; @@ -563,6 +564,7 @@ D22D1F45220496A30077CEC0 /* MVMCoreUISwitch.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUISwitch.m; sourceTree = ""; }; D22D1F542204CE5D0077CEC0 /* MVMCoreUIStackableViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIStackableViewController.h; sourceTree = ""; }; D22D1F552204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIStackableViewController.m; sourceTree = ""; }; + D22D8392241C27B100D3DF69 /* TemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModel.swift; sourceTree = ""; }; D243859823A16B1800332775 /* Container.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Container.swift; sourceTree = ""; }; D256E9922412880000360572 /* Header.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Header.swift; sourceTree = ""; }; D260105223CEA61600764D80 /* ToggleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleModel.swift; sourceTree = ""; }; @@ -1237,6 +1239,7 @@ isa = PBXGroup; children = ( 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, + D22D8392241C27B100D3DF69 /* TemplateModel.swift */, 014AA72823C5059B006F3E93 /* StackPageTemplateModel.swift */, D2A5146022121FBF00345BFB /* MoleculeStackTemplate.swift */, 942C378D2412F5B60066E45E /* ModalMoleculeStackTemplate.swift */, @@ -2033,6 +2036,7 @@ D29DF26C21E6AA0B003B2FB9 /* FLAnimatedImage.m in Sources */, D28A839123CD4FD400DFE4FC /* CornerLabelsModel.swift in Sources */, 012A88F123985E0100FE3DA1 /* Color.swift in Sources */, + D22D8393241C27B100D3DF69 /* TemplateModel.swift in Sources */, 012A889C23889E8400FE3DA1 /* TemplateModelProtocol.swift in Sources */, D29770FC21F7C77400B2F0D0 /* MVMCoreUITextFieldView.m in Sources */, 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */, diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 7aca8f01..080c48c2 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -32,26 +32,6 @@ open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMC private var previousScreenSize = CGSize.zero public var selectedField: UIView? - - public var masterShouldBeAccessible: Bool = false { - didSet { - if let manager = manager as? MFViewController { - manager.masterShouldBeAccessible = masterShouldBeAccessible - } else if MVMCoreUISplitViewController.main()?.getCurrentVisibleController() == self { - MVMCoreUISplitViewController.main()?.setLeftPanelIsAccessible(masterShouldBeAccessible, for: self) - } - } - } - - public var supportShouldBeAccessible: Bool = false { - didSet { - if let manager = manager as? MFViewController { - manager.supportShouldBeAccessible = supportShouldBeAccessible - } else if MVMCoreUISplitViewController.main()?.getCurrentVisibleController() == self { - MVMCoreUISplitViewController.main()?.setRightPanelIsAccessible(supportShouldBeAccessible, for: self) - } - } - } /// Checks if the screen width has changed open func screenSizeChanged() -> Bool { @@ -143,6 +123,24 @@ open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMC } open func parsePageJSON() throws { + if pageModel?.navigationItem == nil { + let navigationModel = NavigationItemModel() + if navigationModel.title == nil { + navigationModel.title = pageModel?.screenHeading + } + if navigationModel.showLeftPanelButton == nil { + navigationModel.showLeftPanelButton = isMasterInitiallyAccessible() + } + if navigationModel.showRightPanelButton == nil { + navigationModel.showRightPanelButton = isSupportInitiallyAccessible() + } + pageModel?.navigationItem = navigationModel + } + if self.formValidator == nil, + let model = pageModel as? FormHolderModelProtocol { + let rules = model.formRules + self.formValidator = FormValidator(rules) + } } open class func verifyRequiredModulesLoaded(for loadObject: MVMCoreLoadObject?, error: inout MVMCoreErrorObject?) -> Bool { @@ -175,37 +173,35 @@ open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMC /// Processes any new data. Called after the page is loaded the first time and on response updates for this page, open func handleNewData() { - // TODO atomize the navigation item - set(navigationController: navigationController) formValidator?.validate() } // MARK: - Navigation Item (Move to model base) open func set(navigationController: UINavigationController?) { - navigationItem.title = pageModel?.screenHeading - navigationItem.accessibilityLabel = pageModel?.screenHeading - guard let navigationController = navigationController else { + guard let navigationItemModel = pageModel?.navigationItem, + let navigationController = navigationController else { MVMCoreUISession.sharedGlobal()?.splitViewController?.parent?.setNeedsStatusBarAppearanceUpdate() return } - navigationController.setNavigationBarHidden(isNavigationBarHidden(), animated: true) - UIColor.setBackgroundColor(forNavigationBar: navigationBarColor(), navigationBar: navigationController.navigationBar, transparent: navigationBarTransparent()) + navigationItem.title = navigationItemModel.title + navigationItem.accessibilityLabel = navigationItemModel.title - let tint = navigationBarTintColor() ?? .black + navigationController.setNavigationBarHidden(navigationItemModel.hidden, animated: true) + UIColor.setBackgroundColor(forNavigationBar: navigationItemModel.backgroundColor?.uiColor ?? .white, navigationBar: navigationController.navigationBar, transparent: navigationItemModel.transparent) + + let tint = navigationItemModel.tintColor.uiColor navigationController.navigationBar.tintColor = tint // Have the navigation title match the tint color - navigationController.navigationBar.titleTextAttributes?.updateValue(navigationBarTintColor, forKey: .foregroundColor) + navigationController.navigationBar.titleTextAttributes?.updateValue(tint, forKey: .foregroundColor) - if navigationController == MVMCoreUISplitViewController.main()?.navigationController { - // Update icons if main navigation controller. + // Update icons if main navigation controller. + if navigationController == MVMCoreUISplitViewController.main()?.navigationController, + MVMCoreUISplitViewController.main()?.getCurrentVisibleController() == self { MVMCoreUISession.sharedGlobal()?.splitViewController?.setupPanels() - let master = masterShouldBeAccessible - masterShouldBeAccessible = master - let support = supportShouldBeAccessible - supportShouldBeAccessible = support - - showBottomProgressBar() + MVMCoreUISplitViewController.main()?.setLeftPanelIsAccessible(navigationItemModel.showLeftPanelButton ?? false, for: self) + MVMCoreUISplitViewController.main()?.setRightPanelIsAccessible(navigationItemModel.showRightPanelButton ?? false, for: self) + showBottomProgressBar() MVMCoreUISession.sharedGlobal()?.splitViewController?.setNavigationIconColor(tint) // Update separator. @@ -213,22 +209,6 @@ open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMC } } - open func navigationBarColor() -> UIColor { - return .white - } - - open func isNavigationBarHidden() -> Bool { - return false - } - - open func navigationBarTransparent() -> Bool { - return false - } - - open func navigationBarTintColor() -> UIColor? { - return nil - } - open func isMasterInitiallyAccessible() -> Bool { if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { return false diff --git a/MVMCoreUI/FormUIHelpers/New/FormProtocol.swift b/MVMCoreUI/FormUIHelpers/New/FormProtocol.swift index bef7f547..1e096372 100644 --- a/MVMCoreUI/FormUIHelpers/New/FormProtocol.swift +++ b/MVMCoreUI/FormUIHelpers/New/FormProtocol.swift @@ -9,7 +9,6 @@ import Foundation //Protocol for Validation -public protocol FormProtocol: class { +public protocol FormHolderModelProtocol: class { var formRules: [FormGroupRule]? { get set } - var formValidator: FormValidator? { get set } } diff --git a/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift b/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift index a981ec64..646123e1 100644 --- a/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift +++ b/MVMCoreUI/Models/ModelProtocols/TemplateModelProtocol.swift @@ -9,7 +9,7 @@ import Foundation -public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, FormProtocol { +public protocol TemplateModelProtocol: PageModelProtocol, ModelProtocol, FormHolderModelProtocol { var template: String { get } } diff --git a/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift b/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift index acddb931..24b375fe 100644 --- a/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift +++ b/MVMCoreUI/Molecules/NavigationItemModelProtocol.swift @@ -8,10 +8,112 @@ import Foundation -public protocol NavigationItemModelProtocol: ModelProtocol { - +public protocol NavigationItemModelProtocol: MoleculeModelProtocol { + var title: String? { get set } + var titleView: MoleculeModelProtocol? { get set } + var hidden: Bool { get set } + var backgroundColor: Color? { get set } + var transparent: Bool { get set } + var tintColor: Color { get set } + var systemBackButton: Bool? { get set } + var showLeftPanelButton: Bool? { get set } + var showRightPanelButton: Bool? { get set } + var additionalLeftItems: [NavigationItemButtonModel]? { get set } + var additionalRightItems: [NavigationItemButtonModel]? { get set } } -public protocol NavigationItemButtonModelProtocol { +public class NavigationItemButtonModel: Codable { + var imageName: String + var action: ActionModelProtocol + public init(with imageName: String, action: ActionModelProtocol) { + self.imageName = imageName + self.action = action + } + + private enum CodingKeys: String, CodingKey { + case imageName + case action + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + imageName = try typeContainer.decode(String.self, forKey: .imageName) + action = try typeContainer.decodeModel(codingKey: .action) + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(imageName, forKey: .imageName) + try container.encodeModel(action, forKey: .action) + } +} + +public class NavigationItemModel: NavigationItemModelProtocol { + public class var identifier: String { + return "navigationItem" + } + + public var title: String? + public var titleView: MoleculeModelProtocol? + public var hidden: Bool + public var backgroundColor: Color? + public var transparent: Bool + public var tintColor: Color + public var systemBackButton: Bool? + public var showLeftPanelButton: Bool? + public var showRightPanelButton: Bool? + public var additionalLeftItems: [NavigationItemButtonModel]? + public var additionalRightItems: [NavigationItemButtonModel]? + + init() { + hidden = false + transparent = false + backgroundColor = Color(uiColor: .white) + tintColor = Color(uiColor: .black) + } + + private enum CodingKeys: String, CodingKey { + case title + case titleView + case hidden + case backgroundColor + case transparent + case tintColor + case systemBackButton + case showLeftPanelButton + case showRightPanelButton + case additionalLeftItems + case additionalRightItems + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + title = try typeContainer.decodeIfPresent(String.self, forKey: .title) + titleView = try typeContainer.decodeModelIfPresent(codingKey: .titleView) + hidden = try typeContainer.decodeIfPresent(Bool.self, forKey: .hidden) ?? false + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) ?? Color(uiColor: .white) + transparent = try typeContainer.decodeIfPresent(Bool.self, forKey: .transparent) ?? false + tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor) ?? Color(uiColor: .black) + systemBackButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .systemBackButton) ?? false + showLeftPanelButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .showLeftPanelButton) + showRightPanelButton = try typeContainer.decodeIfPresent(Bool.self, forKey: .showRightPanelButton) + additionalLeftItems = try typeContainer.decodeIfPresent([NavigationItemButtonModel].self, forKey: .additionalLeftItems) + additionalRightItems = try typeContainer.decodeIfPresent([NavigationItemButtonModel].self, forKey: .additionalRightItems) + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(title, forKey: .title) + try container.encodeModelIfPresent(titleView, forKey: .titleView) + try container.encode(hidden, forKey: .hidden) + try container.encode(backgroundColor, forKey: .backgroundColor) + try container.encode(transparent, forKey: .transparent) + try container.encode(tintColor, forKey: .tintColor) + try container.encodeIfPresent(systemBackButton, forKey: .systemBackButton) + try container.encode(showLeftPanelButton, forKey: .showLeftPanelButton) + try container.encode(showRightPanelButton, forKey: .showRightPanelButton) + try container.encodeIfPresent(additionalLeftItems, forKey: .additionalLeftItems) + try container.encodeIfPresent(additionalRightItems, forKey: .additionalRightItems) + } } diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index ca56b4af..8cff8cd8 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -22,7 +22,8 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol // MARK: - Computed Properties //-------------------------------------------------- open override func parsePageJSON() throws { - try parseTemplateJSON() + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() } open override var loadObject: MVMCoreLoadObject? { diff --git a/MVMCoreUI/Templates/MoleculeStackTemplate.swift b/MVMCoreUI/Templates/MoleculeStackTemplate.swift index f68cfa1a..c8d807cc 100644 --- a/MVMCoreUI/Templates/MoleculeStackTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeStackTemplate.swift @@ -13,7 +13,8 @@ open class MoleculeStackTemplate: ThreeLayerViewController, TemplateProtocol { public var templateModel: StackPageTemplateModel? open override func parsePageJSON() throws { - try parseTemplateJSON() + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() } open override var loadObject: MVMCoreLoadObject? { diff --git a/MVMCoreUI/Templates/StackPageTemplateModel.swift b/MVMCoreUI/Templates/StackPageTemplateModel.swift index 28600453..2b683d98 100644 --- a/MVMCoreUI/Templates/StackPageTemplateModel.swift +++ b/MVMCoreUI/Templates/StackPageTemplateModel.swift @@ -9,55 +9,39 @@ import Foundation -@objcMembers public class StackPageTemplateModel: TemplateModelProtocol { - public var formRules: [FormGroupRule]? - public var formValidator: FormValidator? - - public static var identifier: String = "stack" - - public var pageType: String - public var screenHeading: String? - public var isAtomicTabs: Bool? - public var navigationItem: NavigationItemModelProtocol? +@objcMembers public class StackPageTemplateModel: TemplateModel { + public override class var identifier: String { + return "stack" + } public var header: MoleculeModelProtocol? public var moleculeStack: MoleculeStackModel public var footer: MoleculeModelProtocol? public init(pageType: String, moleculeStack: MoleculeStackModel) { - self.pageType = pageType self.moleculeStack = moleculeStack + super.init(pageType: pageType) } private enum CodingKeys: String, CodingKey { - case pageType - case screenHeading case header case footer case stack - case isAtomicTabs - case formRules } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - pageType = try typeContainer.decode(String.self, forKey: .pageType) moleculeStack = try typeContainer.decode(MoleculeStackModel.self, forKey: .stack) - screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) - isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) header = try typeContainer.decodeModelIfPresent(codingKey: .header) footer = try typeContainer.decodeModelIfPresent(codingKey: .footer) - formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules) + try super.init(from: decoder) } - public func encode(to encoder: Encoder) throws { + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(pageType, forKey: .pageType) try container.encode(moleculeStack, forKey: .stack) - try container.encodeIfPresent(screenHeading, forKey: .screenHeading) - try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) try container.encodeModelIfPresent(header, forKey: .header) try container.encodeModelIfPresent(footer, forKey: .footer) - try container.encodeIfPresent(formRules, forKey: .formRules) } } diff --git a/MVMCoreUI/Templates/TemplateModel.swift b/MVMCoreUI/Templates/TemplateModel.swift new file mode 100644 index 00000000..850ba80b --- /dev/null +++ b/MVMCoreUI/Templates/TemplateModel.swift @@ -0,0 +1,50 @@ +// +// TemplateModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 3/13/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class TemplateModel: TemplateModelProtocol { + public class var identifier: String { + return "" + } + public var pageType: String + public var screenHeading: String? + public var isAtomicTabs: Bool? + public var navigationItem: NavigationItemModelProtocol? + public var formRules: [FormGroupRule]? + + public init(pageType: String) { + self.pageType = pageType + } + + private enum CodingKeys: String, CodingKey { + case pageType + case screenHeading + case isAtomicTabs + case formRules + case navigationItem + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + pageType = try typeContainer.decode(String.self, forKey: .pageType) + screenHeading = try typeContainer.decodeIfPresent(String.self, forKey: .screenHeading) + isAtomicTabs = try typeContainer.decodeIfPresent(Bool.self, forKey: .isAtomicTabs) + formRules = try typeContainer.decodeIfPresent([FormGroupRule].self, forKey: .formRules) + navigationItem = try typeContainer.decodeModelIfPresent(codingKey: .navigationItem) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(pageType, forKey: .pageType) + try container.encodeIfPresent(screenHeading, forKey: .screenHeading) + try container.encodeIfPresent(isAtomicTabs, forKey: .isAtomicTabs) + try container.encodeIfPresent(formRules, forKey: .formRules) + try container.encodeModelIfPresent(navigationItem, forKey: .navigationItem) + } +} diff --git a/MVMCoreUI/Templates/TemplateProtocol.swift b/MVMCoreUI/Templates/TemplateProtocol.swift index f4717774..78b304b0 100644 --- a/MVMCoreUI/Templates/TemplateProtocol.swift +++ b/MVMCoreUI/Templates/TemplateProtocol.swift @@ -15,16 +15,16 @@ public protocol TemplateProtocol: FormHolderProtocol { } public extension TemplateProtocol where Self: ViewController { - func parseTemplateJSON() throws { - guard let pageJSON = self.loadObject?.pageJSON else { return } + func parseTemplate(json: [AnyHashable: Any]?) throws { + guard let pageJSON = json else { return } let data = try JSONSerialization.data(withJSONObject: pageJSON) let decoder = JSONDecoder() let templateModel = try decoder.decode(TemplateModel.self, from: data) - + self.templateModel = templateModel + if self.formValidator == nil { let rules = templateModel.formRules self.formValidator = FormValidator(rules) } - self.templateModel = templateModel } } diff --git a/MVMCoreUI/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Templates/ThreeLayerTemplate.swift index 0f400027..19859667 100644 --- a/MVMCoreUI/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Templates/ThreeLayerTemplate.swift @@ -15,7 +15,8 @@ import UIKit public var templateModel: ThreeLayerPageTemplateModel? open override func parsePageJSON() throws { - try parseTemplateJSON() + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() } override open func viewDidLoad() {