diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 038ecb6c..6a08a82b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -174,8 +174,6 @@ 5870636F2ACF238E00CA18D5 /* ReadableDecodingErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */; }; 58A9DD7D2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */; }; 608211282AC6B57E00C3FC39 /* MVMCoreUILoggingHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 608211262AC6AF8200C3FC39 /* MVMCoreUILoggingHandler.swift */; }; - 7199C8162A4F3A64001568B7 /* AccessibilityHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7199C8152A4F3A64001568B7 /* AccessibilityHandler.swift */; }; - 71BE969E2AD96BE6000B5DB7 /* RotorHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BE969D2AD96BE6000B5DB7 /* RotorHandler.swift */; }; 8D070BB0241B56530099AC56 /* ListRightVariableTotalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */; }; 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; }; 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; }; @@ -575,6 +573,8 @@ DBEFFA04225A829700230692 /* Label.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB891E822253FA8500022516 /* Label.swift */; }; EA05EFA9278DDE2C00828819 /* ClearFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */; }; EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */; }; + EA1758482BC97ED800A5C0D9 /* BadgeIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */; }; + EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */; }; EA41F4AC2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */; }; EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */; }; EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; }; @@ -777,8 +777,6 @@ 5870636E2ACF238E00CA18D5 /* ReadableDecodingErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReadableDecodingErrors.swift; sourceTree = ""; }; 58A9DD7C2AC2103300F5E0B0 /* ReplaceableMoleculeBehaviorModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReplaceableMoleculeBehaviorModel.swift; sourceTree = ""; }; 608211262AC6AF8200C3FC39 /* MVMCoreUILoggingHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MVMCoreUILoggingHandler.swift; sourceTree = ""; }; - 7199C8152A4F3A64001568B7 /* AccessibilityHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityHandler.swift; sourceTree = ""; }; - 71BE969D2AD96BE6000B5DB7 /* RotorHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RotorHandler.swift; sourceTree = ""; }; 8D070BAF241B56530099AC56 /* ListRightVariableTotalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalDataModel.swift; sourceTree = ""; }; 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = ""; }; 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = ""; }; @@ -1179,6 +1177,8 @@ DBC4391A224421A0001AB423 /* CaretLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CaretLink.swift; sourceTree = ""; }; EA05EFA8278DDE2C00828819 /* ClearFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearFormFieldEffectModel.swift; sourceTree = ""; }; EA05EFAA278DE53600828819 /* ClearableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ClearableModelProtocol.swift; sourceTree = ""; }; + EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicator.swift; sourceTree = ""; }; + EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BadgeIndicatorModel.swift; sourceTree = ""; }; EA41F4AB2787927100F5B377 /* DynamicRuleFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DynamicRuleFormFieldEffectModel.swift; sourceTree = ""; }; EA5124FC243601600051A3A4 /* BGImageHeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButton.swift; sourceTree = ""; }; EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = ""; }; @@ -2268,6 +2268,8 @@ AA07EA922510A451009A2AE3 /* Star.swift */, B4CC8FBE29DF34730005D28B /* BadgeModel.swift */, B4CC8FBC29DF34680005D28B /* Badge.swift */, + EA1758492BC97EF100A5C0D9 /* BadgeIndicatorModel.swift */, + EA1758472BC97ED800A5C0D9 /* BadgeIndicator.swift */, EA985C3F2970939A00F2FF2E /* TileletModel.swift */, EA985C3D2970938F00F2FF2E /* Tilelet.swift */, EA7D81612B2B6E7F00D29F9E /* IconModel.swift */, @@ -2684,6 +2686,7 @@ D29B771022C281F400D6ACE0 /* ModuleMolecule.swift in Sources */, AAE96FA225341F6A0037A989 /* ListStoreLocatorModel.swift in Sources */, D28A838923CCCFCB00DFE4FC /* LinkModel.swift in Sources */, + EA17584A2BC97EF100A5C0D9 /* BadgeIndicatorModel.swift in Sources */, AA56A20F243C5EE900303286 /* ListTwoColumnSubsectionDividerModel.swift in Sources */, AAB9C10824346F4B00151545 /* RadioSwatches.swift in Sources */, 94C2D9A923872E5E0006CF46 /* LabelAttributeImageModel.swift in Sources */, @@ -2989,6 +2992,7 @@ D264FAAC2441009400D98315 /* RadioBoxCollectionViewCell.swift in Sources */, BB2C969224330F73006FF80C /* ListRightVariableTextLinkAllTextAndLinks.swift in Sources */, D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */, + EA1758482BC97ED800A5C0D9 /* BadgeIndicator.swift in Sources */, 012A88B1238C880100FE3DA1 /* CarouselPagingModelProtocol.swift in Sources */, 0A9D091E2433796500D2E6C0 /* NumericCarouselIndicatorModel.swift in Sources */, D29DF2C921E7BFC6003B2FB9 /* MFSizeObject.m in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Views/BadgeIndicator.swift b/MVMCoreUI/Atomic/Atoms/Views/BadgeIndicator.swift new file mode 100644 index 00000000..3eb78919 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/BadgeIndicator.swift @@ -0,0 +1,70 @@ +// +// BadgeIndicator.swift +// MVMCoreUI +// +// Created by Matt Bruce on 4/12/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS + +open class BadgeIndicator: VDS.BadgeIndicator, VDSMoleculeViewProtocol { + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + public var viewModel: BadgeIndicatorModel! + + public var delegateObject: MVMCoreUIDelegateObject? + + public var additionalData: [AnyHashable : Any]? + + //-------------------------------------------------- + // MARK: - Public Methods + //-------------------------------------------------- + + public func viewModelDidUpdate() { + surface = viewModel.surface + number = viewModel.number + fillColor = viewModel.fillColor + borderColorLight = viewModel.borderColorLight?.uiColor + borderColorDark = viewModel.borderColorDark?.uiColor + kind = viewModel.kind + maximumDigits = viewModel.maximumDigits + size = viewModel.size + leadingCharacter = viewModel.leadingCharacter + trailingText = viewModel.trailingText + dotSize = viewModel.dotSize + verticalPadding = viewModel.verticalPadding + horizontalPadding = viewModel.horizontalPadding + hideDot = viewModel.hideDot + hideBorder = viewModel.hideBorder + width = viewModel.width + height = viewModel.height + } + + public func updateView(_ size: CGFloat) {} + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + open override func updateAccessibility() { + super.updateAccessibility() + + if let viewModel { + if let accessibilityText = viewModel.accessibilityText { + self.accessibilityLabel = accessibilityText + } + } + } + +} + +//to deal with how it's parent constrains this control +extension BadgeIndicator: MVMCoreUIViewConstrainingProtocol { + + public func needsToBeConstrained() -> Bool { true } + + public func horizontalAlignment() -> UIStackView.Alignment { .leading } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/BadgeIndicatorModel.swift b/MVMCoreUI/Atomic/Atoms/Views/BadgeIndicatorModel.swift new file mode 100644 index 00000000..059f4c7f --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/BadgeIndicatorModel.swift @@ -0,0 +1,111 @@ +// +// BadgeIndicatorModel.swift +// MVMCoreUI +// +// Created by Matt Bruce on 4/12/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS + + +open class BadgeIndicatorModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "badgeIndicator" + public var id: String = UUID().uuidString + public var backgroundColor: Color? + + //-------------------------------------------------- + // MARK: - VDS Properties + //-------------------------------------------------- + public var surface: Surface { inverted ? .dark : .light } + public var inverted: Bool = false + public var number: Int? + public var accessibilityText: String? + public var fillColor = BadgeIndicator.FillColor.red + public var borderColorLight: Color? + public var borderColorDark: Color? + public var kind = BadgeIndicator.Kind.simple + public var maximumDigits = BadgeIndicator.MaximumDigits.two + public var size = BadgeIndicator.Size.xxlarge + public var leadingCharacter: String? + public var trailingText: String? + public var dotSize: CGFloat? + public var verticalPadding: CGFloat? + public var horizontalPadding: CGFloat? + public var hideDot: Bool = false + public var hideBorder: Bool = false + public var width: CGFloat? + public var height: CGFloat? + + private enum CodingKeys: String, CodingKey { + case id + case inverted + case accessibilityText + case number + case fillColor + case borderColorLight + case borderColorDark + case kind + case maximumDigits + case size + case leadingCharacter + case trailingText + case dotSize + case verticalPadding + case horizontalPadding + case hideDot + case hideBorder + case width + case height + } + + required public convenience init(from decoder: Decoder) throws { + self.init() + let container = try decoder.container(keyedBy: CodingKeys.self) + id = try container.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString + inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false + accessibilityText = try container.decodeIfPresent(String.self, forKey: .accessibilityText) + number = try container.decodeIfPresent(Int.self, forKey: .number) + fillColor = try container.decodeIfPresent(BadgeIndicator.FillColor.self, forKey: .fillColor) ?? .red + borderColorLight = try container.decodeIfPresent(Color.self, forKey: .borderColorLight) + borderColorDark = try container.decodeIfPresent(Color.self, forKey: .borderColorDark) + kind = try container.decodeIfPresent(BadgeIndicator.Kind.self, forKey: .kind) ?? .simple + maximumDigits = try container.decodeIfPresent(BadgeIndicator.MaximumDigits.self, forKey: .maximumDigits) ?? .two + size = try container.decodeIfPresent(BadgeIndicator.Size.self, forKey: .size) ?? .xxlarge + leadingCharacter = try container.decodeIfPresent(String.self, forKey: .leadingCharacter) + trailingText = try container.decodeIfPresent(String.self, forKey: .trailingText) + dotSize = try container.decodeIfPresent(CGFloat.self, forKey: .dotSize) + verticalPadding = try container.decodeIfPresent(CGFloat.self, forKey: .verticalPadding) + horizontalPadding = try container.decodeIfPresent(CGFloat.self, forKey: .horizontalPadding) + hideDot = try container.decodeIfPresent(Bool.self, forKey: .hideDot) ?? false + hideBorder = try container.decodeIfPresent(Bool.self, forKey: .hideBorder) ?? false + width = try container.decodeIfPresent(CGFloat.self, forKey: .width) + height = try container.decodeIfPresent(CGFloat.self, forKey: .height) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(id, forKey: .id) + try container.encode(inverted, forKey: .inverted) + try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) + try container.encodeIfPresent(number, forKey: .number) + try container.encodeIfPresent(fillColor, forKey: .fillColor) + try container.encodeIfPresent(borderColorLight, forKey: .borderColorLight) + try container.encodeIfPresent(borderColorDark, forKey: .borderColorDark) + try container.encodeIfPresent(kind, forKey: .kind) + try container.encodeIfPresent(maximumDigits, forKey: .maximumDigits) + try container.encodeIfPresent(size, forKey: .size) + try container.encodeIfPresent(leadingCharacter, forKey: .leadingCharacter) + try container.encodeIfPresent(trailingText, forKey: .trailingText) + try container.encodeIfPresent(dotSize, forKey: .dotSize) + try container.encodeIfPresent(verticalPadding, forKey: .verticalPadding) + try container.encodeIfPresent(hideDot, forKey: .hideDot) + try container.encodeIfPresent(hideBorder, forKey: .hideBorder) + try container.encodeIfPresent(width, forKey: .width) + try container.encodeIfPresent(height, forKey: .height) + } +} diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index 9e524462..caed0f13 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -16,6 +16,10 @@ import VDSColorTokens extension VDS.Surface: Codable {} extension VDS.Badge.FillColor: Codable {} +extension VDS.BadgeIndicator.FillColor: Codable {} +extension VDS.BadgeIndicator.Kind: Codable {} +extension VDS.BadgeIndicator.MaximumDigits: Codable {} +extension VDS.BadgeIndicator.Size: Codable {} extension VDS.ButtonGroup.Alignment: Codable {} extension VDS.Icon.Name: Codable {} extension VDS.Icon.Size: Codable {} diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 6a14767e..c864acdb 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -74,6 +74,7 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(handler: Video.self, for: VideoModel.self) ModelRegistry.register(handler: Tilelet.self, for: TileletModel.self) ModelRegistry.register(handler: Badge.self, for: BadgeModel.self) + ModelRegistry.register(handler: BadgeIndicator.self, for: BadgeIndicatorModel.self) ModelRegistry.register(handler: Icon.self, for: IconModel.self) ModelRegistry.register(handler: Tooltip.self, for: TooltipModel.self)