181 lines
6.1 KiB
Swift
181 lines
6.1 KiB
Swift
//
|
|
// FootnoteGroup.swift
|
|
// VDS
|
|
//
|
|
// Created by Kanamarlapudi, Vasavi on 29/08/24.
|
|
//
|
|
|
|
import Foundation
|
|
import UIKit
|
|
import VDSCoreTokens
|
|
|
|
/// This must always be paired with one or more ``Footnote`` in a FootnoteGroup.
|
|
@objcMembers
|
|
@objc(VDSFootnoteGroup)
|
|
open class FootnoteGroup: View {
|
|
|
|
//--------------------------------------------------
|
|
// 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: - enums
|
|
//--------------------------------------------------
|
|
/// Enum used to describe the width of a fixed value or percentage of parent's width.
|
|
public enum Width {
|
|
case percentage(CGFloat)
|
|
case value(CGFloat)
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Public Properties
|
|
//--------------------------------------------------
|
|
/// Array of ``Footnote`` for the Footnote items.
|
|
open var footnoteItems: [Footnote] = [] { didSet { setNeedsUpdate() } }
|
|
|
|
/// Any percentage or pixel value and cannot exceed container size.
|
|
/// If there is a width that is larger than container size, the footnote will resize to container's width.
|
|
open var width: Width? {
|
|
get { _width }
|
|
set {
|
|
if let newValue {
|
|
switch newValue {
|
|
case .percentage(let percentage):
|
|
if percentage <= 100.0 {
|
|
_width = newValue
|
|
}
|
|
case .value(let value):
|
|
if value > 0 {
|
|
_width = newValue
|
|
}
|
|
}
|
|
} else {
|
|
_width = nil
|
|
}
|
|
setNeedsUpdate()
|
|
}
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Private Properties
|
|
//--------------------------------------------------
|
|
private var _width: Width? = nil
|
|
|
|
private lazy var stackView = UIStackView().with {
|
|
$0.translatesAutoresizingMaskIntoConstraints = false
|
|
$0.axis = .vertical
|
|
$0.alignment = .top
|
|
$0.distribution = .fill
|
|
$0.spacing = VDSLayout.space3X
|
|
$0.backgroundColor = .clear
|
|
}
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Configuration Properties
|
|
//--------------------------------------------------
|
|
internal var maxWidth: CGFloat { frame.size.width }
|
|
internal var minWidth: CGFloat { containerSize.width }
|
|
internal var containerSize: CGSize { CGSize(width: 55, height: 44) }
|
|
|
|
//--------------------------------------------------
|
|
// MARK: - Constraints
|
|
//--------------------------------------------------
|
|
internal var widthConstraint: NSLayoutConstraint?
|
|
internal var trailingEqualsConstraint: NSLayoutConstraint?
|
|
internal var trailingLessThanEqualsConstraint: NSLayoutConstraint?
|
|
|
|
//--------------------------------------------------
|
|
// 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()
|
|
|
|
// add footnote item stackview.
|
|
addSubview(stackView)
|
|
stackView.pinTop().pinBottom().pinLeading()
|
|
trailingEqualsConstraint = stackView.pinTrailing(anchor: trailingAnchor)
|
|
|
|
// width constraints
|
|
trailingLessThanEqualsConstraint = stackView.pinTrailingLessThanOrEqualTo(anchor: trailingAnchor)?.deactivate()
|
|
widthConstraint = stackView.widthAnchor.constraint(equalToConstant: 0).deactivate()
|
|
}
|
|
|
|
open override func setDefaults() {
|
|
super.setDefaults()
|
|
width = nil
|
|
footnoteItems = []
|
|
}
|
|
|
|
/// Resets to default settings.
|
|
open override func reset() {
|
|
super.reset()
|
|
}
|
|
|
|
/// Used to make changes to the View based off a change events or from local properties.
|
|
open override func updateView() {
|
|
super.updateView()
|
|
updateContainerWidth()
|
|
|
|
// symbol containers are as wide as the widest symbol container in the group.
|
|
var symbolMaxWidth = 0.0
|
|
if footnoteItems.count > 0 {
|
|
for index in 0...footnoteItems.count - 1 {
|
|
let footnote: Footnote = footnoteItems[index]
|
|
let separatorWidth = Label().with { $0.text = footnote.symbolType; $0.sizeToFit() }.intrinsicContentSize.width
|
|
symbolMaxWidth = separatorWidth > symbolMaxWidth ? separatorWidth : symbolMaxWidth
|
|
}
|
|
}
|
|
|
|
stackView.subviews.forEach{$0.removeFromSuperview()}
|
|
// add symbol label, text label to stack.
|
|
if footnoteItems.count > 0 {
|
|
for index in 0...footnoteItems.count - 1 {
|
|
let footnote: Footnote = footnoteItems[index]
|
|
footnote.symbolWiderWidth = symbolMaxWidth
|
|
footnote.surface = surface
|
|
stackView.addArrangedSubview(footnote)
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Update container width after updating content.
|
|
internal func updateContainerWidth() {
|
|
var newWidth = 0.0
|
|
switch width {
|
|
case .percentage(let percentage):
|
|
newWidth = max(maxWidth * ((percentage) / 100), minWidth)
|
|
|
|
case .value(let value):
|
|
newWidth = value > maxWidth ? maxWidth : value
|
|
|
|
case nil:
|
|
newWidth = maxWidth
|
|
}
|
|
|
|
widthConstraint?.deactivate()
|
|
trailingLessThanEqualsConstraint?.deactivate()
|
|
trailingEqualsConstraint?.deactivate()
|
|
|
|
if newWidth > minWidth && newWidth < maxWidth {
|
|
widthConstraint?.constant = newWidth
|
|
widthConstraint?.activate()
|
|
trailingLessThanEqualsConstraint?.activate()
|
|
} else {
|
|
trailingEqualsConstraint?.activate()
|
|
}
|
|
}
|
|
}
|