From f3cc8c479ad3e300b07fb32f7c8fbfabe05195bb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 20 May 2020 16:34:40 -0400 Subject: [PATCH 01/24] new addition --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 47 ++++++++++---------- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index ba954d23..54f0efed 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 */; }; @@ -487,6 +489,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 = ""; }; @@ -1649,6 +1653,8 @@ 94382085243238D100B43AF3 /* WebViewModel.swift */, 943820832432382400B43AF3 /* WebView.swift */, D20492A524329CE200A5EED6 /* LoadImageView.swift */, + 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */, + 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */, ); path = Views; sourceTree = ""; @@ -2206,6 +2212,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 */, D253BB9C245874F8002DE544 /* BGImageMolecule.swift in Sources */, D2C78CD224228BBD00B69FDE /* ActionOpenPanelModel.swift in Sources */, @@ -2232,6 +2239,7 @@ 0A21DB83235DFBC500C160A2 /* MdnEntryField.swift in Sources */, 0AE98BB723FF18E9004C5109 /* ArrowModel.swift in Sources */, D28A837D23CCA86A00DFE4FC /* TabsListItemModel.swift in Sources */, + 0A51F3E32475CB73002E08B6 /* LoadingSpinner.swift in Sources */, 012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */, 94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */, D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index e46cfed0..23714df1 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -36,12 +36,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) @@ -51,30 +51,30 @@ 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) MoleculeObjectMapping.shared()?.register(viewClass: RadioSwatches.self, viewModelClass: RadioSwatchesModel.self) - // 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) @@ -87,14 +87,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) @@ -102,7 +103,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: HeadlineBodyButton.self, viewModelClass: HeadlineBodyButtonModel.self) MoleculeObjectMapping.shared()?.register(viewClass: BGImageHeadlineBodyButton.self, viewModelClass: BGImageHeadlineBodyButtonModel.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) @@ -110,21 +111,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) @@ -132,15 +133,15 @@ 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) - // 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: ListLeftVariableCheckboxAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxAllTextAndLinksModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self) @@ -165,7 +166,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) @@ -177,19 +178,19 @@ 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: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2TinyButton.self, viewModelClass: HeadersH2TinyButtonModel.self) MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2Buttons.self, viewModelClass: HeadersH2ButtonsModel.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) @@ -198,12 +199,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) } From 15a51bd86f444274406a6d3b428abf5422152a60 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 20 May 2020 16:36:41 -0400 Subject: [PATCH 02/24] adding to src --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 181 ++++++++++++++++++ .../Atoms/Views/LoadingSpinnerModel.swift | 58 ++++++ 2 files changed, 239 insertions(+) create mode 100644 MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift create mode 100644 MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift new file mode 100644 index 00000000..fbe49535 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -0,0 +1,181 @@ +// +// 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 = 3.0 + + public var speed: Float = 1.5 + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + override open func setupView() { + super.setupView() + + // TODO: remove + pinWidthAndHeight(radius: 20) + } + + override open var layer: CAShapeLayer { + get { return super.layer as! CAShapeLayer } + } + + override open class var layerClass: AnyClass { + return CAShapeLayer.self + } + + override open func layoutSubviews() { + super.layoutSubviews() + layer.fillColor = nil + layer.strokeColor = strokeColor.cgColor + layer.lineWidth = lineWidth + layer.lineCap = .butt + layer.speed = speed + layer.path = UIBezierPath(ovalIn: bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)).cgPath + } + + //-------------------------------------------------- + // MARK: - Animation + //-------------------------------------------------- + + override open func didMoveToWindow() { + animate() + } + + struct Pose { + let secondsSincePriorPose: CFTimeInterval + let start: CGFloat + let length: CGFloat + init(_ secondsSincePriorPose: CFTimeInterval, _ start: CGFloat, _ length: CGFloat) { + self.secondsSincePriorPose = secondsSincePriorPose + self.start = start + self.length = length + } + } + + // TODO: This needs more attention + class var poses: [Pose] { + get { + return [ + Pose(0.0, 0.000, 0.8), + Pose(0.6, 0.500, 0.5), + Pose(0.6, 1.000, 0.3), + Pose(0.6, 1.500, 0.1), + Pose(0.2, 1.875, 0.1), + Pose(0.2, 2.250, 0.3), + Pose(0.2, 2.625, 0.5), + Pose(0.2, 3.000, 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 + let totalSeconds = poses.reduce(0) { $0 + $1.secondsSincePriorPose } + + for pose in poses { + time += pose.secondsSincePriorPose + times.append(time / totalSeconds) + start = pose.start + rotations.append(start * 2 * CGFloat.pi) + strokeEnds.append(pose.length) + } + + times.append(times.last!) + rotations.append(rotations[0]) + strokeEnds.append(strokeEnds[0]) + + 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.duration = duration + animation.rotationMode = .rotateAuto + 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 + layer.beginTime = 0 + let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime + layer.beginTime = timeSincePause + } + + func stopAllAnimations() { + layer.removeAllAnimations() + } + + func pinWidthAndHeight(radius: CGFloat) { + let diameter: CGFloat = radius * 2 + lineWidth + NSLayoutConstraint.activate([ + heightAnchor.constraint(equalToConstant: diameter), + widthAnchor.constraint(equalToConstant: diameter) + ]) + } + + //-------------------------------------------------- + // 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 + } + + 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..604c0689 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift @@ -0,0 +1,58 @@ +// +// 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 = 3 + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case strokeColor + case lineWidth + } + + //-------------------------------------------------- + // 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 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.encode(strokeColor, forKey: .strokeColor) + try container.encode(lineWidth, forKey: .lineWidth) + } +} From eda9379e3719cafe8434618643380218c8eefd71 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 20 May 2020 17:08:43 -0400 Subject: [PATCH 03/24] adjusment --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index fbe49535..929bb5ed 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -72,12 +72,12 @@ open class LoadingSpinner: View { class var poses: [Pose] { get { return [ - Pose(0.0, 0.000, 0.8), - Pose(0.6, 0.500, 0.5), + Pose(0.0, 0.000, 0.7), + Pose(0.7, 0.500, 0.5), Pose(0.6, 1.000, 0.3), - Pose(0.6, 1.500, 0.1), - Pose(0.2, 1.875, 0.1), - Pose(0.2, 2.250, 0.3), + Pose(0.4, 1.500, 0.2), + Pose(0.3, 1.875, 0.2), + Pose(0.3, 2.250, 0.3), Pose(0.2, 2.625, 0.5), Pose(0.2, 3.000, 0.7) ] @@ -118,6 +118,7 @@ open class LoadingSpinner: View { animation.calculationMode = .linear animation.duration = duration animation.rotationMode = .rotateAuto + animation.fillMode = .forwards animation.isRemovedOnCompletion = false animation.repeatCount = .infinity layer.add(animation, forKey: animation.keyPath) From 898877a05105c440e72c455fa0e8e78a51ca5524 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 21 May 2020 10:44:21 -0400 Subject: [PATCH 04/24] curent working order --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 929bb5ed..74eeb2dc 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -58,28 +58,23 @@ open class LoadingSpinner: View { } struct Pose { - let secondsSincePriorPose: CFTimeInterval + let delay: CFTimeInterval let start: CGFloat let length: CGFloat - init(_ secondsSincePriorPose: CFTimeInterval, _ start: CGFloat, _ length: CGFloat) { - self.secondsSincePriorPose = secondsSincePriorPose - self.start = start - self.length = length - } } // TODO: This needs more attention class var poses: [Pose] { get { return [ - Pose(0.0, 0.000, 0.7), - Pose(0.7, 0.500, 0.5), - Pose(0.6, 1.000, 0.3), - Pose(0.4, 1.500, 0.2), - Pose(0.3, 1.875, 0.2), - Pose(0.3, 2.250, 0.3), - Pose(0.2, 2.625, 0.5), - Pose(0.2, 3.000, 0.7) + Pose(delay: 0.0, start: 0.000, length: 0.7), + Pose(delay: 0.7, start: 0.500, length: 0.5), + Pose(delay: 0.6, start: 1.000, length: 0.3), + Pose(delay: 0.5, start: 1.500, length: 0.2), + Pose(delay: 0.4, start: 1.875, length: 0.2), + Pose(delay: 0.3, start: 2.250, length: 0.3), + Pose(delay: 0.2, start: 2.600, length: 0.5), + Pose(delay: 0.2, start: 3.000, length: 0.7) ] } } @@ -92,19 +87,19 @@ open class LoadingSpinner: View { var strokeEnds = [CGFloat]() let poses = Self.poses - let totalSeconds = poses.reduce(0) { $0 + $1.secondsSincePriorPose } + let totalSeconds = poses.reduce(0) { $0 + $1.delay } for pose in poses { - time += pose.secondsSincePriorPose + time += pose.delay times.append(time / totalSeconds) start = pose.start rotations.append(start * 2 * CGFloat.pi) strokeEnds.append(pose.length) } - times.append(times.last!) - rotations.append(rotations[0]) - strokeEnds.append(strokeEnds[0]) +// times.append(times.last ?? 1) +// rotations.append(rotations[0]) +// strokeEnds.append(strokeEnds[0]) animateKeyPath(keyPath: "strokeEnd", duration: totalSeconds, times: times, values: strokeEnds) animateKeyPath(keyPath: "transform.rotation", duration: totalSeconds, times: times, values: rotations) @@ -116,6 +111,7 @@ open class LoadingSpinner: View { 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 @@ -136,6 +132,7 @@ open class LoadingSpinner: View { } func pauseAnimations() { + let pausedTime = layer.convertTime(CACurrentMediaTime(), from: nil) layer.speed = 0 isHidden = true @@ -143,6 +140,7 @@ open class LoadingSpinner: View { } func resumeAnimations() { + let pausedTime = layer.timeOffset isHidden = false layer.speed = speed @@ -153,11 +151,14 @@ open class LoadingSpinner: View { } func stopAllAnimations() { + layer.removeAllAnimations() } func pinWidthAndHeight(radius: CGFloat) { + let diameter: CGFloat = radius * 2 + lineWidth + NSLayoutConstraint.activate([ heightAnchor.constraint(equalToConstant: diameter), widthAnchor.constraint(equalToConstant: diameter) From 9803f04a788b6aca06ac42245ade1556f555e8ca Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 21 May 2020 16:21:19 -0400 Subject: [PATCH 05/24] current --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 74eeb2dc..3a00df8d 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -44,9 +44,12 @@ open class LoadingSpinner: View { layer.fillColor = nil layer.strokeColor = strokeColor.cgColor layer.lineWidth = lineWidth - layer.lineCap = .butt + layer.lineCap = .round layer.speed = speed - layer.path = UIBezierPath(ovalIn: bounds.insetBy(dx: lineWidth / 2, dy: lineWidth / 2)).cgPath + 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.5 * CGFloat.pi, clockwise: true).cgPath + } //-------------------------------------------------- @@ -79,6 +82,25 @@ open class LoadingSpinner: View { } } + // I like this +// Pose(delay: 0.0, start: 0.000, length: 0.75), +// Pose(delay: 0.7, start: 0.500, length: 0.55), +// Pose(delay: 0.5, start: 1.000, length: 0.35), +// Pose(delay: 0.4, start: 1.500, length: 0.4), +// Pose(delay: 0.3, start: 1.875, length: 0.25), +// Pose(delay: 0.3, start: 2.250, length: 0.4), +// Pose(delay: 0.4, start: 2.600, length: 0.55), +// Pose(delay: 0.4, start: 3.000, length: 0.7) + +// Pose(delay: 0.0, start: 0.000, length: 0.7), +// Pose(delay: 0.7, start: 0.500, length: 0.5), +// Pose(delay: 0.6, start: 1.000, length: 0.3), +// Pose(delay: 0.5, start: 1.500, length: 0.2), +// Pose(delay: 0.4, start: 1.875, length: 0.2), +// Pose(delay: 0.3, start: 2.250, length: 0.3), +// Pose(delay: 0.2, start: 2.600, length: 0.5), +// Pose(delay: 0.2, start: 3.000, length: 0.7) + private func animate() { var time: CFTimeInterval = 0 var times = [CFTimeInterval]() From b0172ff1f61c39ee8d4e42f79657df9899ec16d6 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 21 May 2020 16:28:21 -0400 Subject: [PATCH 06/24] bu 2 --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 3a00df8d..6bee5ea6 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -48,7 +48,7 @@ open class LoadingSpinner: View { 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.5 * CGFloat.pi, clockwise: true).cgPath + layer.path = UIBezierPath(arcCenter: CGPoint(x: radius + halfWidth, y: radius + halfWidth), radius: radius, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true).cgPath } From 8a5a2486284cc4bc87dd0870a35d51120adeb8a9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 22 May 2020 09:26:13 -0400 Subject: [PATCH 07/24] latestest state. almost there --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 36 +++++++------------ 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 6bee5ea6..9842ce5a 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -61,8 +61,11 @@ open class LoadingSpinner: View { } struct Pose { + /// Delayed time (in seconds) to execute after the previous Pose. let delay: CFTimeInterval + /// The time into the animation to begin. let start: CGFloat + /// The length of the drawn line. let length: CGFloat } @@ -70,6 +73,7 @@ open class LoadingSpinner: View { class var poses: [Pose] { get { return [ +// Pose(delay: 0.0, start: 1.250, length: 0.7), Pose(delay: 0.0, start: 0.000, length: 0.7), Pose(delay: 0.7, start: 0.500, length: 0.5), Pose(delay: 0.6, start: 1.000, length: 0.3), @@ -78,29 +82,19 @@ open class LoadingSpinner: View { Pose(delay: 0.3, start: 2.250, length: 0.3), Pose(delay: 0.2, start: 2.600, length: 0.5), Pose(delay: 0.2, start: 3.000, length: 0.7) + + // Pose(delay: 0.0, start: 0.000, length: 0.75), + // Pose(delay: 0.7, start: 0.500, length: 0.55), + // Pose(delay: 0.5, start: 1.000, length: 0.35), + // Pose(delay: 0.4, start: 1.500, length: 0.4), + // Pose(delay: 0.3, start: 1.875, length: 0.25), + // Pose(delay: 0.3, start: 2.250, length: 0.4), + // Pose(delay: 0.4, start: 2.600, length: 0.55), + // Pose(delay: 0.4, start: 3.000, length: 0.7) ] } } - // I like this -// Pose(delay: 0.0, start: 0.000, length: 0.75), -// Pose(delay: 0.7, start: 0.500, length: 0.55), -// Pose(delay: 0.5, start: 1.000, length: 0.35), -// Pose(delay: 0.4, start: 1.500, length: 0.4), -// Pose(delay: 0.3, start: 1.875, length: 0.25), -// Pose(delay: 0.3, start: 2.250, length: 0.4), -// Pose(delay: 0.4, start: 2.600, length: 0.55), -// Pose(delay: 0.4, start: 3.000, length: 0.7) - -// Pose(delay: 0.0, start: 0.000, length: 0.7), -// Pose(delay: 0.7, start: 0.500, length: 0.5), -// Pose(delay: 0.6, start: 1.000, length: 0.3), -// Pose(delay: 0.5, start: 1.500, length: 0.2), -// Pose(delay: 0.4, start: 1.875, length: 0.2), -// Pose(delay: 0.3, start: 2.250, length: 0.3), -// Pose(delay: 0.2, start: 2.600, length: 0.5), -// Pose(delay: 0.2, start: 3.000, length: 0.7) - private func animate() { var time: CFTimeInterval = 0 var times = [CFTimeInterval]() @@ -119,10 +113,6 @@ open class LoadingSpinner: View { strokeEnds.append(pose.length) } -// times.append(times.last ?? 1) -// rotations.append(rotations[0]) -// strokeEnds.append(strokeEnds[0]) - animateKeyPath(keyPath: "strokeEnd", duration: totalSeconds, times: times, values: strokeEnds) animateKeyPath(keyPath: "transform.rotation", duration: totalSeconds, times: times, values: rotations) } From 05346d81fac604660c5a64d02de309ca1dc7f3f5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 22 May 2020 16:13:01 -0400 Subject: [PATCH 08/24] loosk pretty good on device --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 9842ce5a..4a82793b 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -73,7 +73,6 @@ open class LoadingSpinner: View { class var poses: [Pose] { get { return [ -// Pose(delay: 0.0, start: 1.250, length: 0.7), Pose(delay: 0.0, start: 0.000, length: 0.7), Pose(delay: 0.7, start: 0.500, length: 0.5), Pose(delay: 0.6, start: 1.000, length: 0.3), @@ -82,15 +81,6 @@ open class LoadingSpinner: View { Pose(delay: 0.3, start: 2.250, length: 0.3), Pose(delay: 0.2, start: 2.600, length: 0.5), Pose(delay: 0.2, start: 3.000, length: 0.7) - - // Pose(delay: 0.0, start: 0.000, length: 0.75), - // Pose(delay: 0.7, start: 0.500, length: 0.55), - // Pose(delay: 0.5, start: 1.000, length: 0.35), - // Pose(delay: 0.4, start: 1.500, length: 0.4), - // Pose(delay: 0.3, start: 1.875, length: 0.25), - // Pose(delay: 0.3, start: 2.250, length: 0.4), - // Pose(delay: 0.4, start: 2.600, length: 0.55), - // Pose(delay: 0.4, start: 3.000, length: 0.7) ] } } From b05b6c20c08478a570952d821d5d38cb4d05cd75 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 26 May 2020 09:38:08 -0400 Subject: [PATCH 09/24] looking bette --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 4a82793b..675e40d0 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -77,7 +77,7 @@ open class LoadingSpinner: View { Pose(delay: 0.7, start: 0.500, length: 0.5), Pose(delay: 0.6, start: 1.000, length: 0.3), Pose(delay: 0.5, start: 1.500, length: 0.2), - Pose(delay: 0.4, start: 1.875, length: 0.2), + Pose(delay: 0.5, start: 1.875, length: 0.2), Pose(delay: 0.3, start: 2.250, length: 0.3), Pose(delay: 0.2, start: 2.600, length: 0.5), Pose(delay: 0.2, start: 3.000, length: 0.7) @@ -93,7 +93,7 @@ open class LoadingSpinner: View { var strokeEnds = [CGFloat]() let poses = Self.poses - let totalSeconds = poses.reduce(0) { $0 + $1.delay } + var totalSeconds: CFTimeInterval = poses.reduce(0) { $0 + $1.delay } for pose in poses { time += pose.delay @@ -103,6 +103,8 @@ open class LoadingSpinner: View { 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) } From c0f3e8a4501785d878bc53eaf7c78b48bf62aaa9 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 26 May 2020 10:40:34 -0400 Subject: [PATCH 10/24] renaming --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 675e40d0..68acdfb7 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -63,8 +63,8 @@ open class LoadingSpinner: View { struct Pose { /// Delayed time (in seconds) to execute after the previous Pose. let delay: CFTimeInterval - /// The time into the animation to begin. - let start: CGFloat + /// The time into the animation to begin drawing. + let startTime: CGFloat /// The length of the drawn line. let length: CGFloat } @@ -73,14 +73,14 @@ open class LoadingSpinner: View { class var poses: [Pose] { get { return [ - Pose(delay: 0.0, start: 0.000, length: 0.7), - Pose(delay: 0.7, start: 0.500, length: 0.5), - Pose(delay: 0.6, start: 1.000, length: 0.3), - Pose(delay: 0.5, start: 1.500, length: 0.2), - Pose(delay: 0.5, start: 1.875, length: 0.2), - Pose(delay: 0.3, start: 2.250, length: 0.3), - Pose(delay: 0.2, start: 2.600, length: 0.5), - Pose(delay: 0.2, start: 3.000, length: 0.7) + 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) ] } } @@ -98,7 +98,7 @@ open class LoadingSpinner: View { for pose in poses { time += pose.delay times.append(time / totalSeconds) - start = pose.start + start = pose.startTime rotations.append(start * 2 * CGFloat.pi) strokeEnds.append(pose.length) } From c6cfe39c3091905618eb39abd1391a67127dc106 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 26 May 2020 14:00:17 -0400 Subject: [PATCH 11/24] testing removed --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 3 --- 1 file changed, 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 68acdfb7..76d8cdd9 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -26,9 +26,6 @@ open class LoadingSpinner: View { override open func setupView() { super.setupView() - - // TODO: remove - pinWidthAndHeight(radius: 20) } override open var layer: CAShapeLayer { From bc9b54c1d19fd407bd134728e71add0c2f1aacd4 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 26 May 2020 14:21:49 -0400 Subject: [PATCH 12/24] design --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 76d8cdd9..a1238552 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -41,7 +41,7 @@ open class LoadingSpinner: View { layer.fillColor = nil layer.strokeColor = strokeColor.cgColor layer.lineWidth = lineWidth - layer.lineCap = .round + layer.lineCap = .butt layer.speed = speed let halfWidth = lineWidth / 2 let radius = (bounds.width - lineWidth) / 2 From 53660f17b975fd12b55e81dbf932fde486b1715d Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 26 May 2020 14:28:09 -0400 Subject: [PATCH 13/24] unsused func --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 4 ---- 1 file changed, 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index a1238552..17be8ba2 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -24,10 +24,6 @@ open class LoadingSpinner: View { // MARK: - Lifecycle //-------------------------------------------------- - override open func setupView() { - super.setupView() - } - override open var layer: CAShapeLayer { get { return super.layer as! CAShapeLayer } } From e4384066ae1615e36f1d5cefa6e20314a9e52a8a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 15 Jun 2020 11:36:42 -0400 Subject: [PATCH 14/24] opening diameter for dev --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 38 ++++++++++++++----- .../Atoms/Views/LoadingSpinnerModel.swift | 4 ++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 17be8ba2..b3224f68 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -19,6 +19,13 @@ open class LoadingSpinner: View { public var lineWidth: CGFloat = 3.0 public var speed: Float = 1.5 + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + + public var heightConstraint: NSLayoutConstraint? + public var widthConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Lifecycle @@ -41,8 +48,19 @@ open class LoadingSpinner: View { 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 - + layer.path = UIBezierPath(arcCenter: CGPoint(x: radius + halfWidth, + y: radius + halfWidth), + radius: radius, + startAngle: -CGFloat.pi / 2, + endAngle: 2 * CGFloat.pi, + clockwise: true).cgPath + } + + public override func reset() { + super.reset() + + heightConstraint?.isActive = false + widthConstraint?.isActive = false } //-------------------------------------------------- @@ -152,14 +170,12 @@ open class LoadingSpinner: View { layer.removeAllAnimations() } - func pinWidthAndHeight(radius: CGFloat) { + func pinWidthAndHeight(diameter: CGFloat) { - let diameter: CGFloat = radius * 2 + lineWidth - - NSLayoutConstraint.activate([ - heightAnchor.constraint(equalToConstant: diameter), - widthAnchor.constraint(equalToConstant: diameter) - ]) + heightConstraint = heightAnchor.constraint(equalToConstant: diameter + lineWidth) + widthConstraint = widthAnchor.constraint(equalToConstant: diameter + lineWidth) + heightConstraint?.isActive = true + widthConstraint?.isActive = true } //-------------------------------------------------- @@ -172,6 +188,10 @@ open class LoadingSpinner: View { strokeColor = model.strokeColor.uiColor lineWidth = model.lineWidth + + if let diameter = model.diameter { + pinWidthAndHeight(diameter: diameter) + } } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift index 604c0689..ef299d46 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift @@ -18,6 +18,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { public static var identifier: String = "loadingSpinner" public var strokeColor = Color(uiColor: .mvmBlack) public var lineWidth: CGFloat = 3 + public var diameter: CGFloat? //-------------------------------------------------- // MARK: - Keys @@ -28,6 +29,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { case backgroundColor case strokeColor case lineWidth + case diameter } //-------------------------------------------------- @@ -38,6 +40,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) if let strokeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .strokeColor) { self.strokeColor = strokeColor @@ -52,6 +55,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { 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) } From a03b50865f1c6af3400f29e2de3aa7be687caabd Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 19 Jun 2020 10:58:59 -0400 Subject: [PATCH 15/24] default dimension --- .../Atomic/Atoms/Views/LoadingSpinner.swift | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index b3224f68..7f7007b2 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -26,7 +26,7 @@ open class LoadingSpinner: View { public var heightConstraint: NSLayoutConstraint? public var widthConstraint: NSLayoutConstraint? - + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -39,6 +39,13 @@ open class LoadingSpinner: View { 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 @@ -172,8 +179,9 @@ open class LoadingSpinner: View { func pinWidthAndHeight(diameter: CGFloat) { - heightConstraint = heightAnchor.constraint(equalToConstant: diameter + lineWidth) - widthConstraint = widthAnchor.constraint(equalToConstant: diameter + lineWidth) + let dimension = diameter + lineWidth + heightConstraint?.constant = dimension + widthConstraint?.constant = dimension heightConstraint?.isActive = true widthConstraint?.isActive = true } @@ -188,10 +196,7 @@ open class LoadingSpinner: View { strokeColor = model.strokeColor.uiColor lineWidth = model.lineWidth - - if let diameter = model.diameter { - pinWidthAndHeight(diameter: diameter) - } + pinWidthAndHeight(diameter: model.diameter ?? 40) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { From 572968f19383acfd042aaaf64cc0171aeec44592 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 19 Jun 2020 10:59:53 -0400 Subject: [PATCH 16/24] default dimension --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 7f7007b2..36476a68 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -20,6 +20,8 @@ open class LoadingSpinner: View { public var speed: Float = 1.5 + public var defaultDimension: CGFloat = 40 + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -196,7 +198,7 @@ open class LoadingSpinner: View { strokeColor = model.strokeColor.uiColor lineWidth = model.lineWidth - pinWidthAndHeight(diameter: model.diameter ?? 40) + pinWidthAndHeight(diameter: model.diameter ?? defaultDimension) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { From 77c6396034981c278a9efbb5d927728f34e7ad25 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 19 Jun 2020 11:17:02 -0400 Subject: [PATCH 17/24] default --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 4 +--- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 36476a68..bfc47613 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -20,8 +20,6 @@ open class LoadingSpinner: View { public var speed: Float = 1.5 - public var defaultDimension: CGFloat = 40 - //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -198,7 +196,7 @@ open class LoadingSpinner: View { strokeColor = model.strokeColor.uiColor lineWidth = model.lineWidth - pinWidthAndHeight(diameter: model.diameter ?? defaultDimension) + pinWidthAndHeight(diameter: model.diameter) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift index ef299d46..aab510a4 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift @@ -18,7 +18,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { public static var identifier: String = "loadingSpinner" public var strokeColor = Color(uiColor: .mvmBlack) public var lineWidth: CGFloat = 3 - public var diameter: CGFloat? + public var diameter: CGFloat = 40 //-------------------------------------------------- // MARK: - Keys @@ -40,7 +40,10 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - diameter = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .diameter) + + 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 From a826ce96c0973be228e35ebbd9311fbb203b3f35 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 25 Jun 2020 16:16:26 -0400 Subject: [PATCH 18/24] update width of line --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift index aab510a4..bdef3c86 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinnerModel.swift @@ -17,7 +17,7 @@ open class LoadingSpinnerModel: MoleculeModelProtocol { public var backgroundColor: Color? public static var identifier: String = "loadingSpinner" public var strokeColor = Color(uiColor: .mvmBlack) - public var lineWidth: CGFloat = 3 + public var lineWidth: CGFloat = 4 public var diameter: CGFloat = 40 //-------------------------------------------------- From 55af2346eb99d458993303868ea377163466cbfb Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 25 Jun 2020 16:16:47 -0400 Subject: [PATCH 19/24] update width of line --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index bfc47613..ae9cce75 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -16,7 +16,7 @@ open class LoadingSpinner: View { public var strokeColor: UIColor = .mvmBlack - public var lineWidth: CGFloat = 3.0 + public var lineWidth: CGFloat = 4.0 public var speed: Float = 1.5 From a09927aba9386a4fc5fc727d4dfe8d6d32c47f97 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Jul 2020 11:07:44 -0400 Subject: [PATCH 20/24] remvoe as it is already 0 when arriving --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index ae9cce75..044df666 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -167,7 +167,6 @@ open class LoadingSpinner: View { isHidden = false layer.speed = speed layer.timeOffset = 0 - layer.beginTime = 0 let timeSincePause = layer.convertTime(CACurrentMediaTime(), from: nil) - pausedTime layer.beginTime = timeSincePause } @@ -197,6 +196,7 @@ open class LoadingSpinner: View { strokeColor = model.strokeColor.uiColor lineWidth = model.lineWidth pinWidthAndHeight(diameter: model.diameter) + resumeSpinnerAfterDelay() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { From a3ddadf14cd8464f65c521ea66b69f1fa7e0461a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Jul 2020 11:24:04 -0400 Subject: [PATCH 21/24] comment --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 044df666..7672329c 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -87,7 +87,7 @@ open class LoadingSpinner: View { let length: CGFloat } - // TODO: This needs more attention + // TODO: This needs more attention to improve frame smoothness. class var poses: [Pose] { get { return [ From 53764d363ab3ca2c9a8f00378fcaa64e1a5d76ef Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Jul 2020 14:30:11 -0400 Subject: [PATCH 22/24] removed for testing --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 7672329c..60abec3c 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -196,7 +196,6 @@ open class LoadingSpinner: View { strokeColor = model.strokeColor.uiColor lineWidth = model.lineWidth pinWidthAndHeight(diameter: model.diameter) - resumeSpinnerAfterDelay() } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { From 027b9c9930a18482bdf9ac7a3a1a0025e72ebfaf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Jul 2020 14:52:30 -0400 Subject: [PATCH 23/24] reuse and rotate --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 60abec3c..9bb6ff91 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -48,6 +48,7 @@ open class LoadingSpinner: View { override open func layoutSubviews() { super.layoutSubviews() +// layer.fillColor = nil layer.strokeColor = strokeColor.cgColor layer.lineWidth = lineWidth @@ -63,9 +64,17 @@ open class LoadingSpinner: View { 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 } From 75c26b21f5074af4524cdf32e641476f05d50d9e Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Jul 2020 14:55:29 -0400 Subject: [PATCH 24/24] emwovw --- MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift index 9bb6ff91..2d58c8f4 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/LoadingSpinner.swift @@ -48,7 +48,7 @@ open class LoadingSpinner: View { override open func layoutSubviews() { super.layoutSubviews() -// + layer.fillColor = nil layer.strokeColor = strokeColor.cgColor layer.lineWidth = lineWidth