// // Table.swift // VDS // // Created by Nadigadda, Sumanth on 24/04/24. // import Foundation import UIKit import VDSTokens @objc(VDSTable) open class Table: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private lazy var matrixView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: flowLayout).with { $0.register(TableCellItem.self, forCellWithReuseIdentifier: TableCellItem.Identifier) $0.dataSource = self $0.delegate = self $0.translatesAutoresizingMaskIntoConstraints = false $0.allowsSelection = false $0.isScrollEnabled = false $0.showsVerticalScrollIndicator = false $0.showsHorizontalScrollIndicator = false $0.isAccessibilityElement = true $0.backgroundColor = .clear } private let flowLayout = MatrixFlowLayout().with { $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize $0.minimumLineSpacing = 0 $0.minimumInteritemSpacing = 0 } //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- public enum Padding: String, CaseIterable { case standard, compact func horizontalValue() -> CGFloat { switch self { case .standard: return UIDevice.isIPad ? VDSLayout.space8X : VDSLayout.space6X case .compact: return UIDevice.isIPad ? VDSLayout.space8X : VDSLayout.space6X } } func verticalValue() -> CGFloat { switch self { case .standard: return UIDevice.isIPad ? VDSLayout.space8X : VDSLayout.space6X case .compact: return UIDevice.isIPad ? VDSLayout.space4X : VDSLayout.space3X } } } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var striped: Bool = false { didSet { setNeedsUpdate() } } open var padding: Padding = .standard { didSet { setNeedsUpdate() } } open var headerBottomLine: Bool = false { didSet { setNeedsUpdate() } } open var rowBottomLine: Bool = false { didSet { setNeedsUpdate() } } open var headerBottomLineType: Line.Style = .primary { didSet { setNeedsUpdate() } } open var rowBottomLineType: Line.Style = .secondary { didSet { setNeedsUpdate() } } open var tableData: [[TableCellModel]]? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- open override func initialSetup() { super.initialSetup() addSubview(matrixView) matrixView.pinToSuperView() } open override func updateView() { super.updateView() matrixView.reloadData() } } extension Table : UICollectionViewDelegate, UICollectionViewDataSource { public func numberOfSections(in collectionView: UICollectionView) -> Int { return tableData?.count ?? 0 } public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return tableData?[section].count ?? 0 } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TableCellItem.Identifier, for: indexPath) as? TableCellItem, let currentItem = tableData?[indexPath.section][indexPath.row] else { return UICollectionViewCell() } let shouldStrip = striped ? (indexPath.section % 2 != 0) : false let style = indexPath.section == 0 ? headerBottomLineType : rowBottomLineType let hideSeparator = indexPath.section == 0 ? headerBottomLine : rowBottomLine cell.updateCell(content: currentItem, surface: surface, separatorStyle: style, isHeader: indexPath.section == 0, hideSeparator: hideSeparator, striped: shouldStrip, padding: padding) return cell } } extension Table: UICollectionViewDelegateFlowLayout { public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { guard let sectionCount = tableData?[indexPath.section].count else { return CGSize.zero } let width = Int(collectionView.frame.width) / sectionCount return CGSize(width: width, height: 100) } }