diff --git a/VDS/Components/PriceLockup/PriceLockup.swift b/VDS/Components/PriceLockup/PriceLockup.swift index 4d21b42c..059a94a6 100644 --- a/VDS/Components/PriceLockup/PriceLockup.swift +++ b/VDS/Components/PriceLockup/PriceLockup.swift @@ -31,11 +31,6 @@ open class PriceLockup: View { //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- - /// Enum used to describe the kind of PriceLockup. - public enum Kind: String, CaseIterable { - case primary, secondary, savings - } - /// Enum used to describe the term of PriceLockup. public enum Term: String, CaseIterable { case month, year, biennial, none @@ -44,7 +39,7 @@ open class PriceLockup: View { public static var defaultValue : Self { .month } /// Text for this term of PriceLockup. - public var text: String { + public var type: String { switch self { case .month: return "mo" @@ -69,7 +64,30 @@ open class PriceLockup: View { case xlarge case xxlarge - public var defaultValue: Self { .medium } + public static var defaultValue: Self { .medium } + } + + /// Enum used to describe the kind of PriceLockup. + public enum Kind: String, CaseIterable { + case primary, secondary, savings + + /// The default kind is 'primary'. + public static var defaultValue : Self { .primary } + + /// Color configuation relative to kind. + public var colorConfiguration: ViewColorConfiguration { + switch self { + case .primary: + return ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false)} + case .secondary: + return ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: false)} + case .savings: + return ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forDisabled: false)} + } + } } //-------------------------------------------------- @@ -89,11 +107,11 @@ open class PriceLockup: View { open var price: Float? { didSet { setNeedsUpdate() } } /// Color to the component. The default kind is primary. - open var kind: Kind = .primary { didSet { setNeedsUpdate() } } + open var kind: Kind = Kind.defaultValue { didSet { setNeedsUpdate() } } /// Size of the component. It varies by size and viewport(mobile/Tablet). /// The default size is medium with viewport mobile. - open var size: Size = .medium { didSet { setNeedsUpdate() } } + open var size: Size = Size.defaultValue { didSet { setNeedsUpdate() } } /// If true, the component with a strikethrough. It applies only when uniformSize is true. /// Does not apply a strikethrough format to leading and trailing text. @@ -116,21 +134,17 @@ open class PriceLockup: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var containerView = View().with { - $0.clipsToBounds = true - } - - internal var label = Label().with { + internal var priceLockupLabel = Label().with { $0.isAccessibilityElement = true $0.lineBreakMode = .byWordWrapping } - internal var index = 0 + internal var delimiterIndex = 0 internal var strikethroughLocation = 0 - internal var strikethroughlength = 0 + internal var strikethroughLength = 0 - internal var textContentType:TextContentType = .preDelimiter - enum TextContentType: String, CaseIterable { + internal var textPosition:TextPosition = .preDelimiter + enum TextPosition: String, CaseIterable { case preDelimiter, postDelimiter } @@ -139,8 +153,8 @@ open class PriceLockup: View { //-------------------------------------------------- internal var containerSize: CGSize { CGSize(width: 45, height: 44) } - private var contentFontSize: VDS.TextStyle { - switch (size, textContentType) { + private var sizeTextStyle: VDS.TextStyle { + switch (size, textPosition) { case (.xxxsmall, .preDelimiter), (.xxxsmall, .postDelimiter): return TextStyle.micro @@ -179,106 +193,34 @@ open class PriceLockup: View { } } - private var textColorConfiguration: ViewColorConfiguration { - switch kind { - - case .primary: - return ViewColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) - } - - case .secondary: - return ViewColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: false) - } - case .savings: - return ViewColorConfiguration().with { - $0.setSurfaceColors(VDSColor.paletteGreen26, VDSColor.paletteGreen36, forDisabled: false) - } - } - } - //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() - addSubview(containerView) - containerView - .pinTop() - .pinBottom() - .pinLeadingGreaterThanOrEqualTo() - .pinTrailingLessThanOrEqualTo() - .height(containerSize.height) - containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() - - // Price lockup - containerView.addSubview(label) - label.pinToSuperView() - label.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + // Price lockup label + addSubview(priceLockupLabel) + priceLockupLabel.pinToSuperView() } - - func updateLabel() { - var attributes: [any LabelAttributeModel] = [] - let colorAttr = ColorLabelAttribute(location: 0, - length: label.text.count, - color: textColorConfiguration.getColor(self)) - attributes.append(colorAttr) - if index > 0 { - textContentType = .preDelimiter - let textStyleAttr = TextStyleLabelAttribute(location: 0, - length: index, - textStyle: contentFontSize) - textContentType = .postDelimiter - let othertextStyleAttr = TextStyleLabelAttribute(location: index+1, - length: label.text.count-index-1, - textStyle: contentFontSize) - attributes.append(textStyleAttr) - attributes.append(othertextStyleAttr) - } - label.attributes = attributes - } - + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - label.text = fetchText() - label.surface = surface + + priceLockupLabel.text = fetchText() + priceLockupLabel.surface = surface // Set the attributed text - updateLabel() - - if strikethrough { - // strike applies only when uniformSize true. Does not apply a strikethrough format to leading, trailing, and superscript text. - textContentType = .postDelimiter - var strikethroughAttributes: [any LabelAttributeModel]? { - [TextStyleLabelAttribute(location: 0, - length: label.text.count, - textStyle: contentFontSize), - StrikeThroughLabelAttribute(location:strikethroughLocation, length: strikethroughlength)] - } - label.attributes = strikethroughAttributes - } - - if uniformSize { - // currency and value have the same font text style as delimeter, term, trailing text and superscript. - textContentType = .postDelimiter - var uniformSizeAttributes: [any LabelAttributeModel]? { - [TextStyleLabelAttribute(location: 0, - length: label.text.count, - textStyle: contentFontSize)] - } - label.attributes = uniformSizeAttributes - } + updateLabelAttributes() } /// Resets to default settings. open override func reset() { super.reset() shouldUpdateView = false - label.reset() + priceLockupLabel.reset() shouldUpdateView = true setNeedsUpdate() } @@ -293,31 +235,73 @@ open class PriceLockup: View { //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- + func updateLabelAttributes() { + var attributes: [any LabelAttributeModel] = [] + attributes.append(ColorLabelAttribute(location: 0, + length: priceLockupLabel.text.count, + color: kind.colorConfiguration.getColor(self))) + textPosition = .postDelimiter + if strikethrough { + + // strike applies only when uniformSize true. Does not apply a strikethrough format to leading, trailing, and superscript text. + attributes.append(TextStyleLabelAttribute(location: 0, + length: priceLockupLabel.text.count, + textStyle: sizeTextStyle, + textPosition: .left)) + attributes.append(StrikeThroughLabelAttribute(location:strikethroughLocation, length: strikethroughLength)) + } else if uniformSize { + + // currency and value have the same font text style as delimeter, term, trailing text and superscript. + attributes.append(TextStyleLabelAttribute(location: 0, + length: priceLockupLabel.text.count, + textStyle: sizeTextStyle, + textPosition: .left)) + } else { + + // size updates relative to predelimiter, postdelimiter + if delimiterIndex > 0 { + textPosition = .preDelimiter + attributes.append(TextStyleLabelAttribute(location: 0, + length: delimiterIndex, + textStyle: sizeTextStyle, + textPosition: .left)) + + textPosition = .postDelimiter + attributes.append(TextStyleLabelAttribute(location: delimiterIndex, + length: priceLockupLabel.text.count-delimiterIndex, + textStyle: sizeTextStyle, + textPosition: .left)) + } + } + priceLockupLabel.attributes = attributes + } + open func fetchText() -> String { var text : String = "" - index = 0 + let space = " " + let delimiter = "/" + delimiterIndex = 0 let currency: String = hideCurrency ? "" : "$" if let leadingStr = leadingText { - text = text + leadingStr + " " - index = index + leadingStr.count + 1 + text = text + leadingStr + space + delimiterIndex = delimiterIndex + leadingStr.count + space.count } if let value = price { - strikethroughLocation = index + strikethroughLocation = delimiterIndex let valueStr = "\(value.clean)" text = text + currency + valueStr - index = index + valueStr.count + 1 - strikethroughlength = valueStr.count + 1 + delimiterIndex = delimiterIndex + valueStr.count + currency.count + strikethroughLength = valueStr.count + currency.count } if term != .none { - text = text + "/" + term.text - strikethroughlength = strikethroughlength + term.text.count + 1 + text = text + delimiter + term.type + strikethroughLength = strikethroughLength + delimiter.count + term.type.count } if let trailingStr = trailingText { - text = text + " " + trailingStr + text = text + space + trailingStr } text = text + (superscript ?? "") return text - } }