vds_ios/VDS/Components/Tooltip/TrailingTooltipLabel.swift
Matt Bruce ba8e557cd0 updated didset
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
2023-08-30 18:04:46 -05:00

172 lines
6.3 KiB
Swift

//
// TrailingTooltipLabel.swift
// VDS
//
// Created by Matt Bruce on 4/14/23.
//
import Foundation
import UIKit
import Combine
/// A trailing tooltip is view that contains a label that has a tooltip overlay
/// applied at the last character of the text.
@objc(VDSTrailingTooltipLabel)
open class TrailingTooltipLabel: View, TooltipLaunchable {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
required public init() {
super.init(frame: .zero)
}
public override init(frame: CGRect) {
super.init(frame: .zero)
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
}
//--------------------------------------------------
// MARK: - Private Properties
//--------------------------------------------------
private let tooltipAction = PassthroughSubject<Void, Never>()
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
/// Label used to render the label text.
open var label = Label()
/// Text used to render the label.
open var labelText: String? { didSet { if oldValue != labelText { setNeedsUpdate() } } }
/// Attributes used to render the label.
open var labelAttributes: [any LabelAttributeModel]? { didSet { if oldValue != labelAttributes { setNeedsUpdate() } } }
/// Text style used to render the label.
open var labelTextStyle: TextStyle = .defaultStyle { didSet { if oldValue != labelTextStyle { setNeedsUpdate() } } }
/// Text position used to render the label.
open var labelTextAlignment: TextAlignment = .left { didSet { if oldValue != labelTextAlignment { setNeedsUpdate() } } }
/// Color configuration set for the label.
public lazy var textColorConfiguration: AnyColorable = {
label.textColorConfiguration
}() { didSet { setNeedsUpdate() } }
/// Will render the text for Close button for tooltip dialog when on mobile devices
open var tooltipCloseButtonText: String = "Close" { didSet { if oldValue != tooltipCloseButtonText { setNeedsUpdate() } } }
/// Text rendered for the title of the tooltip
open var tooltipTitle: String? { didSet { if oldValue != tooltipTitle { setNeedsUpdate() } } }
/// Text rendered for the content of the tooltip
open var tooltipContent: String? { didSet { if oldValue != tooltipContent { setNeedsUpdate() } } }
/// UIView rendered for the content area of the tooltip
open var tooltipContentView: UIView? { didSet { if oldValue != tooltipContentView { setNeedsUpdate() } } }
//--------------------------------------------------
// 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(label)
label.pinToSuperView()
//create the tooltip click event
tooltipAction.sink { [weak self] in
guard let self else { return }
self.presentTooltip(surface: self.surface,
title: self.tooltipTitle,
content: self.tooltipContent,
closeButtonText: self.tooltipCloseButtonText,
presenter: self)
}.store(in: &subscribers)
}
/// Used to make changes to the View based off a change events or from local properties.
open override func updateView() {
super.updateView()
label.text = labelText
label.textStyle = labelTextStyle
label.textAlignment = labelTextAlignment.value
label.attributes = labelAttributes
label.surface = surface
label.isEnabled = isEnabled
//add tooltip
if let labelText, !labelText.isEmpty {
label.addTooltip(model: .init(surface: surface, closeButtonText: tooltipCloseButtonText, title: tooltipTitle, content: tooltipContent, contentView: tooltipContentView))
}
}
/// Resets to default settings.
open override func reset() {
super.reset()
shouldUpdateView = false
labelText = nil
labelAttributes = nil
labelTextStyle = .defaultStyle
labelTextAlignment = .left
tooltipCloseButtonText = "Close"
tooltipTitle = ""
tooltipContent = ""
shouldUpdateView = true
setNeedsUpdate()
}
}
extension Label {
/// Model used to represent the tooltip.
public struct TooltipModel {
/// Current Surface and this is used to pass down to child objects that implement Surfacable
public var surface: Surface
public var closeButtonText: String
public var title: String?
public var content: String?
public var contentView: UIView?
public init(surface: Surface = .light, closeButtonText: String = "Close", title: String?, content: String?, contentView: UIView?) {
self.surface = surface
self.closeButtonText = closeButtonText
self.title = title
self.content = content
self.contentView = contentView
}
}
/// Helper to add a tool tip attribute to an existing label.
public func addTooltip(model: TooltipModel) {
var newAttributes: [any LabelAttributeModel] = []
if let attributes {
attributes.forEach { attribute in
if type(of: attribute) != TooltipLabelAttribute.self {
newAttributes.append(attribute)
}
}
}
if let text = text, !text.isEmpty {
let tooltip = TooltipLabelAttribute(surface: surface,
closeButtonText: model.closeButtonText,
title: model.title,
content: model.content,
contentView: model.contentView,
presenter: self)
newAttributes.append(tooltip)
}
if !newAttributes.isEmpty {
attributes = newAttributes
}
}
}