diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 569b13cb..0b5aea33 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -575,6 +575,8 @@ EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; }; EA6E8B952B504A43000139B4 /* ButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6E8B942B504A43000139B4 /* ButtonGroup.swift */; }; EA6E8B972B504A4D000139B4 /* ButtonGroupModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA6E8B962B504A4D000139B4 /* ButtonGroupModel.swift */; }; + EA7D81602B2B6E6800D29F9E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D815F2B2B6E6800D29F9E /* Icon.swift */; }; + EA7D81622B2B6E7F00D29F9E /* IconModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D81612B2B6E7F00D29F9E /* IconModel.swift */; }; EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */; }; EA7E67762758365300ABF773 /* UIUpdatableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */; }; EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3D2970938F00F2FF2E /* Tilelet.swift */; }; @@ -1169,6 +1171,8 @@ EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = ""; }; EA6E8B942B504A43000139B4 /* ButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroup.swift; sourceTree = ""; }; EA6E8B962B504A4D000139B4 /* ButtonGroupModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupModel.swift; sourceTree = ""; }; + EA7D815F2B2B6E6800D29F9E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; + EA7D81612B2B6E7F00D29F9E /* IconModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconModel.swift; sourceTree = ""; }; EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableFormFieldEffectModel.swift; sourceTree = ""; }; EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUpdatableModelProtocol.swift; sourceTree = ""; }; EA985C3D2970938F00F2FF2E /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = ""; }; @@ -2246,6 +2250,8 @@ B4CC8FBC29DF34680005D28B /* Badge.swift */, EA985C3F2970939A00F2FF2E /* TileletModel.swift */, EA985C3D2970938F00F2FF2E /* Tilelet.swift */, + EA7D81612B2B6E7F00D29F9E /* IconModel.swift */, + EA7D815F2B2B6E6800D29F9E /* Icon.swift */, ); path = Views; sourceTree = ""; @@ -2967,6 +2973,7 @@ C7F8012123E8303200396FBD /* ListRVWheel.swift in Sources */, BB2C968F24330EA7006FF80C /* ListRightVariableTextLinkAllTextAndLinksModel.swift in Sources */, D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */, + EA7D81622B2B6E7F00D29F9E /* IconModel.swift in Sources */, 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */, BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */, 8DEFA95E243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift in Sources */, @@ -3138,6 +3145,7 @@ D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */, BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */, C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, + EA7D81602B2B6E6800D29F9E /* Icon.swift in Sources */, D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */, D2B9D0E4265EEE9D0084735C /* MoleculeListProtocol.swift in Sources */, D29C559625C099630082E7D6 /* VideoDataManager.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Views/Icon.swift b/MVMCoreUI/Atomic/Atoms/Views/Icon.swift new file mode 100644 index 00000000..a01c6b12 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/Icon.swift @@ -0,0 +1,60 @@ +// +// Icon.swift +// MVMCoreUI +// +// Created by Matt Bruce on 12/14/23. +// Copyright © 2023 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS + +/** + This class expects its height and width to be equal. + */ +open class Icon: VDS.Icon, VDSMoleculeViewProtocol{ + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public var viewModel: IconModel! + public var delegateObject: MVMCoreUIDelegateObject? + public var additionalData: [AnyHashable: Any]? + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public convenience required init() { + self.init(frame: .zero) + } + + //-------------------------------------------------- + // MARK: - Public + //-------------------------------------------------- + public func viewModelDidUpdate() { + surface = viewModel.surface + color = viewModel.color.uiColor + size = viewModel.size + customSize = viewModel.customSize + name = viewModel.name + } + + //-------------------------------------------------- + // MARK: - MVMCoreViewProtocol + //-------------------------------------------------- + open func updateView(_ size: CGFloat) {} + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + //since this is a class func, we can't reference it directly + public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + VDS.Icon.Size.medium.dimensions.height + } +} + +extension Icon: MVMCoreUIViewConstrainingProtocol { + + public func needsToBeConstrained() -> Bool { true } + + public func horizontalAlignment() -> UIStackView.Alignment { .leading } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift b/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift new file mode 100644 index 00000000..a1339cf3 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift @@ -0,0 +1,38 @@ +// +// IconModel.swift +// MVMCoreUI +// +// Created by Matt Bruce on 12/14/23. +// Copyright © 2023 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS +import VDSColorTokens + +open class IconModel: MoleculeModelProtocol { + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "icon" + + @DecodableDefault.UUIDString public var id: String + + public var backgroundColor: Color? + + /// A representation that will be used to render the icon with corresponding name. + public var name: Icon.Name + + /// Color of the icon. + @DecodableDefault.BlackColor() public var color: Color + + /// Enum for a preset height and width for the icon. + @DecodableDefault.IconSize public var size: VDS.Icon.Size + + /// surface of the object + @DecodableDefault.Surface public var surface: VDS.Surface + + /// A custom size of the icon. + public var customSize: Int? +} diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index 974fe33d..20a13fb4 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -8,6 +8,11 @@ import Foundation import VDS +import VDSColorTokens + +//-------------------------------------------------- +// MARK: - Codable Extensions +//-------------------------------------------------- extension VDS.Surface: Codable {} extension VDS.Badge.FillColor: Codable {} @@ -30,3 +35,26 @@ extension VDS.Button.Size: RawRepresentableCodable { public static var mapping: [String : VDS.Button.Size] { ["standard": .large, "tiny": .small] } public static var defaultValue: VDS.Button.Size? { nil } } + +//-------------------------------------------------- +// MARK: - Decodable Defaults +//-------------------------------------------------- +extension DecodableDefault.Sources { + public struct Surface: DecodableDefaultSource { + public static var defaultValue: VDS.Surface { .light } + } + + public struct IconSize: DecodableDefaultSource { + public static var defaultValue: VDS.Icon.Size { .medium } + } + + public struct BlackColor: DecodableDefaultSource { + public static var defaultValue: Color { .init(uiColor: VDSColor.paletteBlack) } + } +} + +extension DecodableDefault { + public typealias IconSize = Wrapper + public typealias BlackColor = Wrapper + public typealias Surface = Wrapper +} diff --git a/MVMCoreUI/CustomPrimitives/Color.swift b/MVMCoreUI/CustomPrimitives/Color.swift index b251f778..9245153d 100644 --- a/MVMCoreUI/CustomPrimitives/Color.swift +++ b/MVMCoreUI/CustomPrimitives/Color.swift @@ -84,10 +84,17 @@ public final class Color: Codable { required public init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() let colorString = try container.decode(String.self) - let components = try Color.getColorComponents(for: colorString) - self.uiColor = components.color - hex = components.hex - name = components.name ?? "" + + if let vdsColor = UIColor.VDSColor(rawValue: colorString) { + self.uiColor = vdsColor.uiColor + hex = uiColor.hexString ?? "" + } else { + let components = try Color.getColorComponents(for: colorString) + self.uiColor = components.color + hex = components.hex + name = components.name ?? "" + } + determineRGBA() } diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 8b3d5529..b10742ab 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: Icon.self, for: IconModel.self) // MARK:- Horizontal Combination Molecules ModelRegistry.register(handler: StringAndMoleculeView.self, for: StringAndMoleculeModel.self)