From 6d38474675932ac6cf855e88aa59d82e5c5090cb Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 26 Feb 2024 17:51:16 -0600 Subject: [PATCH] added text as a property added subclass of UITextField to deal with text rendering and attributes. Signed-off-by: Matt Bruce --- .../TextFields/TextArea/TextArea.swift | 179 ++++++++++++++++-- 1 file changed, 164 insertions(+), 15 deletions(-) diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index a9c1cbf4..e9da9b11 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -107,20 +107,21 @@ open class TextArea: EntryFieldBase { } } + /// The text of this textField. + open override var text: String? { + get { textView.text } + set { + textView.text = newValue + } + } + /// UITextView shown in the TextArea. - open var textView = UITextView().with { + open var textView = TextView().with { $0.translatesAutoresizingMaskIntoConstraints = false - $0.font = TextStyle.bodyLarge.font $0.sizeToFit() $0.isScrollEnabled = false } - /// Color configuration for the textView. - open var textViewTextColorConfiguration: AnyColorable = ViewColorConfiguration().with { - $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) - }.eraseToAnyColorable() { didSet { setNeedsUpdate() } } - /// Color configuration for error icon. internal var iconColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) @@ -187,7 +188,9 @@ open class TextArea: EntryFieldBase { super.updateView() textView.isEditable = isEnabled - textView.textColor = textViewTextColorConfiguration.getColor(self) + textView.isEnabled = isEnabled + textView.surface = surface + //set the width constraints if let width { widthConstraint?.constant = width @@ -260,12 +263,18 @@ open class TextArea: EntryFieldBase { open func highlightCharacterOverflow() { let count = textView.text.count - guard let maxLength, - count > maxLength, - let text = textView.attributedText?.mutableCopy() as? NSMutableAttributedString else { return } - text.addAttribute(NSAttributedString.Key.backgroundColor, value: highlightBackgroundColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) - text.addAttribute(NSAttributedString.Key.foregroundColor, value: highlightTextColor.getColor(self), range: NSRange(location:maxLength, length: (count - maxLength))) - textView.attributedText = text + guard let maxLength, count > maxLength else { + textView.textAttributes = nil + return + } + + var textAttributes = [any LabelAttributeModel]() + let location = maxLength + let length = count - maxLength + textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightBackgroundColor.getColor(self), isForegroundColor: false)) + textAttributes.append(ColorLabelAttribute(location: location, length: length, color: highlightTextColor.getColor(self), isForegroundColor: true)) + + textView.textAttributes = textAttributes } } @@ -310,3 +319,143 @@ extension TextArea: UITextViewDelegate { } } } + +/// Will move this into a new file, need to talk with Scott/Kyle +open class TextView: UITextView, ViewProtocol { + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero, textContainer: nil) + initialSetup() + } + + public override init(frame: CGRect, textContainer: NSTextContainer?) { + super.init(frame: frame, textContainer: textContainer) + initialSetup() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + initialSetup() + } + + //-------------------------------------------------- + // MARK: - Combine Properties + //-------------------------------------------------- + /// Set of Subscribers for any Publishers for this Control. + open var subscribers = Set() + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + private var initialSetupPerformed = false + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + /// Key of whether or not updateView() is called in setNeedsUpdate() + open var shouldUpdateView: Bool = true + + open var surface: Surface = .light { didSet { setNeedsUpdate() } } + + /// Array of LabelAttributeModel objects used in rendering the text. + open var textAttributes: [any LabelAttributeModel]? { didSet { setNeedsUpdate() } } + + /// TextStyle used on the titleLabel. + open var textStyle: TextStyle { .defaultStyle } + + /// Will determine if a scaled font should be used for the titleLabel font. + open var useScaledFont: Bool = false { didSet { setNeedsUpdate() } } + + open var isEnabled: Bool = true { didSet { setNeedsUpdate() } } + + open var textColorConfiguration: AnyColorable = ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forDisabled: false) + }.eraseToAnyColorable(){ didSet { setNeedsUpdate() }} + + open override var textColor: UIColor? { + get { textColorConfiguration.getColor(self) } + set { } + } + + override public var text: String! { + get { super.text } + set { + super.text = newValue + updateLabel() + } + } + + override public var textAlignment: NSTextAlignment { + didSet { + if textAlignment != oldValue { + // Text alignment can be part of our paragraph style, so we may need to + // re-style when changed + updateLabel() + } + } + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open func initialSetup() { + if !initialSetupPerformed { + backgroundColor = .clear + translatesAutoresizingMaskIntoConstraints = false + accessibilityCustomActions = [] + setup() + setNeedsUpdate() + } + } + + + open func setup() { + translatesAutoresizingMaskIntoConstraints = false + } + + open func updateView() { + updateLabel() + } + + open func updateAccessibility() {} + + open func reset() { + shouldUpdateView = false + surface = .light + text = nil + accessibilityCustomActions = [] + shouldUpdateView = true + setNeedsUpdate() + } + + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + private func updateLabel() { + + //clear the arrays holding actions + accessibilityCustomActions = [] + if let text, !text.isEmpty { + //create the primary string + let mutableText = NSMutableAttributedString.mutableText(for: text, + textStyle: textStyle, + useScaledFont: useScaledFont, + textColor: textColor!, + alignment: textAlignment, + lineBreakMode: .byWordWrapping) + //apply any attributes + if let attributes = textAttributes { + mutableText.apply(attributes: attributes) + } + attributedText = mutableText + } else { + attributedText = nil + } + } + + +}