From 441971d2f917ff5ebdd97437fa4878e18dba9893 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 09:20:17 -0600 Subject: [PATCH 1/8] updated to fix issue for attributedText Signed-off-by: Matt Bruce --- .../Selector/SelectorItemBase.swift | 2 - VDS/Components/Label/Label.swift | 118 ++++++++++++------ VDS/Components/RadioBox/RadioBoxItem.swift | 3 - 3 files changed, 82 insertions(+), 41 deletions(-) diff --git a/VDS/BaseClasses/Selector/SelectorItemBase.swift b/VDS/BaseClasses/Selector/SelectorItemBase.swift index 9ca86d8c..869c40e0 100644 --- a/VDS/BaseClasses/Selector/SelectorItemBase.swift +++ b/VDS/BaseClasses/Selector/SelectorItemBase.swift @@ -102,7 +102,6 @@ open class SelectorItemBase: Control, Errorable, /// Instead of use labelText and labelTextAttirbutes, this is a fully baked NSAttributedString with both text and attributes. open var labelAttributedText: NSAttributedString? { didSet { - label.useAttributedText = !(labelAttributedText?.string.isEmpty ?? true) label.attributedText = labelAttributedText setNeedsUpdate() } @@ -117,7 +116,6 @@ open class SelectorItemBase: Control, Errorable, /// Instead of use childText and childTextAttirbutes, this is a fully baked NSAttributedString with both text and attributes. open var childAttributedText: NSAttributedString? { didSet { - childLabel.useAttributedText = !(childAttributedText?.string.isEmpty ?? true) childLabel.attributedText = childAttributedText setNeedsUpdate() } diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 67e53abe..c998c70b 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -42,6 +42,13 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + private enum TextSetMode { + case text + case attributedText + } + + private var textSetMode: TextSetMode = .text + private var initialSetupPerformed = false private var edgeInsets: UIEdgeInsets { textStyle.edgeInsets } @@ -102,10 +109,6 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- /// Key of whether or not updateView() is called in setNeedsUpdate() open var shouldUpdateView: Bool = true - - /// Determines if the label should use its own attributedText property instead of rendering the attributedText propert - /// based of other local properties, such as textStyle, textColor, surface, etc... The default value is false. - open var useAttributedText: Bool = false /// Will determine if a scaled font should be used for the font. open var useScaledFont: Bool = false { didSet { setNeedsUpdate() }} @@ -132,15 +135,25 @@ open class Label: UILabel, ViewProtocol, UserInfoable { private var _text: String? /// Text that will be used in the label. - override open var text: String? { - get { _text } + override public var text: String! { + get { super.text } set { - if _text != newValue || newValue != attributedText?.string { - _text = newValue - useAttributedText = false - attributes?.removeAll() - setNeedsUpdate() - } + // When text is set, we may need to re-style it as attributedText + // with the correct paragraph style to achieve the desired line height. + textSetMode = .text + attributes?.removeAll() + styleText(newValue) + } + } + + ///AttributedText that will be used in the label. + override public var attributedText: NSAttributedString? { + get { super.attributedText } + set { + // When text is set, we may need to re-style it as attributedText + // with the correct paragraph style to achieve the desired line height. + textSetMode = .attributedText + styleAttributedText(newValue) } } @@ -200,30 +213,13 @@ open class Label: UILabel, ViewProtocol, UserInfoable { } open func updateView() { - if !useAttributedText { - if let text { - accessibilityCustomActions = [] - - //create the primary string - let mutableText = NSMutableAttributedString.mutableText(for: text, - textStyle: textStyle, - useScaledFont: useScaledFont, - textColor: textColorConfiguration.getColor(self), - alignment: textAlignment, - lineBreakMode: lineBreakMode) - - applyAttributes(mutableText) - - //set the attributed text - attributedText = mutableText - - //force a drawText - setNeedsDisplay() - - setNeedsLayout() - layoutIfNeeded() - } - } + restyleText() + + //force a drawText + setNeedsDisplay() + + setNeedsLayout() + layoutIfNeeded() } open func updateAccessibility() { @@ -269,6 +265,56 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- + private func restyleText() { + if textSetMode == .text { + styleText(text) + } else { + styleAttributedText(attributedText) + } + } + + private func styleText(_ newValue: String!) { + defer { invalidateIntrinsicContentSize() } + guard let newValue else { + // We don't need to use attributed text + super.attributedText = nil + super.text = newValue + return + } + + accessibilityCustomActions = [] + + //create the primary string + let mutableText = NSMutableAttributedString.mutableText(for: newValue, + textStyle: textStyle, + useScaledFont: useScaledFont, + textColor: textColorConfiguration.getColor(self), + alignment: textAlignment, + lineBreakMode: lineBreakMode) + + applyAttributes(mutableText) + + // Set attributed text to match typography + super.attributedText = mutableText + + } + + private func styleAttributedText(_ newValue: NSAttributedString?) { + defer { invalidateIntrinsicContentSize() } + guard let newValue = newValue else { + // We don't need any additional styling + super.attributedText = newValue + return + } + + var mutableText = NSMutableAttributedString(attributedString: newValue) + + applyAttributes(mutableText) + + // Modify attributed text to match typography + super.attributedText = newValue + } + private func applyAttributes(_ mutableAttributedString: NSMutableAttributedString) { actions = [] diff --git a/VDS/Components/RadioBox/RadioBoxItem.swift b/VDS/Components/RadioBox/RadioBoxItem.swift index 81f3f709..cfeb54e6 100644 --- a/VDS/Components/RadioBox/RadioBoxItem.swift +++ b/VDS/Components/RadioBox/RadioBoxItem.swift @@ -100,7 +100,6 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { /// If provided, the RadioBox textAttributedText will be rendered. open var textAttributedText: NSAttributedString? { didSet { - textLabel.useAttributedText = !(textAttributedText?.string.isEmpty ?? true) textLabel.attributedText = textAttributedText setNeedsUpdate() } @@ -115,7 +114,6 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { /// If provided, the RadioBox subTextAttributedText will be rendered. open var subTextAttributedText: NSAttributedString? { didSet { - subTextLabel.useAttributedText = !(subTextAttributedText?.string.isEmpty ?? true) subTextLabel.attributedText = subTextAttributedText setNeedsUpdate() } @@ -130,7 +128,6 @@ open class RadioBoxItem: Control, Changeable, FormFieldable { /// If provided, the RadioBox subTextRightAttributedText will be rendered. open var subTextRightAttributedText: NSAttributedString? { didSet { - subTextRightLabel.useAttributedText = !(subTextRightAttributedText?.string.isEmpty ?? true) subTextRightLabel.attributedText = subTextRightAttributedText setNeedsUpdate() } From 0fffd3811396b7120575501620e7af1a71fe8cb2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 10:08:12 -0600 Subject: [PATCH 2/8] updated initialSetup Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonBase.swift | 1 + VDS/Components/TextFields/TextArea/TextView.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index 255c6f64..cc096d41 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -102,6 +102,7 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { //-------------------------------------------------- open func initialSetup() { if !initialSetupPerformed { + initialSetupPerformed = true backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false accessibilityCustomActions = [] diff --git a/VDS/Components/TextFields/TextArea/TextView.swift b/VDS/Components/TextFields/TextArea/TextView.swift index ea96ed6e..ffb355d1 100644 --- a/VDS/Components/TextFields/TextArea/TextView.swift +++ b/VDS/Components/TextFields/TextArea/TextView.swift @@ -94,6 +94,7 @@ open class TextView: UITextView, ViewProtocol { //-------------------------------------------------- open func initialSetup() { if !initialSetupPerformed { + initialSetupPerformed = true backgroundColor = .clear translatesAutoresizingMaskIntoConstraints = false accessibilityCustomActions = [] From 21ab644c16358f85f46a0e6996aff75a29b360c2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 10:08:32 -0600 Subject: [PATCH 3/8] refactored for custom fonts Signed-off-by: Matt Bruce --- VDS/Fonts/Font.swift | 11 +++++++++-- VDS/Fonts/FontProtocol.swift | 3 ++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/VDS/Fonts/Font.swift b/VDS/Fonts/Font.swift index c5caaa32..6b875ad3 100644 --- a/VDS/Fonts/Font.swift +++ b/VDS/Fonts/Font.swift @@ -8,13 +8,14 @@ import Foundation /// Enum that is matched up for the Verizon fonts. -public enum Font: String, FontProtocol { +public enum Font: FontProtocol { case edsBold case edsRegular case dsLight case etxBold case etxRegular - + case custom(String) + public var fontName: String { switch self { case .edsBold: @@ -27,9 +28,15 @@ public enum Font: String, FontProtocol { return "VerizonNHGeTX-Bold" case .etxRegular: return "VerizonNHGeTX-Regular" + case .custom(let fontName): + return fontName } } + public static var allCases: [Font] { + [.edsBold, .edsRegular, .dsLight, .etxBold, .etxRegular] + } + /// File Extension for each of the Font enums. public var fontFileExtension: String { return "otf" diff --git a/VDS/Fonts/FontProtocol.swift b/VDS/Fonts/FontProtocol.swift index 9ee21939..fbca693b 100644 --- a/VDS/Fonts/FontProtocol.swift +++ b/VDS/Fonts/FontProtocol.swift @@ -9,9 +9,10 @@ import Foundation import UIKit /// Used in Classes that require Fonts -public protocol FontProtocol: CaseIterable, RawRepresentable, Hashable { +public protocol FontProtocol: Hashable { var fontFileExtension: String { get } var fontName: String { get } + static var allCases: [Self] { get } } extension FontProtocol { From 23f3f8b6bfe471b29ed8110785911f4e5ae4ae57 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 10:08:50 -0600 Subject: [PATCH 4/8] added a conversion of a UIFont to a TextStyle Signed-off-by: Matt Bruce --- VDS/Typography/Typogprahy+Styles.swift | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/VDS/Typography/Typogprahy+Styles.swift b/VDS/Typography/Typogprahy+Styles.swift index ec144617..0cd6e614 100644 --- a/VDS/Typography/Typogprahy+Styles.swift +++ b/VDS/Typography/Typogprahy+Styles.swift @@ -209,6 +209,24 @@ extension TextStyle { boldMicro ] } + + public static func convert(font: UIFont) -> TextStyle { + var found: TextStyle? + + for textStyle in allCases { + if font.fontName == textStyle.fontFace.fontName && + font.pointSize == textStyle.pointSize { + found = textStyle + break + } + } + + guard let found else { + return TextStyle(rawValue: "Custom", fontFace: .custom(font.fontName), pointSize: font.pointSize) + } + + return found + } } extension TextStyle { From 89a4c5d397e7df17355d5869c14ac03445e12d69 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 10:09:59 -0600 Subject: [PATCH 5/8] updated label with overrides for textColor and font Signed-off-by: Matt Bruce --- VDS/Components/Label/Label.swift | 35 +++++++++++++++++++++----------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index c998c70b..0c89ae3f 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -131,32 +131,43 @@ open class Label: UILabel, ViewProtocol, UserInfoable { /// Line break mode for the label, default is set to word wrapping. open override var lineBreakMode: NSLineBreakMode { didSet { setNeedsUpdate() }} - - private var _text: String? - + /// Text that will be used in the label. - override public var text: String! { + override open var text: String! { get { super.text } set { - // When text is set, we may need to re-style it as attributedText - // with the correct paragraph style to achieve the desired line height. textSetMode = .text - attributes?.removeAll() styleText(newValue) } } ///AttributedText that will be used in the label. - override public var attributedText: NSAttributedString? { + override open var attributedText: NSAttributedString? { get { super.attributedText } set { - // When text is set, we may need to re-style it as attributedText - // with the correct paragraph style to achieve the desired line height. textSetMode = .attributedText styleAttributedText(newValue) } } + override open var font: UIFont! { + didSet { + if let font, initialSetupPerformed { + textStyle = TextStyle.convert(font: font) + } + setNeedsUpdate() + } + } + + override open var textColor: UIColor! { + didSet { + if let textColor, initialSetupPerformed { + textColorConfiguration = SurfaceColorConfiguration(textColor, textColor).eraseToAnyColorable() + } + setNeedsUpdate() + } + } + /// Whether the View is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate() } } @@ -175,13 +186,13 @@ open class Label: UILabel, ViewProtocol, UserInfoable { //-------------------------------------------------- open func initialSetup() { if !initialSetupPerformed { + initialSetupPerformed = true //register for ContentSizeChanges NotificationCenter .Publisher(center: .default, name: UIContentSizeCategory.didChangeNotification) .sink { [weak self] notification in self?.setNeedsUpdate() }.store(in: &subscribers) - backgroundColor = .clear numberOfLines = 0 lineBreakMode = .byWordWrapping @@ -307,7 +318,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { return } - var mutableText = NSMutableAttributedString(attributedString: newValue) + let mutableText = NSMutableAttributedString(attributedString: newValue) applyAttributes(mutableText) From 473ab531e86e354b420811f2d8be77216aeb9f3e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 12:34:07 -0600 Subject: [PATCH 6/8] fixed bug Signed-off-by: Matt Bruce --- VDS/Components/Label/Label.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 0c89ae3f..60e88740 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -323,7 +323,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { applyAttributes(mutableText) // Modify attributed text to match typography - super.attributedText = newValue + super.attributedText = mutableText } private func applyAttributes(_ mutableAttributedString: NSMutableAttributedString) { From fbdcdfc2774428db1efa330e18645280d1da84ab Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 12:34:23 -0600 Subject: [PATCH 7/8] refactored method Signed-off-by: Matt Bruce --- VDS/Typography/Typogprahy+Styles.swift | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/VDS/Typography/Typogprahy+Styles.swift b/VDS/Typography/Typogprahy+Styles.swift index 0cd6e614..0136d3c4 100644 --- a/VDS/Typography/Typogprahy+Styles.swift +++ b/VDS/Typography/Typogprahy+Styles.swift @@ -211,20 +211,9 @@ extension TextStyle { } public static func convert(font: UIFont) -> TextStyle { - var found: TextStyle? - - for textStyle in allCases { - if font.fontName == textStyle.fontFace.fontName && - font.pointSize == textStyle.pointSize { - found = textStyle - break - } + guard let found = allCases.first(where: { font.fontName == $0.fontFace.fontName && font.pointSize == $0.pointSize} ) else { + return TextStyle(rawValue: "Custom\(font.fontName)", fontFace: .custom(font), pointSize: font.pointSize) } - - guard let found else { - return TextStyle(rawValue: "Custom", fontFace: .custom(font.fontName), pointSize: font.pointSize) - } - return found } } From fd641a85cf5d2814f759322f9f33ec64c2f3ad37 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 8 Mar 2024 12:34:31 -0600 Subject: [PATCH 8/8] updated to handle custom fonts Signed-off-by: Matt Bruce --- VDS/Fonts/Font.swift | 22 +++++++++++++++++++--- VDS/Fonts/FontProtocol.swift | 2 +- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/VDS/Fonts/Font.swift b/VDS/Fonts/Font.swift index 6b875ad3..f4ba798d 100644 --- a/VDS/Fonts/Font.swift +++ b/VDS/Fonts/Font.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit /// Enum that is matched up for the Verizon fonts. public enum Font: FontProtocol { @@ -14,7 +15,7 @@ public enum Font: FontProtocol { case dsLight case etxBold case etxRegular - case custom(String) + case custom(UIFont) public var fontName: String { switch self { @@ -28,8 +29,8 @@ public enum Font: FontProtocol { return "VerizonNHGeTX-Bold" case .etxRegular: return "VerizonNHGeTX-Regular" - case .custom(let fontName): - return fontName + case .custom(let font): + return font.fontName } } @@ -41,4 +42,19 @@ public enum Font: FontProtocol { public var fontFileExtension: String { return "otf" } + + /// Returns a UIFont for the fontName and size given. + /// - Parameters: + /// - size: Size of the font + /// - Returns: UIFont for the fontName and Size. + public func font(ofSize size: CGFloat) -> UIFont{ + DispatchQueue.once(block: { self.register() }) + switch self { + case .custom(let font): + return font + default: + guard let found = UIFont(name: self.fontName, size: size) else { return .systemFont(ofSize: size) } + return found + } + } } diff --git a/VDS/Fonts/FontProtocol.swift b/VDS/Fonts/FontProtocol.swift index fbca693b..df6ac6a3 100644 --- a/VDS/Fonts/FontProtocol.swift +++ b/VDS/Fonts/FontProtocol.swift @@ -9,7 +9,7 @@ import Foundation import UIKit /// Used in Classes that require Fonts -public protocol FontProtocol: Hashable { +public protocol FontProtocol { var fontFileExtension: String { get } var fontName: String { get } static var allCases: [Self] { get }