diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 5855f95f..104eef80 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -602,6 +602,7 @@ EA985C852981AA9C00F2FF2E /* VDS-Enums+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */; }; EA985C872981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */; }; EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */; }; + EA985C8B2983259900F2FF2E /* VDS-LabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C8A2983259900F2FF2E /* VDS-LabelAttributeModel.swift */; }; EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */; }; EAA0CFB1275E823A00D65EB0 /* HideFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */; }; EAA0CFB3275E831E00D65EB0 /* DisableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */; }; @@ -1212,6 +1213,7 @@ EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Enums+Codable.swift"; sourceTree = ""; }; EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Tilelet+Codable.swift"; sourceTree = ""; }; EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-TextStyle.swift"; sourceTree = ""; }; + EA985C8A2983259900F2FF2E /* VDS-LabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-LabelAttributeModel.swift"; sourceTree = ""; }; EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormFieldEffectProtocol.swift; sourceTree = ""; }; EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideFormFieldEffectModel.swift; sourceTree = ""; }; EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableFormFieldEffectModel.swift; sourceTree = ""; }; @@ -1626,6 +1628,7 @@ EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */, EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */, EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */, + EA985C8A2983259900F2FF2E /* VDS-LabelAttributeModel.swift */, ); path = Extensions; sourceTree = ""; @@ -2992,6 +2995,7 @@ FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */, BBC0C4FD24811DBC0087C44F /* Tag.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, + EA985C8B2983259900F2FF2E /* VDS-LabelAttributeModel.swift in Sources */, 944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */, D2E2A99623D8CF85000B42E6 /* HeadlineBodyLinkToggleModel.swift in Sources */, C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Extensions/VDS-LabelAttributeModel.swift b/MVMCoreUI/Atomic/Extensions/VDS-LabelAttributeModel.swift new file mode 100644 index 00000000..4eab03b2 --- /dev/null +++ b/MVMCoreUI/Atomic/Extensions/VDS-LabelAttributeModel.swift @@ -0,0 +1,205 @@ +// +// VDS-LabelAttributeModel.swift +// MVMCoreUI +// +// Created by Matt Bruce on 1/26/23. +// Copyright © 2023 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS +import Combine + +//Meant to be used to convert Any Array of type LabelAttributeModel +extension Array where Element: MVMCoreUI.LabelAttributeModel { + public func toVDSLabelAttributeModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> [any VDS.LabelAttributeModel] { + var attributes: [any VDS.LabelAttributeModel] = [] + forEach { atomicLabelAttribute in + if let attr = atomicLabelAttribute as? (any VDSLabelAttributeConvertable), + let vds = attr.convertToVDSLabelAttirbute(delegateObject: delegateObject, + additionalData: additionalData){ + attributes.append(vds) + } + } + return attributes + } +} + +//VDS Convertable Protocol and Extensions +public protocol VDSLabelAttributeConvertable { + associatedtype LabelAttributeType: VDS.LabelAttributeModel + func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> LabelAttributeType? +} + +extension LabelAttributeUnderlineModel: VDSLabelAttributeConvertable { + + public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> UnderlineLabelAttribute? { + guard let style = UnderlineLabelAttribute.Style(rawValue: style.rawValue) else { return nil } + + var pattern: UnderlineLabelAttribute.Pattern? + if let attrPattern = pattern { + pattern = UnderlineLabelAttribute.Pattern(rawValue: attrPattern.rawValue) + } + + return VDS.UnderlineLabelAttribute(location: location, + length: length, + style: style, + color: color?.uiColor, + pattern: pattern) + } +} + +extension LabelAttributeActionModel: VDSLabelAttributeConvertable { + public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> ActionLabelAttribute? { + var vdsAttribute = VDS.ActionLabelAttribute(location: location, length: length) + vdsAttribute.subscriber = vdsAttribute.action.sink { [weak self] in + guard let self else { return } + MVMCoreUIActionHandler.performActionUnstructured(with: self.action, + sourceModel: nil, + additionalData: additionalData, + delegateObject: delegateObject) + } + return vdsAttribute + } +} + +extension LabelAttributeFontModel: VDSLabelAttributeConvertable { + public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> TextStyleLabelAttribute? { + + var textStyle: TextStyle? + if let found = style?.vdsTextStyle() { + textStyle = found + } else if let name, let found = TextStyle(rawValue: name) { + textStyle = found + } + + guard let textStyle else { return nil } + + return TextStyleLabelAttribute(location: location, + length: length, + textStyle: textStyle) + } +} + +extension LabelAttributeColorModel: VDSLabelAttributeConvertable { + public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> ColorLabelAttribute? { + guard let textColor else { return nil } + return ColorLabelAttribute(location: location, + length: length, + color: textColor.uiColor) + } +} + +extension LabelAttributeStrikeThroughModel: VDSLabelAttributeConvertable { + public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> StrikeThroughLabelAttribute? { + return StrikeThroughLabelAttribute(location: location, + length: length) + } +} + +extension LabelAttributeImageModel: VDSLabelAttributeConvertable { + public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> AtomicImageLabelAttribute? { + var frame: CGRect? + if let size { + frame = CGRect(x: 0, y: 0, width: size, height: size) + } + return AtomicImageLabelAttribute(location: location, + length: length, + imageName: name, + imageURL: URL, + frame: frame, + tintColor: tintColor?.uiColor) + } +} + +//Custom Atomic Additions for the ImageAttachment +public class AtomicImageLabelAttribute: AttachmentLabelAttributeModel { + //-------------------------------------------------- + // MARK: - Enums + //-------------------------------------------------- + public enum Error: Swift.Error { + case bundleNotFound + case imageNotFound(String) + case imageNotSet + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + public var id = UUID() + public var location: Int + public var length: Int = 1 + public var imageName: String? + public var imageURL: String? + public var image: UIImage? + public var frame: CGRect? + public var tintColor: UIColor? + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + public init(location: Int, length: Int = 1, imageName: String? = nil, imageURL: String? = nil, + image: UIImage? = nil, frame: CGRect? = nil, tintColor: UIColor?) { + self.location = location + self.length = length + self.imageName = imageName + self.imageURL = imageURL + self.image = image + self.frame = frame + self.tintColor = tintColor + fetchImage() + } + + //-------------------------------------------------- + // MARK: - Equatable + //-------------------------------------------------- + public static func == (lhs: AtomicImageLabelAttribute, rhs: AtomicImageLabelAttribute) -> Bool { + lhs.isEqual(rhs) + } + + public func isEqual(_ equatable: AtomicImageLabelAttribute) -> Bool { + return id == equatable.id && range == equatable.range && imageName == equatable.imageName && imageURL == equatable.imageURL + } + + //-------------------------------------------------- + // MARK: - Private Functions + //-------------------------------------------------- + private func fetchImage() { + if image != nil { return } + + //get a local asset + if let imageName { + if let coreImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(imageName) { + image = coreImage + } + + if let vdsImage = BundleManager.shared.image(for: imageName) { + image = vdsImage + } + }//get from url + else if let imageURL { + DispatchQueue.global(qos: .default).async { + MVMCoreCache.shared()?.getImage(imageURL, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, localFallbackImageName: nil) { [weak self] image, data, _ in + DispatchQueue.main.sync { + self?.image = image + } + } + } + } + } + + //-------------------------------------------------- + // MARK: - Public Functions + //-------------------------------------------------- + public func getAttachment() throws -> NSTextAttachment { + if let image { + let attachment = NSTextAttachment() + attachment.image = tintColor != nil ? image.withTintColor(tintColor!) : image + attachment.bounds = frame ?? .init(x: 0, y: 0, width: image.size.width, height: image.size.height) + return attachment + } else { + throw Error.imageNotSet + } + } +} +