diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9aaecbbb..65c0e81d 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -72,6 +72,8 @@ 0A25209824645B76000FA9F6 /* TextViewEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */; }; 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; + 0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */; }; + 0A51F3E32475CB73002E08B6 /* LoadingSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; 0A6682A22434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A12434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift */; }; 0A6682A42434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A32434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift */; }; @@ -529,6 +531,8 @@ 0A25209724645B76000FA9F6 /* TextViewEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextViewEntryFieldModel.swift; sourceTree = ""; }; 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; + 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingSpinnerModel.swift; sourceTree = ""; }; + 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadingSpinner.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; 0A6682A12434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonBodyText.swift; sourceTree = ""; }; 0A6682A32434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonBodyTextModel.swift; sourceTree = ""; }; @@ -1797,6 +1801,8 @@ 94382085243238D100B43AF3 /* WebViewModel.swift */, 943820832432382400B43AF3 /* WebView.swift */, D20492A524329CE200A5EED6 /* LoadImageView.swift */, + 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */, + 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */, ); path = Views; sourceTree = ""; @@ -2411,6 +2417,7 @@ 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */, D2092355244FA0FD0044AD09 /* ThreeLayerTemplateModelProtocol.swift in Sources */, 0AE14F64238315D2005417F8 /* TextField.swift in Sources */, + 0A51F3E22475CB73002E08B6 /* LoadingSpinnerModel.swift in Sources */, 0AB764D124460F6300E7FE72 /* UIDatePicker+Extension.swift in Sources */, BB105859248DEFF70069D008 /* UICollectionViewLeftAlignedLayout.swift in Sources */, D253BB9C245874F8002DE544 /* BGImageMolecule.swift in Sources */, @@ -2440,6 +2447,7 @@ 0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */, 0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */, D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */, + 0A51F3E32475CB73002E08B6 /* LoadingSpinner.swift in Sources */, BB2FB3BB247E7EBC00DF73CD /* TagCollectionViewCell.swift in Sources */, 012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */, 94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift new file mode 100644 index 00000000..2d58c8f4 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -0,0 +1,213 @@ +// +// LoadingSpinner.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 5/20/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + + +open class LoadingSpinner: View { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var strokeColor: UIColor = .mvmBlack + + public var lineWidth: CGFloat = 4.0 + + public var speed: Float = 1.5 + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + + public var heightConstraint: NSLayoutConstraint? + public var widthConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + override open var layer: CAShapeLayer { + get { return super.layer as! CAShapeLayer } + } + + override open class var layerClass: AnyClass { + return CAShapeLayer.self + } + + open override func setupView() { + super.setupView() + + heightConstraint = heightAnchor.constraint(equalToConstant: 0) + widthConstraint = widthAnchor.constraint(equalToConstant: 0) + } + + override open func layoutSubviews() { + super.layoutSubviews() + + layer.fillColor = nil + layer.strokeColor = strokeColor.cgColor + layer.lineWidth = lineWidth + layer.lineCap = .butt + layer.speed = speed + let halfWidth = lineWidth / 2 + let radius = (bounds.width - lineWidth) / 2 + layer.path = UIBezierPath(arcCenter: CGPoint(x: radius + halfWidth, + y: radius + halfWidth), + radius: radius, + startAngle: -CGFloat.pi / 2, + endAngle: 2 * CGFloat.pi, + clockwise: true).cgPath + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + + layer.removeAllAnimations() + animate() + } + + public override func reset() { + super.reset() + + layer.removeAllAnimations() + heightConstraint?.isActive = false + widthConstraint?.isActive = false + } + + //-------------------------------------------------- + // MARK: - Animation + //-------------------------------------------------- + + override open func didMoveToWindow() { + animate() + } + + struct Pose { + /// Delayed time (in seconds) to execute after the previous Pose. + let delay: CFTimeInterval + /// The time into the animation to begin drawing. + let startTime: CGFloat + /// The length of the drawn line. + let length: CGFloat + } + + // TODO: This needs more attention to improve frame smoothness. + class var poses: [Pose] { + get { + return [ + Pose(delay: 0.0, startTime: 0.000, length: 0.7), + Pose(delay: 0.7, startTime: 0.500, length: 0.5), + Pose(delay: 0.6, startTime: 1.000, length: 0.3), + Pose(delay: 0.5, startTime: 1.500, length: 0.2), + Pose(delay: 0.5, startTime: 1.875, length: 0.2), + Pose(delay: 0.3, startTime: 2.250, length: 0.3), + Pose(delay: 0.2, startTime: 2.600, length: 0.5), + Pose(delay: 0.2, startTime: 3.000, length: 0.7) + ] + } + } + + private func animate() { + var time: CFTimeInterval = 0 + var times = [CFTimeInterval]() + var start: CGFloat = 0 + var rotations = [CGFloat]() + var strokeEnds = [CGFloat]() + + let poses = Self.poses + var totalSeconds: CFTimeInterval = poses.reduce(0) { $0 + $1.delay } + + for pose in poses { + time += pose.delay + times.append(time / totalSeconds) + start = pose.startTime + rotations.append(start * 2 * CGFloat.pi) + strokeEnds.append(pose.length) + } + + totalSeconds += 0.3 + + animateKeyPath(keyPath: "strokeEnd", duration: totalSeconds, times: times, values: strokeEnds) + animateKeyPath(keyPath: "transform.rotation", duration: totalSeconds, times: times, values: rotations) + } + + private func animateKeyPath(keyPath: String, duration: CFTimeInterval, times: [CFTimeInterval], values: [CGFloat]) { + + let animation = CAKeyframeAnimation(keyPath: keyPath) + animation.keyTimes = times as [NSNumber]? + animation.values = values + animation.calculationMode = .linear + animation.timingFunction = CAMediaTimingFunction(name: .linear) + animation.duration = duration + animation.rotationMode = .rotateAuto + animation.fillMode = .forwards + animation.isRemovedOnCompletion = false + animation.repeatCount = .infinity + layer.add(animation, forKey: animation.keyPath) + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + func resumeSpinnerAfterDelay() { + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in + self?.resumeAnimations() + } + } + + func pauseAnimations() { + + let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil) + layer.speed = 0 + isHidden = true + layer.timeOffset = pausedTime + } + + func resumeAnimations() { + + let pausedTime = layer.timeOffset + isHidden = false + layer.speed = speed + layer.timeOffset = 0 + let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime + layer.beginTime = timeSincePause + } + + func stopAllAnimations() { + + layer.removeAllAnimations() + } + + func pinWidthAndHeight(diameter: CGFloat) { + + let dimension = diameter + lineWidth + heightConstraint?.constant = dimension + widthConstraint?.constant = dimension + heightConstraint?.isActive = true + widthConstraint?.isActive = true + } + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + + public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? LoadingSpinnerModel else { return } + + strokeColor = model.strokeColor.uiColor + lineWidth = model.lineWidth + pinWidthAndHeight(diameter: model.diameter) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + return 40.0 + } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift new file mode 100644 index 00000000..bdef3c86 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift @@ -0,0 +1,65 @@ +// +// LoadingSpinnerModel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 5/20/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + + +open class LoadingSpinnerModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var backgroundColor: Color? + public static var identifier: String = "loadingSpinner" + public var strokeColor = Color(uiColor: .mvmBlack) + public var lineWidth: CGFloat = 4 + public var diameter: CGFloat = 40 + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case strokeColor + case lineWidth + case diameter + } + + //-------------------------------------------------- + // 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) + + if let diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) { + self.diameter = diameter + } + + if let strokeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .strokeColor) { + self.strokeColor = strokeColor + } + + if let lineWidth = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .lineWidth) { + self.lineWidth = lineWidth + } + } + + 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.encodeIfPresent(diameter, forKey: .diameter) + try container.encode(strokeColor, forKey: .strokeColor) + try container.encode(lineWidth, forKey: .lineWidth) + } +} diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 38aac342..5a3a3a1f 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -48,12 +48,12 @@ import Foundation /// Call to register all of the CoreUI molecules. public static func registerObjects() { - // Stacks + // MARK:- Stacks MoleculeObjectMapping.shared()?.register(viewClass: MoleculeStackView.self, viewModelClass: StackModel.self) MoleculeObjectMapping.shared()?.register(viewClass: UnOrderedList.self, viewModelClass: UnOrderedListModel.self) MoleculeObjectMapping.shared()?.register(viewClass: NumberedList.self, viewModelClass: NumberedListModel.self) - // Label + // MARK:- Label MoleculeObjectMapping.shared()?.register(viewClass: Label.self, viewModelClass: LabelModel.self) // need to move labelattributemodel to different method try? ModelRegistry.register(LabelAttributeFontModel.self) @@ -63,24 +63,24 @@ import Foundation try? ModelRegistry.register(LabelAttributeStrikeThroughModel.self) try? ModelRegistry.register(LabelAttributeActionModel.self) - // TextView + // MARK:- TextView MoleculeObjectMapping.shared()?.register(viewClass: TextViewEntryField.self, viewModelClass: TextViewEntryFieldModel.self) - // Buttons + // MARK:- Buttons MoleculeObjectMapping.shared()?.register(viewClass: PillButton.self, viewModelClass: ButtonModel.self) MoleculeObjectMapping.shared()?.register(viewClass: TwoButtonView.self, viewModelClass: TwoButtonViewModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ExternalLink.self, viewModelClass: ExternalLinkModel.self) MoleculeObjectMapping.shared()?.register(viewClass: Link.self, viewModelClass: LinkModel.self) MoleculeObjectMapping.shared()?.register(viewClass: CaretLink.self, viewModelClass: CaretLinkModel.self) - // Entry Field + // MARK:- Entry Field MoleculeObjectMapping.shared()?.register(viewClass: TextEntryField.self, viewModelClass: TextEntryFieldModel.self) MoleculeObjectMapping.shared()?.register(viewClass: MdnEntryField.self, viewModelClass: MdnEntryFieldModel.self) MoleculeObjectMapping.shared()?.register(viewClass: DigitEntryField.self, viewModelClass: DigitEntryFieldModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ItemDropdownEntryField.self, viewModelClass: ItemDropdownEntryFieldModel.self) MoleculeObjectMapping.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self) - // Selectors + // MARK:- Selectors 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) @@ -90,7 +90,7 @@ import Foundation - // Other Atoms + // MARK:- Other Atoms MoleculeObjectMapping.shared()?.register(viewClass: ProgressBar.self, viewModelClass: ProgressBarModel.self) MoleculeObjectMapping.shared()?.register(viewClass: MultiProgress.self, viewModelClass: MultiProgressBarModel.self) MoleculeObjectMapping.shared()?.register(viewClass: CaretView.self, viewModelClass: CaretViewModel.self) @@ -103,14 +103,15 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: Arrow.self, viewModelClass: ArrowModel.self) MoleculeObjectMapping.shared()?.register(viewClass: RadioButtonLabel.self, viewModelClass: RadioButtonLabelModel.self) MoleculeObjectMapping.shared()?.register(viewClass: WebView.self, viewModelClass: WebViewModel.self) - - // Horizontal Combination Molecules + MoleculeObjectMapping.shared()?.register(viewClass: LoadingSpinner.self, viewModelClass: LoadingSpinnerModel.self) + + // MARK:- Horizontal Combination Molecules MoleculeObjectMapping.shared()?.register(viewClass: StringAndMoleculeView.self, viewModelClass: StringAndMoleculeModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ImageHeadlineBody.self, viewModelClass: ImageHeadlineBodyModel.self) MoleculeObjectMapping.shared()?.register(viewClass: Tabs.self, viewModelClass: TabsModel.self) MoleculeObjectMapping.shared()?.register(viewClass: TwoLinkView.self, viewModelClass: TwoLinkViewModel.self) - // Vertical Combination Molecules + // MARK:- Vertical Combination Molecules MoleculeObjectMapping.shared()?.register(viewClass: HeadlineBody.self, viewModelClass: HeadlineBodyModel.self) MoleculeObjectMapping.shared()?.register(viewClass: HeadLineBodyCaretLinkImage.self, viewModelClass: HeadlineBodyCaretLinkImageModel.self) MoleculeObjectMapping.shared()?.register(viewClass: EyebrowHeadlineBodyLink.self, viewModelClass: EyebrowHeadlineBodyLinkModel.self) @@ -119,7 +120,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: BGImageHeadlineBodyButton.self, viewModelClass: BGImageHeadlineBodyButtonModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ThreeHeadlineBodyLink.self, viewModelClass: ThreeHeadlineBodyLinkModel.self) - // Left Right Molecules + // MARK:- Left Right Molecules MoleculeObjectMapping.shared()?.register(viewClass: CornerLabels.self, viewModelClass: CornerLabelsModel.self) MoleculeObjectMapping.shared()?.register(viewClass: LeftRightLabelView.self, viewModelClass: LeftRightLabelModel.self) MoleculeObjectMapping.shared()?.register(viewClass: LabelToggle.self, viewModelClass: LabelToggleModel.self) @@ -127,21 +128,21 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: HeadlineBodyLinkToggle.self, viewModelClass: HeadlineBodyLinkToggleModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ActionDetailWithImage.self, viewModelClass: ActionDetailWithImageModel.self) - // List items + // MARK:- List items MoleculeObjectMapping.shared()?.register(viewClass: MoleculeTableViewCell.self, viewModelClass: MoleculeListItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: DropDownFilterTableViewCell.self, viewModelClass: DropDownListItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: AccordionMoleculeTableViewCell.self, viewModelClass: AccordionListItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: TabsTableViewCell.self, viewModelClass: TabsListItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListProgressBarData.self, viewModelClass: ListProgressBarDataModel.self) - // Other Items + // MARK:- Other Items MoleculeObjectMapping.shared()?.register(viewClass: MoleculeStackItem.self, viewModelClass: MoleculeStackItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: StackItem.self, viewModelClass: StackItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: MoleculeCollectionViewCell.self, viewModelClass: MoleculeCollectionItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: CarouselItem.self, viewModelClass: CarouselItemModel.self) - // Other Container Molecules + // MARK:- Other Container Molecules MoleculeObjectMapping.shared()?.register(viewClass: MoleculeContainer.self, viewModelClass: MoleculeContainerModel.self) MoleculeObjectMapping.shared()?.register(viewClass: MoleculeHeaderView.self, viewModelClass: MoleculeHeaderModel.self) MoleculeObjectMapping.shared()?.register(viewClass: FooterView.self, viewModelClass: FooterModel.self) @@ -149,7 +150,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: ModuleMolecule.self, viewModelClass: ModuleMoleculeModel.self) MoleculeObjectMapping.shared()?.register(viewClass: BGImageMolecule.self, viewModelClass: BGImageMoleculeModel.self) - // Other Molecules + // MARK:- Other Molecules MoleculeObjectMapping.shared()?.register(viewClass: DoughnutChartView.self, viewModelClass: DoughnutChartModel.self) // Navigation Molecules @@ -157,12 +158,12 @@ import Foundation try? ModelRegistry.register(NavigationImageButtonModel.self) try? ModelRegistry.register(NavigationLabelButtonModel.self) - // Other Organisms + // MARK:- Other Organisms MoleculeObjectMapping.shared()?.register(viewClass: Carousel.self, viewModelClass: CarouselModel.self) MoleculeObjectMapping.shared()?.register(viewClass: BarsIndicatorView.self, viewModelClass: BarsCarouselIndicatorModel.self) MoleculeObjectMapping.shared()?.register(viewClass: NumericIndicatorView.self, viewModelClass: NumericCarouselIndicatorModel.self) - // Designed List Items + // MARK:- Designed List Items MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableIconWithRightCaretBodyText.self, viewModelClass: ListLeftVariableIconWithRightCaretBodyTextModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableCheckboxAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxAllTextAndLinksModel.self) @@ -192,7 +193,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageListItem.self, viewModelClass: ListFourColumnDataUsageListItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListProgressBarThin.self, viewModelClass: ListProgressBarThinModel.self) - // Designed Section Dividers + // MARK:- Designed Section Dividers MoleculeObjectMapping.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnPlanDataDivider.self, viewModelClass: ListThreeColumnPlanDataDividerModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerShort.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerShortModel.self) @@ -204,7 +205,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnBillChangesDivider.self, viewModelClass: ListThreeColumnBillChangesDividerModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnDataUsageDivider.self, viewModelClass: ListThreeColumnDataUsageDividerModel.self) - // Designed Headers + // MARK:- Designed Headers MoleculeObjectMapping.shared()?.register(viewClass: HeadersH1Button.self, viewModelClass: HeadersH1ButtonModel.self) MoleculeObjectMapping.shared()?.register(viewClass: HeadersH1LandingPageHeader.self, viewModelClass: HeadersH1LandingPageHeaderModel.self) MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) @@ -214,14 +215,14 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2Link.self, viewModelClass: HeadersH2LinkModel.self) MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2CaretLink.self, viewModelClass: HeadersH2CaretLinkModel.self) - // Device Items + // MARK:- Device Items MoleculeObjectMapping.shared()?.register(viewClass: ListDeviceComplexButtonMedium.self, viewModelClass: ListDeviceComplexButtonMediumModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListDeviceComplexButtonSmall.self, viewModelClass: ListDeviceComplexButtonSmallModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListDeviceComplexLinkSmall.self, viewModelClass: ListDeviceComplexLinkSmallModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListDeviceComplexLinkMedium.self, viewModelClass: ListDeviceComplexLinkMediumModel.self) - // Helper models + // MARK:- Helper models try? ModelRegistry.register(RuleRequiredModel.self) try? ModelRegistry.register(RuleAnyRequiredModel.self) try? ModelRegistry.register(RuleAnyValueChangedModel.self) @@ -230,12 +231,12 @@ import Foundation try? ModelRegistry.register(RuleEqualsIgnoreCaseModel.self) try? ModelRegistry.register(RuleRegexModel.self) - // Actions + // MARK:- Actions try? ModelRegistry.register(ActionTopAlertModel.self) try? ModelRegistry.register(ActionCollapseNotificationModel.self) try? ModelRegistry.register(ActionOpenPanelModel.self) - // Behaviors + // MARK:- Behaviors try? ModelRegistry.register(ScreenBrightnessModifierBehavior.self) }