diff --git a/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift b/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift index b41d9eef..7cc9747e 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift @@ -68,23 +68,35 @@ open class TileletModel: MoleculeModelProtocol { public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? { guard let title else { return nil } let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) - let style: TextStyle? = title.fontStyle?.vdsTextStyle() - if let style, let standardStyle = Tilelet.TitleModel.StandardStyle(rawValue: style.toStandardStyle().rawValue) { - return .init(text: title.text, textAttributes: attrs, standardStyle: standardStyle) - } else { - return .init(text: title.text, textAttributes: attrs) - } - } + + do { + if let style = title.fontStyle { + return .init(text: title.text, + textAttributes: attrs, + standardStyle: try style.vdsSubsetStyle()) + } + } catch MVMCoreError.errorObject(let object) { + MVMCoreLoggingHandler.shared()?.addError(toLog: object) + } catch { } + + return .init(text: title.text, textAttributes: attrs) + } + public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.SubTitleModel? { guard let subTitle else { return nil } let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) - let style: TextStyle? = subTitle.fontStyle?.vdsTextStyle() - if let style, let standardStyle = Tilelet.SubTitleModel.StandardStyle(rawValue: style.toStandardStyle().rawValue) { - return .init(text: subTitle.text, textAttributes: attrs, standardStyle: standardStyle) - } else { - return .init(text: subTitle.text, textAttributes: attrs) - } + do { + if let style = subTitle.fontStyle { + return .init(text: subTitle.text, + otherStandardStyle: try style.vdsSubsetStyle(), + textAttributes: attrs) + } + } catch MVMCoreError.errorObject(let object) { + MVMCoreLoggingHandler.shared()?.addError(toLog: object) + } catch { } + + return .init(text: subTitle.text, textAttributes: attrs) } public func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift index 6a9cc598..b0ca7300 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift @@ -28,6 +28,7 @@ extension VDS.TextLinkCaret.IconPosition: Codable {} extension VDS.TileContainer.BackgroundColor: Codable {} extension VDS.TileContainer.Padding: Codable {} extension VDS.TileContainer.AspectRatio: Codable {} +extension VDS.TitleLockup.TextAlignment: Codable {} extension VDS.Tooltip.FillColor: Codable {} extension VDS.Tooltip.Size: Codable {} extension VDS.Line.Style: Codable {} diff --git a/MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift b/MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift index f1fc1794..6da79f1f 100644 --- a/MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift +++ b/MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift @@ -18,14 +18,16 @@ extension Styler.Font { return style } - public func vdsSubsetStyle() -> T? { - guard let style = vdsTextStyle() else { return nil } - guard let rawValue = style.rawValue as? T.RawValue, - let found = T(rawValue: rawValue) else { - print("Style: \(style.rawValue) is not in enum \(T.self)\ronly these cases exist:\r\(T.allCases)") - return nil + public func vdsSubsetStyle() throws -> T { + guard let style = vdsTextStyle(), let rawValue = style.toStandardStyle().rawValue as? T.RawValue, let standardStyle = T(rawValue: rawValue) else { + let err = "\(rawValue) was not found in the \(T.self), only these cases exist:\r\(T.allCases)" + throw MVMCoreError.errorObject(MVMCoreErrorObject(title: "\(T.self) conversion Issue", + messageToLog: err, + code: 999, + domain: ErrorDomainNative, + location: #file)!) } - return found + return standardStyle } private func mapped() -> Styler.Font { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockup.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockup.swift index b48e4ddb..6339b8e2 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockup.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockup.swift @@ -5,119 +5,43 @@ // Created by Nadigadda, Sumanth on 04/05/22. // Copyright © 2022 Verizon Wireless. All rights reserved. // +import VDS + +@objcMembers open class TitleLockup: VDS.TitleLockup, VDSMoleculeViewProtocol { -@objcMembers open class TitleLockup: View { //-------------------------------------------------- - // MARK: - Outlets + // MARK: - Public Properties //-------------------------------------------------- + open var viewModel: TitleLockupModel! + open var delegateObject: MVMCoreUIDelegateObject? + open var additionalData: [AnyHashable : Any]? - public let eyebrow = Label(fontStyle: .RegularBodySmall) - public let title = Label(fontStyle: .RegularBodySmall) - public let subTitle = Label(fontStyle: .RegularBodySmall) - public lazy var stack: UIStackView = { - let stack = UIStackView(arrangedSubviews: [eyebrow, title, subTitle]) - stack.translatesAutoresizingMaskIntoConstraints = false - stack.axis = .vertical - return stack - }() - - var castModel: TitleLockupModel? { - get { return model as? TitleLockupModel } + //-------------------------------------------------- + // MARK: - Public Functions + //-------------------------------------------------- + open func viewModelDidUpdate() { + surface = viewModel.surface + textAlignment = viewModel.textAlignment + eyebrowModel = viewModel.eyebrowModel(delegateObject: delegateObject, additionalData: additionalData) + titleModel = viewModel.titleModel(delegateObject: delegateObject, additionalData: additionalData) + subTitleModel = viewModel.subTitleModel(delegateObject: delegateObject, additionalData: additionalData) } - + //-------------------------------------------------- // MARK: - Initialization //-------------------------------------------------- - public convenience init() { + public convenience required init() { self.init(frame: .zero) } - //-------------------------------------------------- - // MARK: - MFViewProtocol - //-------------------------------------------------- - - open override func setupView() { - super.setupView() - addSubview(stack) - NSLayoutConstraint.constraintPinSubview(toSuperview: stack) - } - - open override func updateView(_ size: CGFloat) { - super.updateView(size) - stack.updateView(size) - } - //-------------------------------------------------- // MARK: - MoleculeViewProtocol //-------------------------------------------------- - - open override func reset() { - super.reset() - stack.reset() - } - - //-------------------------------------------------- - // MARK: - MoleculeViewProtocol - //-------------------------------------------------- - - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - super.set(with: model, delegateObject, additionalData) - guard let model = model as? TitleLockupModel else { return } - stack.setCustomSpacing(model.defaultEyebrowTitleSpacing(), after: eyebrow) - stack.setCustomSpacing(model.defaultTitleSubTitleSpacing(), after: title) - stack.updateContainedMolecules(with: [model.eyebrow, - model.title, - model.subTitle], - delegateObject, additionalData) - } - - open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { + open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { return 65 } - //-------------------------------------------------- - // MARK: - Accessibility Helpers - //-------------------------------------------------- - - /// Returns the labels text in one message. - func getAccessibilityMessage() -> String? { - - var message = "" - - if let eyebrowLabel = eyebrow.text { - message += eyebrowLabel + ", " - } - - if let headlineLabel = title.text { - message += headlineLabel + ", " - } - - if let bodyLabel = subTitle.text { - message += bodyLabel - } - - return message.count > 0 ? message : nil - } - - /// Returns an array of the appropriate accessibility elements. - func getAccessibilityElements() -> [Any]? { - - var elements: [UIView] = [] - - if eyebrow.hasText { - elements.append(eyebrow) - } - - if title.hasText { - elements.append(title) - } - - if subTitle.hasText { - elements.append(subTitle) - } - - return elements.count > 0 ? elements : nil - } + open func updateView(_ size: CGFloat) {} } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockupModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockupModel.swift index 89d32ca9..6c48398b 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockupModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/LockUps/TitleLockupModel.swift @@ -7,6 +7,7 @@ // import VDSColorTokens +import VDS public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol { @@ -18,47 +19,16 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco public var moleculeName: String = TitleLockupModel.identifier public var id: String = UUID().uuidString + public var textAlignment: TitleLockup.TextAlignment = .left public var eyebrow: LabelModel? public var title: LabelModel public var subTitle: LabelModel? + public var subTitleColor: Use = .primary - public var alignment: Alignment = .left { - didSet { - ///Updating the text alignment for all labels - if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) { - eyebrow?.textAlignment = textAlignment - title.textAlignment = textAlignment - subTitle?.textAlignment = textAlignment - } - } - } + public var alignment: VDS.TitleLockup.TextAlignment = .left + public var inverted: Bool = false - public var inverted: Bool = false { - didSet { - ///Updating the text color - eyebrow?.textColor = titleColor - title.textColor = titleColor - subTitle?.textColor = subTitleColor - } - } - - private var _backgroundColor: Color? - public var backgroundColor: Color? { - get { - return inverted ? Color(uiColor: VDSColor.backgroundPrimaryDark) : Color(uiColor: VDSColor.backgroundPrimaryLight) - } - set { - _backgroundColor = newValue - } - } - - public var titleColor: Color? { - return inverted ? Color(uiColor: VDSColor.elementsPrimaryOndark) : Color(uiColor: VDSColor.elementsPrimaryOnlight) - } - - public var subTitleColor: Color? { - return inverted ? Color(uiColor: VDSColor.elementsSecondaryOndark) : Color(uiColor: VDSColor.elementsSecondaryOnlight) - } + public var backgroundColor: Color? public var children: [MoleculeModelProtocol] { [eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule } @@ -72,58 +42,6 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco self.eyebrow = eyebrow self.title = title self.subTitle = subTitle - updateLabelAttributes() - } - - //-------------------------------------------------- - // MARK: - Enum - //-------------------------------------------------- - - public enum Alignment: String, Codable { - case left - case center - } - - //-------------------------------------------------- - // MARK: - Styling - //-------------------------------------------------- - - /// Returns the default fontStyle for the subtitle, based on the title fontStyle. - func defaultSubtitleFontStyle() -> Styler.Font { - switch title.fontStyle { - case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall: - return .RegularBodyLarge - case .RegularFeatureSmall, .RegularFeatureMedium: - return .RegularTitleLarge - default: - return .RegularBodySmall - } - } - - /// Returns the default spacing between the eyebrow and title, based on the title fontStyle. - func defaultEyebrowTitleSpacing() -> CGFloat { - switch title.fontStyle { - case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall: - return Padding.Three - case .RegularFeatureMedium: - return subTitle?.fontStyle == .RegularBodyLarge ? Padding.Three : Padding.Four - default: - return Padding.Two - } - } - - /// Returns the default spacing between the title and subTitle, based on the title fontStyle. - func defaultTitleSubTitleSpacing() -> CGFloat { - switch title.fontStyle { - case .RegularTitleXLarge: - return Padding.Three - case .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall: - return Padding.Four - case .RegularFeatureMedium: - return Padding.Five - default: - return Padding.Two - } } //-------------------------------------------------- @@ -133,10 +51,11 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco private enum CodingKeys: String, CodingKey { case id case moleculeName - case backgroundColor + case textAlignment case eyebrow case title case subTitle + case subTitleColor case inverted case alignment } @@ -148,72 +67,91 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString - title = try typeContainer.decodeMolecule(codingKey: .title) + textAlignment = try typeContainer.decodeIfPresent(TitleLockup.TextAlignment.self, forKey: .textAlignment) ?? .left + title = try typeContainer.decode(LabelModel.self, forKey: .title) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow) - subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle) - - if let newAlignment = try typeContainer.decodeIfPresent(Alignment.self, forKey: .alignment) { + subTitle = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .subTitle) + subTitleColor = try typeContainer.decodeIfPresent(Use.self, forKey: .subTitleColor) ?? .primary + + if let newAlignment = try typeContainer.decodeIfPresent(VDS.TitleLockup.TextAlignment.self, forKey: .alignment) { alignment = newAlignment } if let invertedStatus = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) { inverted = invertedStatus } - - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - - updateLabelAttributes() } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(id, forKey: .id) try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(textAlignment, forKey: .textAlignment) try container.encodeIfPresent(eyebrow, forKey: .eyebrow) try container.encodeModel(title, forKey: .title) try container.encodeIfPresent(subTitle, forKey: .subTitle) + try container.encode(subTitleColor, forKey: .subTitleColor) try container.encode(alignment, forKey: .alignment) try container.encode(inverted, forKey: .inverted) - try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor) } - //-------------------------------------------------- - // MARK: - Model updates - //-------------------------------------------------- + public func eyebrowModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.EyebrowModel? { + guard let eyebrow else { return nil } + let attrs = eyebrow.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) + do { + if let style = eyebrow.fontStyle { + return .init(text: eyebrow.text, + isBold: style.isBold(), + standardStyle: try style.vdsSubsetStyle(), + textAttributes: attrs, + numberOfLines: eyebrow.numberOfLines ?? 0) + } + } catch MVMCoreError.errorObject(let object) { + MVMCoreLoggingHandler.shared()?.addError(toLog: object) + } catch { } + + return .init(text: eyebrow.text, textAttributes: attrs, numberOfLines: eyebrow.numberOfLines ?? 0) + } + + public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.TitleModel { + let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) + do { + if let style = title.fontStyle { + return .init(text: title.text, + textAttributes: attrs, + isBold: style.isBold(), + standardStyle: try style.vdsSubsetStyle(), + numberOfLines: title.numberOfLines ?? 0) + } - private func updateLabelAttributes() { - // If subtitle style is not available, will set font style based on the component - if subTitle?.fontStyle == nil { - subTitle?.fontStyle = defaultSubtitleFontStyle() - } + } catch MVMCoreError.errorObject(let object) { + MVMCoreLoggingHandler.shared()?.addError(toLog: object) + } catch { } - // If eyebrow style is not available, will set font style based on the component. Eyebrow and subtitle share the same font size - if eyebrow?.fontStyle == nil { - eyebrow?.fontStyle = subTitle?.fontStyle - } + return .init(text: title.text, textAttributes: attrs, numberOfLines: title.numberOfLines ?? 0) + } + + public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.SubTitleModel? { + guard let subTitle else { return nil } + let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) - // Updating the text color - if eyebrow?.textColor == nil { - eyebrow?.textColor = subTitleColor - } - if title.textColor == nil { - title.textColor = titleColor - } - if subTitle?.textColor == nil { - subTitle?.textColor = subTitleColor - } - - // Updating the text alignment for all labels - if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) { - if eyebrow?.textAlignment == nil { - eyebrow?.textAlignment = textAlignment + do { + if let style = subTitle.fontStyle { + return .init(text: subTitle.text, + otherStandardStyle: try style.vdsSubsetStyle(), + textColor: subTitleColor, + textAttributes: attrs, + numberOfLines: subTitle.numberOfLines ?? 0) } - if title.textAlignment == nil { - title.textAlignment = textAlignment - } - if subTitle?.textAlignment == nil { - subTitle?.textAlignment = textAlignment - } - } + } catch MVMCoreError.errorObject(let object) { + MVMCoreLoggingHandler.shared()?.addError(toLog: object) + } catch { } + + return .init(text: subTitle.text, textColor: subTitleColor, textAttributes: attrs, numberOfLines: subTitle.numberOfLines ?? 0) + } } + +extension TitleLockupModel { + public var surface: Surface { inverted ? .dark : .light } +}