diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index c9833c3f..15f22974 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -121,6 +121,8 @@ 0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */; }; 0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB423FF18D2004C5109 /* Arrow.swift */; }; 0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */; }; + 1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */; }; + 1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1D6D258726899B0B00DEBB08 /* ImageButton.swift */; }; 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */; }; 27F6B08826051831008529AA /* MoleculeTreeTraversalProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */; }; 27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */; }; @@ -684,6 +686,8 @@ 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalLinkModel.swift; sourceTree = ""; }; 0AE98BB423FF18D2004C5109 /* Arrow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Arrow.swift; sourceTree = ""; }; 0AE98BB623FF18E9004C5109 /* ArrowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArrowModel.swift; sourceTree = ""; }; + 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButtonModel.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift; sourceTree = SOURCE_ROOT; }; + 1D6D258726899B0B00DEBB08 /* ImageButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageButton.swift; path = MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift; sourceTree = SOURCE_ROOT; }; 279B1568242BBC2F00921D6C /* ActionModelAdapter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActionModelAdapter.swift; sourceTree = ""; }; 27F6B08726051831008529AA /* MoleculeTreeTraversalProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeTreeTraversalProtocol.swift; sourceTree = ""; }; 27F6B08B26052AFF008529AA /* ParentMoleculeModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ParentMoleculeModelProtocol.swift; sourceTree = ""; }; @@ -1289,6 +1293,8 @@ 0AE98BAD23FEF92B004C5109 /* Link */ = { isa = PBXGroup; children = ( + 1D6D258726899B0B00DEBB08 /* ImageButton.swift */, + 1D6D258626899B0B00DEBB08 /* ImageButtonModel.swift */, D28A838823CCCFCB00DFE4FC /* LinkModel.swift */, C07065C32395677300FBF997 /* Link.swift */, 0AE98BB223FF0934004C5109 /* ExternalLinkModel.swift */, @@ -2884,6 +2890,7 @@ D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */, AA617AB02453010A00910B8F /* ListDeviceComplexLinkSmall.swift in Sources */, D23A8FD9260CE004007E14CE /* MFStyler+PaddingExtension.swift in Sources */, + 1D6D258926899B0C00DEBB08 /* ImageButton.swift in Sources */, C695A68123C9830D00BFB94E /* NumberedListModel.swift in Sources */, 01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */, D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */, @@ -2928,6 +2935,7 @@ BB2BF0EC2452A9D5001D0FC2 /* ListDeviceComplexButtonSmallModel.swift in Sources */, 943784F6236B77BB006A1E82 /* WheelAnimationHandler.swift in Sources */, 011D95A1240453D0000E3791 /* RuleEqualsModel.swift in Sources */, + 1D6D258826899B0C00DEBB08 /* ImageButtonModel.swift in Sources */, AA07EA912510A442009A2AE3 /* StarModel.swift in Sources */, D29DF2AA21E7B2F9003B2FB9 /* MVMCoreUIConstants.m in Sources */, 011D95892404249B000E3791 /* FormHolderModelProtocol.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift new file mode 100644 index 00000000..2d71ee6e --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Buttons/ImageButton.swift @@ -0,0 +1,54 @@ +// +// ImageButton.swift +// MobileFirstFramework +// +// Created by Chintakrinda, Arun Kumar (Arun) on 07/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ImageButton: Button { + + public let image = LoadImageView(pinnedEdges: .all) + + open override func setupView() { + super.setupView() + insertSubview(image, at: 0) + image.isUserInteractionEnabled = false + NSLayoutConstraint.constraintPinSubview(toSuperview: image) + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let castModel = model as? ImageButtonModel else { + super.set(with: model, delegateObject, additionalData) + return + } + image.setOptional(with: castModel.image, delegateObject, additionalData) + castModel.updateUI = { [weak self] in + MVMCoreDispatchUtility.performBlock(onMainThread: { + self?.setState() + }) + } + + super.set(with: model, delegateObject, additionalData) + FormValidator.setupValidation(for: castModel, delegate: delegateObject?.formHolderDelegate) + + } + + private func setState() { + guard let castModel = model as? ImageButtonModel else { + return + } + if castModel.enabled { + if let enabledTintColor = castModel.enabledTintColor { + image.imageView.tintColor = enabledTintColor.uiColor + } + } else if let disabledTintColor = castModel.disabledTintColor { + image.imageView.tintColor = disabledTintColor.uiColor + } + } + + + +} diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift new file mode 100644 index 00000000..d8217d0d --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Buttons/ImageButtonModel.swift @@ -0,0 +1,95 @@ +// +// ImageButtonModel.swift +// MobileFirstFramework +// +// Created by Chintakrinda, Arun Kumar (Arun) on 07/10/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ImageButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol, EnableableModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "imageButton" + public var backgroundColor: Color? + + public var image: ImageViewModel? + + public var accessibilityText: String? + public var action: ActionModelProtocol + public var enabled: Bool = true + public var enabledTintColor: Color? + public var disabledTintColor: Color? + + public var groupName: String = "" + + public func setValidity(_ valid: Bool, group: FormGroupRule) { + enabled = valid + updateUI?() + } + + public var updateUI: ActionBlock? + + public init(image: ImageViewModel?, action: ActionModelProtocol) { + self.image = image + self.action = action + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case image + case backgroundColor + case accessibilityText + case action + case enabled + case groupName + case enabledTintColor + case disabledTintColor + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + image = try typeContainer.decodeIfPresent(ImageViewModel.self, forKey: .image) + accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) + action = try typeContainer.decodeModel(codingKey: .action) + + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { + self.enabled = enabled + } + + if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { + self.groupName = groupName + } + + if let enabledTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .enabledTintColor) { + self.enabledTintColor = enabledTintColor + } + + if let disabledTintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTintColor) { + self.disabledTintColor = disabledTintColor + } + + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(image, forKey: .image) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) + try container.encode(enabled, forKey: .enabled) + try container.encodeModel(action, forKey: .action) + try container.encodeIfPresent(groupName, forKey: .groupName) + try container.encodeIfPresent(enabledTintColor, forKey: .enabledTintColor) + try container.encodeIfPresent(disabledTintColor, forKey: .disabledTintColor) + } +} diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxes.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxes.swift index e8f940a2..c0f001e7 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxes.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioBoxes.swift @@ -8,6 +8,10 @@ import Foundation +public protocol RadioBoxSelectionDelegate: class { + func selected(radioBox: RadioBoxModel) +} + open class RadioBoxes: View { public var collectionView: CollectionView! @@ -19,14 +23,14 @@ open class RadioBoxes: View { private var radioBoxesModel: RadioBoxesModel? { return model as? RadioBoxesModel } - + public weak var radioDelegate: RadioBoxSelectionDelegate? private var delegateObject: MVMCoreUIDelegateObject? /// The models for the molecules. public var boxes: [RadioBoxModel]? - + private var size: CGFloat? - + open override func layoutSubviews() { super.layoutSubviews() // Accounts for any collection size changes @@ -37,7 +41,7 @@ open class RadioBoxes: View { open func updateAccessibilityValue(collectionView: UICollectionView, cell: RadioBoxCollectionViewCell, indexPath: IndexPath) { guard let format = MVMCoreUIUtility.hardcodedString(withKey: "index_string_of_total"), - let indexString = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: indexPath.row + 1)) else { return } + let indexString = MVMCoreUIUtility.getOrdinalString(forIndex: NSNumber(value: indexPath.row + 1)) else { return } let total = self.collectionView(collectionView, numberOfItemsInSection: indexPath.section) cell.accessibilityValue = String(format: format, indexString, total) } @@ -60,7 +64,7 @@ open class RadioBoxes: View { guard let model = model as? RadioBoxesModel else { return } boxes = model.boxes FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate) - + backgroundColor = model.backgroundColor?.uiColor registerCells() @@ -85,7 +89,7 @@ open class RadioBoxes: View { layout.minimumInteritemSpacing = itemSpacing return layout } - + /// Creates the collection view. open func createCollectionView() -> CollectionView { let collection = CollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout()) @@ -98,7 +102,7 @@ open class RadioBoxes: View { open func registerCells() { collectionView.register(RadioBoxCollectionViewCell.self, forCellWithReuseIdentifier: "RadioBoxCollectionViewCell") } - + // MARK: - JSON Setters open func setHeight() { guard let boxes = boxes, boxes.count > 0 else { @@ -127,7 +131,7 @@ extension RadioBoxes: UICollectionViewDataSource { open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let molecule = boxes?[indexPath.row], - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioBoxCollectionViewCell", for: indexPath) as? RadioBoxCollectionViewCell else { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioBoxCollectionViewCell", for: indexPath) as? RadioBoxCollectionViewCell else { fatalError() } cell.reset() @@ -162,6 +166,8 @@ extension RadioBoxes: UICollectionViewDelegate { cell.radioBox.selectBox() _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) cell.updateAccessibility() + guard let radioBox = boxes?[indexPath.row] else { return } + radioDelegate?.selected(radioBox: radioBox) } open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) { diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift index f3ce24e5..804075ff 100644 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift +++ b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/Tabs.swift @@ -13,7 +13,8 @@ import UIKit func didSelectItem(_ indexPath: IndexPath, tabs: Tabs) } -@objcMembers open class Tabs: View, MVMCoreUIViewConstrainingProtocol { +@objcMembers open class Tabs: View, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol { + public var tabsModel: TabsModel? { get { return model as? TabsModel } diff --git a/MVMCoreUI/Atomic/Templates/TemplateModel.swift b/MVMCoreUI/Atomic/Templates/TemplateModel.swift index 4f565e85..45c2ed1a 100644 --- a/MVMCoreUI/Atomic/Templates/TemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/TemplateModel.swift @@ -13,8 +13,7 @@ import Foundation //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - - public class var identifier: String { "" } + open class var identifier: String { "" } public var pageType: String public var template: String { @@ -74,7 +73,7 @@ import Foundation tabBarIndex = try typeContainer.decodeIfPresent(Int.self, forKey: .tabBarIndex) } - public func encode(to encoder: Encoder) throws { + open func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(pageType, forKey: .pageType) try container.encode(template, forKey: .template) diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index f45d3aac..d4eb516e 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -86,6 +86,7 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(handler: HeadlineBodyButton.self, for: HeadlineBodyButtonModel.self) ModelRegistry.register(handler: BGImageHeadlineBodyButton.self, for: BGImageHeadlineBodyButtonModel.self) ModelRegistry.register(handler: ThreeHeadlineBodyLink.self, for: ThreeHeadlineBodyLinkModel.self) + ModelRegistry.register(handler: ImageButton.self, for: ImageButtonModel.self) // MARK:- Left Right Molecules ModelRegistry.register(handler: CornerLabels.self, for: CornerLabelsModel.self)