// // TileletGroup.swift // VDS // // Created by Matt Bruce on 10/8/24. // import Foundation import UIKit import VDSCoreTokens import Combine open class TileletGroup: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- /// CollectionView to show the rows and columns private lazy var matrixView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: flowLayout).with { $0.register(TileletGroupCellItem.self, forCellWithReuseIdentifier: TileletGroupCellItem.Identifier) $0.dataSource = self $0.delegate = self $0.translatesAutoresizingMaskIntoConstraints = false $0.allowsSelection = false $0.showsVerticalScrollIndicator = false $0.showsHorizontalScrollIndicator = false $0.isAccessibilityElement = true $0.backgroundColor = .clear } /// Custom flow layout to manage the height of the cells private lazy var flowLayout = TileletGroupFlowLayout().with { $0.delegate = self $0.scrollDirection = .horizontal } /// Parameter to show the all table rows private var rows: [[Tilelet]] = [] { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- /// Enums used to define the padding for the cell edge spacing. public enum Padding: String, CaseIterable { case standard, compact var value: CGFloat { switch self { case .standard: return UIDevice.isIPad ? 40.0 : VDSLayout.space3X case .compact: return UIDevice.isIPad ? VDSLayout.space6X : VDSLayout.space3X } } func horizontalValue() -> CGFloat { value } func verticalValue() -> CGFloat { value } } //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- /// Parameter to set the padding for the cell open var padding: Padding = .standard { didSet { setNeedsUpdate() } } /// An object containing number of Button components per row for iPhones open var rowQuantityPhone: Int = 2 { didSet { updateRows() } } /// An object containing number of Button components per row for iPads open var rowQuantityTablet: Int = 4 { didSet { updateRows() } } /// An object containing number of Button components per row open var rowQuantity: Int { UIDevice.isIPad ? min(rowQuantityTablet,6) : min(rowQuantityPhone, 3) } open var tilelets: [Tilelet] = [] { didSet { updateRows() } } //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- ///Called upon initializing the table view open override func setup() { super.setup() addSubview(matrixView) matrixView.pinToSuperView() } /// Will update the table view, when called becasue of any changes in component parameters open override func updateView() { super.updateView() flowLayout.verticalPadding = padding.verticalValue() flowLayout.horizontalPadding = padding.horizontalValue() matrixView.reloadData() matrixView.collectionViewLayout.invalidateLayout() } open override func setDefaults() { super.setDefaults() padding = .standard rows = [[]] } func updateRows() { var tempRows: [[Tilelet]] = [] for i in stride(from: 0, to: tilelets.count, by: rowQuantity) { let endIndex = min(i + rowQuantity, tilelets.count) let row = Array(tilelets[i.. Int { return rows.count } public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return rows[section].count } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TileletGroupCellItem.Identifier, for: indexPath) as? TileletGroupCellItem else { return UICollectionViewCell() } let currentItem = rows[indexPath.section][indexPath.row] cell.updateCell(component: currentItem) // let rowColors: (UIColor,UIColor) = indexPath.section % 2 == 0 ? (.green, .yellow) : (.blue, .brown) // cell.backgroundColor = indexPath.row % 2 == 0 ? rowColors.0 : rowColors.1 return cell } //-------------------------------------------------- // MARK: - TableCollectionViewLayoutDataDelegate //-------------------------------------------------- internal func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> Tilelet { return rows[indexPath.section][indexPath.row] } } final class TileletGroupCellItem: UICollectionViewCell { /// Identifier for TableCellItem static let Identifier: String = String(describing: TileletGroupCellItem.self) //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- /// Main view which holds the content of the cell private let containerView = View() //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- override init(frame: CGRect) { super.init(frame: frame) setupCell() } required init?(coder: NSCoder) { super.init(coder: coder) setupCell() } private func setupCell() { contentView.backgroundColor = .clear addSubview(containerView) containerView.pinToSuperView() } //-------------------------------------------------- // MARK: - Public Methods //-------------------------------------------------- public func updateCell(component: Tilelet) { containerView.subviews.forEach({ $0.removeFromSuperview() }) containerView.addSubview(component) component.pinToSuperView() } }