Merge branch 'feature/atomic_vds_titleLockup' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/vds_batch_three

# Conflicts:
#	MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-02-16 10:09:18 -06:00
commit e331f28ca6
5 changed files with 125 additions and 248 deletions

View File

@ -68,23 +68,35 @@ open class TileletModel: MoleculeModelProtocol {
public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? { public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? {
guard let title else { return nil } guard let title else { return nil }
let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) 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) { do {
return .init(text: title.text, textAttributes: attrs, standardStyle: standardStyle) if let style = title.fontStyle {
} else { return .init(text: title.text,
return .init(text: title.text, textAttributes: attrs) 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? { public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.SubTitleModel? {
guard let subTitle else { return nil } guard let subTitle else { return nil }
let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
let style: TextStyle? = subTitle.fontStyle?.vdsTextStyle() do {
if let style, let standardStyle = Tilelet.SubTitleModel.StandardStyle(rawValue: style.toStandardStyle().rawValue) { if let style = subTitle.fontStyle {
return .init(text: subTitle.text, textAttributes: attrs, standardStyle: standardStyle) return .init(text: subTitle.text,
} else { otherStandardStyle: try style.vdsSubsetStyle(),
return .init(text: subTitle.text, textAttributes: attrs) 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 { public func encode(to encoder: Encoder) throws {

View File

@ -28,6 +28,7 @@ extension VDS.TextLinkCaret.IconPosition: Codable {}
extension VDS.TileContainer.BackgroundColor: Codable {} extension VDS.TileContainer.BackgroundColor: Codable {}
extension VDS.TileContainer.Padding: Codable {} extension VDS.TileContainer.Padding: Codable {}
extension VDS.TileContainer.AspectRatio: Codable {} extension VDS.TileContainer.AspectRatio: Codable {}
extension VDS.TitleLockup.TextAlignment: Codable {}
extension VDS.Tooltip.FillColor: Codable {} extension VDS.Tooltip.FillColor: Codable {}
extension VDS.Tooltip.Size: Codable {} extension VDS.Tooltip.Size: Codable {}
extension VDS.Line.Style: Codable {} extension VDS.Line.Style: Codable {}

View File

@ -18,14 +18,16 @@ extension Styler.Font {
return style return style
} }
public func vdsSubsetStyle<T: EnumSubset>() -> T? { public func vdsSubsetStyle<T: EnumSubset>() throws -> T {
guard let style = vdsTextStyle() else { return nil } guard let style = vdsTextStyle(), let rawValue = style.toStandardStyle().rawValue as? T.RawValue, let standardStyle = T(rawValue: rawValue) else {
guard let rawValue = style.rawValue as? T.RawValue, let err = "\(rawValue) was not found in the \(T.self), only these cases exist:\r\(T.allCases)"
let found = T(rawValue: rawValue) else { throw MVMCoreError.errorObject(MVMCoreErrorObject(title: "\(T.self) conversion Issue",
print("Style: \(style.rawValue) is not in enum \(T.self)\ronly these cases exist:\r\(T.allCases)") messageToLog: err,
return nil code: 999,
domain: ErrorDomainNative,
location: #file)!)
} }
return found return standardStyle
} }
private func mapped() -> Styler.Font { private func mapped() -> Styler.Font {

View File

@ -5,119 +5,43 @@
// Created by Nadigadda, Sumanth on 04/05/22. // Created by Nadigadda, Sumanth on 04/05/22.
// Copyright © 2022 Verizon Wireless. All rights reserved. // 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) // MARK: - Public Functions
public let subTitle = Label(fontStyle: .RegularBodySmall) //--------------------------------------------------
public lazy var stack: UIStackView = { open func viewModelDidUpdate() {
let stack = UIStackView(arrangedSubviews: [eyebrow, title, subTitle]) surface = viewModel.surface
stack.translatesAutoresizingMaskIntoConstraints = false textAlignment = viewModel.textAlignment
stack.axis = .vertical eyebrowModel = viewModel.eyebrowModel(delegateObject: delegateObject, additionalData: additionalData)
return stack titleModel = viewModel.titleModel(delegateObject: delegateObject, additionalData: additionalData)
}() subTitleModel = viewModel.subTitleModel(delegateObject: delegateObject, additionalData: additionalData)
var castModel: TitleLockupModel? {
get { return model as? TitleLockupModel }
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initialization // MARK: - Initialization
//-------------------------------------------------- //--------------------------------------------------
public convenience init() { public convenience required init() {
self.init(frame: .zero) 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 // MARK: - MoleculeViewProtocol
//-------------------------------------------------- //--------------------------------------------------
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
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? {
return 65 return 65
} }
//-------------------------------------------------- open func updateView(_ size: CGFloat) {}
// 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
}
} }

View File

@ -7,6 +7,7 @@
// //
import VDSColorTokens import VDSColorTokens
import VDS
public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol { public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
@ -18,47 +19,16 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
public var moleculeName: String = TitleLockupModel.identifier public var moleculeName: String = TitleLockupModel.identifier
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var textAlignment: TitleLockup.TextAlignment = .left
public var eyebrow: LabelModel? public var eyebrow: LabelModel?
public var title: LabelModel public var title: LabelModel
public var subTitle: LabelModel? public var subTitle: LabelModel?
public var subTitleColor: Use = .primary
public var alignment: Alignment = .left { public var alignment: VDS.TitleLockup.TextAlignment = .left
didSet { public var inverted: Bool = false
///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 inverted: Bool = false { public var backgroundColor: Color?
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 children: [MoleculeModelProtocol] { public var children: [MoleculeModelProtocol] {
[eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule } [eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule }
@ -72,58 +42,6 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
self.eyebrow = eyebrow self.eyebrow = eyebrow
self.title = title self.title = title
self.subTitle = subTitle 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 { private enum CodingKeys: String, CodingKey {
case id case id
case moleculeName case moleculeName
case backgroundColor case textAlignment
case eyebrow case eyebrow
case title case title
case subTitle case subTitle
case subTitleColor
case inverted case inverted
case alignment case alignment
} }
@ -148,72 +67,91 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
required public init(from decoder: Decoder) throws { required public init(from decoder: Decoder) throws {
let typeContainer = try decoder.container(keyedBy: CodingKeys.self) let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString 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) eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle) subTitle = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .subTitle)
subTitleColor = try typeContainer.decodeIfPresent(Use.self, forKey: .subTitleColor) ?? .primary
if let newAlignment = try typeContainer.decodeIfPresent(Alignment.self, forKey: .alignment) {
if let newAlignment = try typeContainer.decodeIfPresent(VDS.TitleLockup.TextAlignment.self, forKey: .alignment) {
alignment = newAlignment alignment = newAlignment
} }
if let invertedStatus = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) { if let invertedStatus = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
inverted = invertedStatus inverted = invertedStatus
} }
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
updateLabelAttributes()
} }
public func encode(to encoder: Encoder) throws { public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(id, forKey: .id) try container.encode(id, forKey: .id)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encode(textAlignment, forKey: .textAlignment)
try container.encodeIfPresent(eyebrow, forKey: .eyebrow) try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
try container.encodeModel(title, forKey: .title) try container.encodeModel(title, forKey: .title)
try container.encodeIfPresent(subTitle, forKey: .subTitle) try container.encodeIfPresent(subTitle, forKey: .subTitle)
try container.encode(subTitleColor, forKey: .subTitleColor)
try container.encode(alignment, forKey: .alignment) try container.encode(alignment, forKey: .alignment)
try container.encode(inverted, forKey: .inverted) try container.encode(inverted, forKey: .inverted)
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
} }
//-------------------------------------------------- public func eyebrowModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.EyebrowModel? {
// MARK: - Model updates 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() { } catch MVMCoreError.errorObject(let object) {
// If subtitle style is not available, will set font style based on the component MVMCoreLoggingHandler.shared()?.addError(toLog: object)
if subTitle?.fontStyle == nil { } catch { }
subTitle?.fontStyle = defaultSubtitleFontStyle()
}
// If eyebrow style is not available, will set font style based on the component. Eyebrow and subtitle share the same font size return .init(text: title.text, textAttributes: attrs, numberOfLines: title.numberOfLines ?? 0)
if eyebrow?.fontStyle == nil { }
eyebrow?.fontStyle = subTitle?.fontStyle
} 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 do {
if eyebrow?.textColor == nil { if let style = subTitle.fontStyle {
eyebrow?.textColor = subTitleColor return .init(text: subTitle.text,
} otherStandardStyle: try style.vdsSubsetStyle(),
if title.textColor == nil { textColor: subTitleColor,
title.textColor = titleColor textAttributes: attrs,
} numberOfLines: subTitle.numberOfLines ?? 0)
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
} }
if title.textAlignment == nil { } catch MVMCoreError.errorObject(let object) {
title.textAlignment = textAlignment MVMCoreLoggingHandler.shared()?.addError(toLog: object)
} } catch { }
if subTitle?.textAlignment == nil {
subTitle?.textAlignment = textAlignment return .init(text: subTitle.text, textColor: subTitleColor, textAttributes: attrs, numberOfLines: subTitle.numberOfLines ?? 0)
}
}
} }
} }
extension TitleLockupModel {
public var surface: Surface { inverted ? .dark : .light }
}