Merge branch 'feature/radio_swatches' into 'develop'
Feature/radio swatches See merge request BPHV_MIPS/mvm_core_ui!360
This commit is contained in:
commit
fddc676af9
@ -190,8 +190,12 @@
|
||||
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 /* 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 /* 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 */; };
|
||||
BB47A586241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */; };
|
||||
@ -222,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 */; };
|
||||
@ -616,8 +621,12 @@
|
||||
AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnSpeedTestDivider.swift; sourceTree = "<group>"; };
|
||||
AA56A20E243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDividerModel.swift; sourceTree = "<group>"; };
|
||||
AA56A210243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTwoColumnSubsectionDivider.swift; sourceTree = "<group>"; };
|
||||
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchCollectionViewCell.swift; sourceTree = "<group>"; };
|
||||
AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = "<group>"; };
|
||||
AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = "<group>"; };
|
||||
AAB9C10724346F4B00151545 /* RadioSwatches.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatches.swift; sourceTree = "<group>"; };
|
||||
AAB9C109243496DD00151545 /* RadioSwatch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatch.swift; sourceTree = "<group>"; };
|
||||
AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchesModel.swift; sourceTree = "<group>"; };
|
||||
BB2C968D24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinksModel.swift; sourceTree = "<group>"; };
|
||||
BB2C969124330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ListRightVariableTextLinkAllTextAndLinks.swift; sourceTree = "<group>"; };
|
||||
BB47A585241615EF002BB23C /* ListOneColumnFullWidthTextDividerSubsectionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextDividerSubsectionModel.swift; sourceTree = "<group>"; };
|
||||
@ -648,6 +657,7 @@
|
||||
C7F8012223E846C300396FBD /* ListRVWheelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRVWheelModel.swift; sourceTree = "<group>"; };
|
||||
D202AFE3242A5F5E00E5BEDF /* NSTextAlignment+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSTextAlignment+Extension.swift"; sourceTree = "<group>"; };
|
||||
D202AFE5242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UICollectionViewScrollPosition+Extension.swift"; sourceTree = "<group>"; };
|
||||
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioSwatchModel.swift; sourceTree = "<group>"; };
|
||||
D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = "<group>"; };
|
||||
D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = "<group>"; };
|
||||
D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||
@ -1429,6 +1439,11 @@
|
||||
01004F2F22721C3800991ECC /* RadioButton.swift */,
|
||||
31BE15CA23D8924C00452370 /* CheckboxModel.swift */,
|
||||
0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */,
|
||||
AAC6F166243332E400F295C1 /* RadioSwatchesModel.swift */,
|
||||
AAB9C10724346F4B00151545 /* RadioSwatches.swift */,
|
||||
D2092348244A51D40044AD09 /* RadioSwatchModel.swift */,
|
||||
AAB9C109243496DD00151545 /* RadioSwatch.swift */,
|
||||
AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */,
|
||||
);
|
||||
path = Selectors;
|
||||
sourceTree = "<group>";
|
||||
@ -2040,6 +2055,7 @@
|
||||
isa = PBXSourcesBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
AAC6F167243332E400F295C1 /* RadioSwatchesModel.swift in Sources */,
|
||||
5248BFED23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift in Sources */,
|
||||
0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */,
|
||||
8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */,
|
||||
@ -2056,6 +2072,7 @@
|
||||
D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */,
|
||||
D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */,
|
||||
AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */,
|
||||
AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */,
|
||||
94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */,
|
||||
DBC4391922442197001AB423 /* DashLine.swift in Sources */,
|
||||
D264FAAA2440F97600D98315 /* CollectionView.swift in Sources */,
|
||||
@ -2100,6 +2117,7 @@
|
||||
012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */,
|
||||
BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */,
|
||||
D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */,
|
||||
AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */,
|
||||
D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */,
|
||||
011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */,
|
||||
D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */,
|
||||
@ -2204,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 */,
|
||||
@ -2318,6 +2337,7 @@
|
||||
0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */,
|
||||
AA56A211243C5EFC00303286 /* ListTwoColumnSubsectionDivider.swift in Sources */,
|
||||
D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */,
|
||||
AA85236C244435A20059CC1E /* RadioSwatchCollectionViewCell.swift in Sources */,
|
||||
52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */,
|
||||
D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */,
|
||||
0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */,
|
||||
|
||||
166
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift
Normal file
166
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatch.swift
Normal file
@ -0,0 +1,166 @@
|
||||
//
|
||||
// RadioSwatch.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 01/04/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
|
||||
open class RadioSwatch: Control {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
public let bottomText = Label.createLabelRegularMicro(true)
|
||||
|
||||
private var circleLayer: CAShapeLayer?
|
||||
private var selectedLayer: CALayer?
|
||||
private var strikeLayer: CALayer?
|
||||
private var maskLayer: CALayer?
|
||||
|
||||
public var radioSwatchModel: RadioSwatchModel? {
|
||||
return model as? RadioSwatchModel
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
bottomText.updateView(size)
|
||||
layer.setNeedsDisplay()
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
addSubview(bottomText)
|
||||
bottomText.textAlignment = .center
|
||||
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? RadioSwatchModel else { return }
|
||||
isSelected = model.selected
|
||||
isEnabled = model.enabled
|
||||
bottomText.text = model.text
|
||||
}
|
||||
|
||||
public override func reset() {
|
||||
super.reset()
|
||||
isSelected = false
|
||||
isEnabled = true
|
||||
bottomText.text = nil
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - State Handling
|
||||
//------------------------------------------------------
|
||||
open override func draw(_ layer: CALayer, in ctx: CGContext) {
|
||||
//Draw the swatch
|
||||
circleLayer?.removeFromSuperlayer()
|
||||
let circle = getCircle(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
|
||||
layer.addSublayer(circle)
|
||||
circleLayer = circle
|
||||
|
||||
//Draw the strikethrough
|
||||
strikeLayer?.removeFromSuperlayer()
|
||||
if radioSwatchModel?.strikethrough ?? false {
|
||||
let line = getStrikeThrough(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
|
||||
layer.addSublayer(line)
|
||||
strikeLayer = line
|
||||
}
|
||||
|
||||
//Draw the selected layer
|
||||
selectedLayer?.removeFromSuperlayer()
|
||||
if isSelected {
|
||||
let outerCircle = getSelectedLayer(color: isSelected ? .mvmBlack : .mvmCoolGray6, thickness: 1)
|
||||
layer.addSublayer(outerCircle)
|
||||
selectedLayer = outerCircle
|
||||
bottomText.isHidden = false
|
||||
} else {
|
||||
bottomText.isHidden = true
|
||||
}
|
||||
|
||||
//Handle Mask
|
||||
maskLayer?.removeFromSuperlayer()
|
||||
if !isEnabled {
|
||||
let mask = getMaskLayer()
|
||||
layer.mask = mask
|
||||
maskLayer = mask
|
||||
}
|
||||
}
|
||||
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
// Accounts for any size changes
|
||||
layer.setNeedsDisplay()
|
||||
}
|
||||
|
||||
@objc open func selectSwatch() {
|
||||
guard isEnabled else { return }
|
||||
isSelected = true
|
||||
radioSwatchModel?.selected = isSelected
|
||||
layer.setNeedsDisplay()
|
||||
}
|
||||
|
||||
@objc open func deselectSwatch() {
|
||||
isSelected = false
|
||||
radioSwatchModel?.selected = isSelected
|
||||
layer.setNeedsDisplay()
|
||||
}
|
||||
|
||||
func getCircle(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
|
||||
let circle = CAShapeLayer()
|
||||
circle.name = "innercircle"
|
||||
circle.fillColor = radioSwatchModel?.color.cgColor ?? UIColor.blue.cgColor
|
||||
circle.opacity = 1.0
|
||||
circle.lineWidth = thickness
|
||||
circle.strokeColor = color.cgColor
|
||||
|
||||
let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30))
|
||||
circle.path = circlePath.cgPath
|
||||
return circle
|
||||
}
|
||||
|
||||
func getStrikeThrough(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
|
||||
let strikeThrough = CAShapeLayer()
|
||||
strikeThrough.name = "strikethrough"
|
||||
strikeThrough.fillColor = nil
|
||||
strikeThrough.opacity = 1.0
|
||||
strikeThrough.lineWidth = thickness
|
||||
strikeThrough.strokeColor = color.cgColor
|
||||
|
||||
let linePath = UIBezierPath()
|
||||
linePath.move(to: CGPoint(x: 12, y: 31))
|
||||
linePath.addLine(to: CGPoint(x: 42, y: 1))
|
||||
strikeThrough.path = linePath.cgPath
|
||||
return strikeThrough
|
||||
}
|
||||
|
||||
func getSelectedLayer(color: UIColor, thickness: CGFloat) -> CAShapeLayer {
|
||||
circleLayer?.path = UIBezierPath(ovalIn: CGRect(x: 15, y: 4, width: 24, height: 24)).cgPath
|
||||
let circle = CAShapeLayer()
|
||||
circle.name = "outercircle"
|
||||
circle.fillColor = UIColor.clear.cgColor
|
||||
circle.opacity = 1.0
|
||||
circle.lineWidth = thickness
|
||||
circle.strokeColor = color.cgColor
|
||||
|
||||
let circlePath = UIBezierPath(ovalIn: CGRect(x: 12, y: 1, width: 30, height: 30))
|
||||
circle.path = circlePath.cgPath
|
||||
return circle
|
||||
}
|
||||
|
||||
func getMaskLayer() -> CALayer {
|
||||
let mask = CALayer()
|
||||
mask.backgroundColor = UIColor.white.cgColor
|
||||
mask.opacity = 0.3
|
||||
mask.frame = bounds
|
||||
return mask
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
//
|
||||
// RadioSwatchCollectionViewCell.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 13/04/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
open class RadioSwatchCollectionViewCell: CollectionViewCell {
|
||||
public let radioSwatch = RadioSwatch()
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
addMolecule(radioSwatch)
|
||||
MVMCoreUIUtility.setMarginsFor(contentView, leading: 0, top: 0, trailing: 0, bottom: 0)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let model = model as? RadioSwatchModel else { return }
|
||||
radioSwatch.set(with: model, delegateObject, additionalData)
|
||||
}
|
||||
}
|
||||
64
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift
Normal file
64
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchModel.swift
Normal file
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
152
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatches.swift
Normal file
152
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatches.swift
Normal file
@ -0,0 +1,152 @@
|
||||
//
|
||||
// RadioSwatches.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 01/04/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
open class RadioSwatches: View {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
public var collectionView: CollectionView!
|
||||
public var swatches: [RadioSwatchModel]?
|
||||
private var size: CGFloat?
|
||||
private var delegateObject: MVMCoreUIDelegateObject?
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//------------------------------------------------------
|
||||
public var collectionViewHeight: NSLayoutConstraint?
|
||||
private let cellSize: CGFloat = 54.0
|
||||
private let itemSpacing: CGFloat = 8.0
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
// Accounts for any collection size changes
|
||||
setHeight()
|
||||
DispatchQueue.main.async {
|
||||
self.collectionView.collectionViewLayout.invalidateLayout()
|
||||
}
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
collectionView = createCollectionView()
|
||||
addSubview(collectionView)
|
||||
NSLayoutConstraint.constraintPinSubview(toSuperview: collectionView)
|
||||
collectionViewHeight = collectionView.heightAnchor.constraint(equalToConstant: 100)
|
||||
collectionViewHeight?.isActive = true
|
||||
}
|
||||
|
||||
@objc override open func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
self.size = size
|
||||
collectionView.updateView(size)
|
||||
}
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
self.delegateObject = delegateObject
|
||||
|
||||
guard let radioSwatchesModel = model as? RadioSwatchesModel else { return }
|
||||
swatches = radioSwatchesModel.swatches
|
||||
FormValidator.setupValidation(for: radioSwatchesModel, delegate: delegateObject?.formHolderDelegate)
|
||||
collectionView.reloadData()
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//------------------------------------------------------
|
||||
/// 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
|
||||
}
|
||||
|
||||
/// Creates the layout for the collection.
|
||||
open func createCollectionViewLayout() -> UICollectionViewLayout {
|
||||
let layout = UICollectionViewFlowLayout()
|
||||
layout.scrollDirection = .vertical
|
||||
layout.minimumLineSpacing = itemSpacing
|
||||
layout.minimumInteritemSpacing = itemSpacing
|
||||
return layout
|
||||
}
|
||||
|
||||
open func setHeight() {
|
||||
guard let swatches = swatches, swatches.count > 0 else {
|
||||
collectionViewHeight?.constant = 0
|
||||
return
|
||||
}
|
||||
// Calculate the height
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------
|
||||
// MARK: - Delegate methods
|
||||
//------------------------------------------------------
|
||||
extension RadioSwatches: UICollectionViewDelegateFlowLayout {
|
||||
open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
|
||||
return CGSize(width: cellSize, height: cellSize)
|
||||
}
|
||||
}
|
||||
|
||||
extension RadioSwatches: UICollectionViewDataSource {
|
||||
open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
|
||||
return swatches?.count ?? 0
|
||||
}
|
||||
|
||||
open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||
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 {
|
||||
collectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredVertically)
|
||||
}
|
||||
cell.layoutIfNeeded()
|
||||
return cell
|
||||
}
|
||||
}
|
||||
|
||||
extension RadioSwatches: UICollectionViewDelegate {
|
||||
open func collectionView(_ collectionView: UICollectionView, shouldSelectItemAt indexPath: IndexPath) -> Bool {
|
||||
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? 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? RadioSwatchCollectionViewCell else { return }
|
||||
cell.radioSwatch.deselectSwatch()
|
||||
}
|
||||
}
|
||||
54
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift
Normal file
54
MVMCoreUI/Atomic/Atoms/Selectors/RadioSwatchesModel.swift
Normal file
@ -0,0 +1,54 @@
|
||||
//
|
||||
// RadioSwatchesModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Lekshmi S on 31/03/20.
|
||||
// Copyright © 2020 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objcMembers public class RadioSwatchesModel: MoleculeModelProtocol, FormFieldProtocol {
|
||||
public static var identifier: String = "radioSwatches"
|
||||
public var backgroundColor: Color?
|
||||
public var swatches: [RadioSwatchModel]
|
||||
public var fieldKey: String?
|
||||
public var groupName: String = FormValidator.defaultGroupName
|
||||
public var baseValue: AnyHashable?
|
||||
|
||||
/// 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
|
||||
}
|
||||
return selectedSwatch?.fieldValue ?? selectedSwatch?.text
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case swatches
|
||||
case fieldKey
|
||||
case groupName
|
||||
}
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
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
|
||||
}
|
||||
baseValue = formFieldValue()
|
||||
}
|
||||
|
||||
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(swatches, forKey: .swatches)
|
||||
try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
|
||||
try container.encode(groupName, forKey: .groupName)
|
||||
}
|
||||
}
|
||||
@ -70,6 +70,7 @@ import Foundation
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioBoxes.self, viewModelClass: RadioBoxesModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: Checkbox.self, viewModelClass: CheckboxModel.self)
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: RadioSwatches.self, viewModelClass: RadioSwatchesModel.self)
|
||||
|
||||
// Other Atoms
|
||||
MoleculeObjectMapping.shared()?.register(viewClass: ProgressBar.self, viewModelClass: ProgressBarModel.self)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user