diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 077b0ca2..befe232c 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -190,11 +190,11 @@ AA1EC59924373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */; }; AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */; }; AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */; }; - AA85236C244435A20059CC1E /* RadioSwatchItemCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchItemCollectionViewCell.swift */; }; + AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */; }; AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C10724346F4B00151545 /* RadioSwatches.swift */; }; - AAB9C10A243496DD00151545 /* RadioSwatchItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C109243496DD00151545 /* RadioSwatchItem.swift */; }; + AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB9C109243496DD00151545 /* RadioSwatch.swift */; }; AAC6F167243332E400F295C1 /* RadioSwatchesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */; }; BB2C968F24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */; }; BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */; }; @@ -226,6 +226,7 @@ C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7F8012223E846C300396FBD /* ListRVWheelModel.swift */; }; D202AFE4242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D202AFE3242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift */; }; D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */; }; + D2092349244A51D40044AD09 /* RadioSwatchModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2092348244A51D40044AD09 /* RadioSwatchModel.swift */; }; D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; @@ -620,11 +621,11 @@ AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnSpeedTestDivider.swift; sourceTree = ""; }; AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDividerModel.swift; sourceTree = ""; }; AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDivider.swift; sourceTree = ""; }; - AA85236B244435A20059CC1E /* RadioSwatchItemCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchItemCollectionViewCell.swift; sourceTree = ""; }; + AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = ""; }; AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; AAB9C10724346F4B00151545 /* RadioSwatches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatches.swift; sourceTree = ""; }; - AAB9C109243496DD00151545 /* RadioSwatchItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchItem.swift; sourceTree = ""; }; + AAB9C109243496DD00151545 /* RadioSwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = ""; }; AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchesModel.swift; sourceTree = ""; }; BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinksModel.swift; sourceTree = ""; }; BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinks.swift; sourceTree = ""; }; @@ -656,6 +657,7 @@ C7F8012223E846C300396FBD /* ListRVWheelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRVWheelModel.swift; sourceTree = ""; }; D202AFE3242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextAlignment+Extension.swift"; sourceTree = ""; }; D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewScrollPosition+Extension.swift"; sourceTree = ""; }; + D2092348244A51D40044AD09 /* RadioSwatchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchModel.swift; sourceTree = ""; }; D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -1439,8 +1441,9 @@ 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */, AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */, AAB9C10724346F4B00151545 /* RadioSwatches.swift */, - AAB9C109243496DD00151545 /* RadioSwatchItem.swift */, - AA85236B244435A20059CC1E /* RadioSwatchItemCollectionViewCell.swift */, + D2092348244A51D40044AD09 /* RadioSwatchModel.swift */, + AAB9C109243496DD00151545 /* RadioSwatch.swift */, + AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */, ); path = Selectors; sourceTree = ""; @@ -2114,7 +2117,7 @@ 012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */, BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */, D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */, - AAB9C10A243496DD00151545 /* RadioSwatchItem.swift in Sources */, + AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, 011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */, D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */, @@ -2219,6 +2222,7 @@ D260105D23D0BCD400764D80 /* Stack.swift in Sources */, 0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */, BB54C5212434D92F0038326C /* ListRightVariableButtonAllTextAndLinksModel.swift in Sources */, + D2092349244A51D40044AD09 /* RadioSwatchModel.swift in Sources */, 8DD1E370243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */, @@ -2333,7 +2337,7 @@ 0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */, AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */, D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */, - AA85236C244435A20059CC1E /* RadioSwatchItemCollectionViewCell.swift in Sources */, + AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */, 52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */, D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */, 0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchItem.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift similarity index 77% rename from MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchItem.swift rename to MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift index a6e6b802..35294457 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchItem.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift @@ -1,5 +1,5 @@ // -// RadioSwatchItem.swift +// RadioSwatch.swift // MVMCoreUI // // Created by Lekshmi S on 01/04/20. @@ -9,21 +9,19 @@ import Foundation import UIKit -open class RadioSwatchItem: Control { +open class RadioSwatch: Control { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- public let bottomText = Label.createLabelRegularMicro(true) - public var isOutOfStock = false - public var fillColor: Color = Color(uiColor: .mvmBlue) private var circleLayer: CAShapeLayer? private var selectedLayer: CALayer? private var strikeLayer: CALayer? private var maskLayer: CALayer? - public var radioSwatchModel: RadioSwatchItemModel? { - return model as? RadioSwatchItemModel + public var radioSwatchModel: RadioSwatchModel? { + return model as? RadioSwatchModel } //-------------------------------------------------- @@ -40,18 +38,23 @@ open class RadioSwatchItem: Control { addSubview(bottomText) bottomText.textAlignment = .center - NSLayoutConstraint.constraintPinSubview(bottomText, pinTop: true, topConstant: 38, pinBottom: false, bottomConstant: 0, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0) + NSLayoutConstraint.constraintPinSubview(bottomText, pinTop: true, topConstant: 38, pinBottom: true, bottomConstant: 0, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0) addTarget(self, action: #selector(selectSwatch), for: .touchUpInside) } open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) - guard let model = model as? RadioSwatchItemModel else { return } - fillColor = model.color - isSelected = model.selected ?? false - isEnabled = model.enabled ?? true + guard let model = model as? RadioSwatchModel else { return } + isSelected = model.selected + isEnabled = model.enabled bottomText.text = model.text - isOutOfStock = model.strikethrough ?? false + } + + public override func reset() { + super.reset() + isSelected = false + isEnabled = true + bottomText.text = nil } //------------------------------------------------------ @@ -60,14 +63,14 @@ open class RadioSwatchItem: Control { open override func draw(_ layer: CALayer, in ctx: CGContext) { //Draw the swatch circleLayer?.removeFromSuperlayer() - let circle = getCircle(color: .mvmBlack, thickness: 1) + let circle = getCircle(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1) layer.addSublayer(circle) circleLayer = circle //Draw the strikethrough strikeLayer?.removeFromSuperlayer() - if isOutOfStock { - let line = getStrikeThrough(color: .mvmBlack, thickness: 1) + if radioSwatchModel?.strikethrough ?? false { + let line = getStrikeThrough(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1) layer.addSublayer(line) strikeLayer = line } @@ -75,12 +78,11 @@ open class RadioSwatchItem: Control { //Draw the selected layer selectedLayer?.removeFromSuperlayer() if isSelected { - let outerCircle = getSelectedLayer(color: .mvmBlack, thickness: 1) + let outerCircle = getSelectedLayer(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1) layer.addSublayer(outerCircle) selectedLayer = outerCircle bottomText.isHidden = false } else { - circleLayer?.path = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30)).cgPath bottomText.isHidden = true } @@ -115,10 +117,10 @@ open class RadioSwatchItem: Control { func getCircle(color: UIColor, thickness: CGFloat) -> CAShapeLayer { let circle = CAShapeLayer() circle.name = "innercircle" - circle.fillColor = fillColor.cgColor + circle.fillColor = radioSwatchModel?.color.cgColor ?? UIColor.blue.cgColor circle.opacity = 1.0 circle.lineWidth = thickness - circle.strokeColor = isSelected ? color.cgColor : UIColor.mvmCoolGray6.cgColor + circle.strokeColor = color.cgColor let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30)) circle.path = circlePath.cgPath @@ -131,11 +133,11 @@ open class RadioSwatchItem: Control { strikeThrough.fillColor = nil strikeThrough.opacity = 1.0 strikeThrough.lineWidth = thickness - strikeThrough.strokeColor = isSelected ? color.cgColor : UIColor.mvmCoolGray6.cgColor + strikeThrough.strokeColor = color.cgColor let linePath = UIBezierPath() - linePath.move(to: CGPoint(x: 12, y: 30)) - linePath.addLine(to: CGPoint(x: 42, y: 0)) + linePath.move(to: CGPoint(x: 12, y: 31)) + linePath.addLine(to: CGPoint(x: 42, y: 1)) strikeThrough.path = linePath.cgPath return strikeThrough } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchItemCollectionViewCell.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchCollectionViewCell.swift similarity index 71% rename from MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchItemCollectionViewCell.swift rename to MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchCollectionViewCell.swift index a820a680..8412dab2 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchItemCollectionViewCell.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchCollectionViewCell.swift @@ -1,5 +1,5 @@ // -// RadioSwatchItemCollectionViewCell.swift +// RadioSwatchCollectionViewCell.swift // MVMCoreUI // // Created by Lekshmi S on 13/04/20. @@ -7,8 +7,8 @@ // import Foundation -open class RadioSwatchItemCollectionViewCell: CollectionViewCell { - public let radioSwatch = RadioSwatchItem() +open class RadioSwatchCollectionViewCell: CollectionViewCell { + public let radioSwatch = RadioSwatch() open override func setupView() { super.setupView() @@ -17,7 +17,7 @@ open class RadioSwatchItemCollectionViewCell: CollectionViewCell { } open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - guard let model = model as? RadioSwatchItemModel else { return } + guard let model = model as? RadioSwatchModel else { return } radioSwatch.set(with: model, delegateObject, additionalData) } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift new file mode 100644 index 00000000..3aadd467 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift @@ -0,0 +1,64 @@ +// +// RadioSwatchModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/17/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class RadioSwatchModel: MoleculeModelProtocol { + public static var identifier: String = "radioSwatch" + public var backgroundColor: Color? + public var color: Color = Color(uiColor: .mvmBlue) + public var text: String? + public var selected: Bool = false + public var enabled: Bool = true + public var strikethrough: Bool = false + public var fieldValue: String? + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case color + case text + case selected + case enabled + case strikethrough + case fieldValue + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + if let color = try typeContainer.decodeIfPresent(Color.self, forKey: .color) { + self.color = color + } + text = try typeContainer.decodeIfPresent(String.self, forKey: .text) + if let selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) { + self.selected = selected + } + if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { + self.enabled = enabled + } + if let strikethrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) { + self.strikethrough = strikethrough + } + fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encode(color, forKey: .color) + try container.encodeIfPresent(text, forKey: .text) + try container.encode(selected, forKey: .selected) + try container.encode(enabled, forKey: .enabled) + try container.encode(strikethrough, forKey: .strikethrough) + try container.encodeIfPresent(fieldValue, forKey: .fieldValue) + } +} + + diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatches.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatches.swift index f13dd331..8a6b8faf 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatches.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatches.swift @@ -13,7 +13,7 @@ open class RadioSwatches: View { // MARK: - Properties //-------------------------------------------------- public var collectionView: CollectionView! - public var swatches: [RadioSwatchItemModel]? + public var swatches: [RadioSwatchModel]? private var size: CGFloat? private var delegateObject: MVMCoreUIDelegateObject? @@ -30,6 +30,7 @@ open class RadioSwatches: View { open override func layoutSubviews() { super.layoutSubviews() // Accounts for any collection size changes + setHeight() DispatchQueue.main.async { self.collectionView.collectionViewLayout.invalidateLayout() } @@ -57,24 +58,18 @@ open class RadioSwatches: View { guard let radioSwatchesModel = model as? RadioSwatchesModel else { return } swatches = radioSwatchesModel.swatches FormValidator.setupValidation(for: radioSwatchesModel, delegate: delegateObject?.formHolderDelegate) - registerCells() - setHeight() collectionView.reloadData() } //------------------------------------------------------ // MARK: - Methods //------------------------------------------------------ - /// Registers the cells with the collection view - open func registerCells() { - collectionView.register(RadioSwatchItemCollectionViewCell.self, forCellWithReuseIdentifier: "RadioSwatchItemCollectionViewCell") - } - /// Creates the collection view. open func createCollectionView() -> CollectionView { let collection = CollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout()) collection.dataSource = self collection.delegate = self + collection.register(RadioSwatchCollectionViewCell.self, forCellWithReuseIdentifier: "RadioSwatchCollectionViewCell") return collection } @@ -93,10 +88,17 @@ open class RadioSwatches: View { return } // Calculate the height - let collectionViewWidth = UIScreen.main.bounds.width - (2 * MFStyler.defaultHorizontalPaddingForApplicationWidth()) - let swatchesInRow = floor(CGFloat(collectionViewWidth/(cellSize + itemSpacing))) + let swatchesInRow = floor(CGFloat(collectionView.bounds.width/(cellSize + itemSpacing))) let numberOfRows = ceil(CGFloat(swatches.count)/swatchesInRow) let height = (numberOfRows * cellSize) + (itemSpacing * (numberOfRows-1)) + + if let oldHeight = collectionViewHeight?.constant, + height != oldHeight { + // Notify delegate of height change, called async to avoid various race conditions caused while happening while laying out initially. + DispatchQueue.main.async { + self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self) + } + } collectionViewHeight?.constant = CGFloat(height) } } @@ -116,13 +118,14 @@ extension RadioSwatches: UICollectionViewDataSource { } open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let molecule = swatches?[indexPath.row], let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioSwatchItemCollectionViewCell", for: indexPath) as? RadioSwatchItemCollectionViewCell else { + guard let molecule = swatches?[indexPath.row], let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "RadioSwatchCollectionViewCell", for: indexPath) as? RadioSwatchCollectionViewCell else { fatalError() } + cell.reset() cell.radioSwatch.isUserInteractionEnabled = false cell.set(with: molecule, delegateObject, nil) cell.updateView(size ?? collectionView.bounds.width) - if molecule.selected ?? false { + if molecule.selected { collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically) } cell.layoutIfNeeded() @@ -132,17 +135,18 @@ extension RadioSwatches: UICollectionViewDataSource { extension RadioSwatches: UICollectionViewDelegate { open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool { - guard let molecule = swatches?[indexPath.row] else {return true } - return molecule.enabled ?? true + guard let molecule = swatches?[indexPath.row] else { return false } + return molecule.enabled } open func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchItemCollectionViewCell else { return } + guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return } cell.radioSwatch.selectSwatch() _ = FormValidator.validate(delegate: delegateObject?.formHolderDelegate) } + open func collectionView(_ collectionView: UICollectionView, didDeselectItemAt indexPath: IndexPath) { - guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchItemCollectionViewCell else { return } + guard let cell = collectionView.cellForItem(at: indexPath) as? RadioSwatchCollectionViewCell else { return } cell.radioSwatch.deselectSwatch() } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift index d422d0db..db8e5d5d 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift @@ -9,9 +9,9 @@ import Foundation @objcMembers public class RadioSwatchesModel: MoleculeModelProtocol, FormFieldProtocol { - public var backgroundColor: Color? public static var identifier: String = "radioSwatches" - public var swatches: [RadioSwatchItemModel] + public var backgroundColor: Color? + public var swatches: [RadioSwatchModel] public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName public var baseValue: AnyHashable? @@ -19,7 +19,7 @@ import Foundation /// Returns the fieldValue of the selected swatch, otherwise the text of selected swatch. public func formFieldValue() -> AnyHashable? { let selectedSwatch = swatches.first { (swatch) -> Bool in - return (swatch.selected ?? false) + return swatch.selected } return selectedSwatch?.fieldValue ?? selectedSwatch?.text } @@ -34,8 +34,8 @@ import Foundation required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - self.swatches = try typeContainer.decode([RadioSwatchItemModel].self, forKey: .swatches) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + swatches = try typeContainer.decode([RadioSwatchModel].self, forKey: .swatches) fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey) if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) { self.groupName = groupName @@ -49,61 +49,6 @@ import Foundation try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encode(swatches, forKey: .swatches) try container.encodeIfPresent(fieldKey, forKey: .fieldKey) - try container.encodeIfPresent(groupName, forKey: .groupName) + try container.encode(groupName, forKey: .groupName) } } - -@objcMembers public class RadioSwatchItemModel: MoleculeModelProtocol { - public var backgroundColor: Color? - public static var identifier: String = "radioSwatchItem" - public var color: Color = Color(uiColor: .mvmBlue) - public var text: String? - public var selected: Bool? = false - public var enabled: Bool? = true - public var strikethrough: Bool? = false - public var fieldValue: String? - - private enum CodingKeys: String, CodingKey { - case moleculeName - case backgroundColor - case color - case text - case selected - case enabled - case strikethrough - case fieldValue - } - - required public init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - color = try typeContainer.decode(Color.self, forKey: .color) - if let text = try typeContainer.decodeIfPresent(String.self, forKey: .text) { - self.text = text - } - if let selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected) { - self.selected = selected - } - if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) { - self.enabled = enabled - } - if let strikethrough = try typeContainer.decodeIfPresent(Bool.self, forKey: .strikethrough) { - self.strikethrough = strikethrough - } - fieldValue = try typeContainer.decodeIfPresent(String.self, forKey: .fieldValue) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) - try container.encode(color, forKey: .color) - try container.encodeIfPresent(text, forKey: .text) - try container.encodeIfPresent(selected, forKey: .selected) - try container.encodeIfPresent(enabled, forKey: .enabled) - try container.encodeIfPresent(strikethrough, forKey: .strikethrough) - try container.encodeIfPresent(fieldValue, forKey: .fieldValue) - } -} - -