From 17c5ab948e59cb9594ca9661790cceed9e26cf9e Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Tue, 30 Apr 2024 16:49:45 +0530 Subject: [PATCH 01/24] Initial commit for Table component --- VDS.xcodeproj/project.pbxproj | 16 ++ .../xcshareddata/xcschemes/VDS.xcscheme | 2 +- VDS/Components/Table/Table.swift | 157 ++++++++++++++++++ VDS/Components/Table/TableCellItem.swift | 80 +++++++++ 4 files changed, 254 insertions(+), 1 deletion(-) create mode 100644 VDS/Components/Table/Table.swift create mode 100644 VDS/Components/Table/TableCellItem.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index f805c10f..1d495038 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -20,6 +20,8 @@ 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; }; + 440B84CA2BD8E0E9004A732A /* Table.swift in Sources */ = {isa = PBXBuildFile; fileRef = 440B84C92BD8E0E9004A732A /* Table.swift */; }; + 443DBAFA2BDA303F0021497E /* TableCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 443DBAF92BDA303F0021497E /* TableCellItem.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; @@ -209,6 +211,8 @@ 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = ""; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = ""; }; + 440B84C92BD8E0E9004A732A /* Table.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Table.swift; sourceTree = ""; }; + 443DBAF92BDA303F0021497E /* TableCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellItem.swift; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -427,6 +431,15 @@ path = Breadcrumbs; sourceTree = ""; }; + 440B84C82BD8E0CE004A732A /* Table */ = { + isa = PBXGroup; + children = ( + 440B84C92BD8E0E9004A732A /* Table.swift */, + 443DBAF92BDA303F0021497E /* TableCellItem.swift */, + ); + path = Table; + sourceTree = ""; + }; 445BA07629C07ABA0036A7C5 /* Notification */ = { isa = PBXGroup; children = ( @@ -584,6 +597,7 @@ 71B23C2B2B91FA510027F7D9 /* Pagination */, EA89200B28B530F0006B9984 /* RadioBox */, EAF7F11428A1470D00B287F5 /* RadioButton */, + 440B84C82BD8E0CE004A732A /* Table */, EA596ABB2A16B4D500300C4B /* Tabs */, EAC925852911C9DE00091998 /* TextFields */, EA5E304A294CBDBB0082B959 /* TileContainer */, @@ -1156,6 +1170,7 @@ EAC9258F2911C9DE00091998 /* EntryFieldBase.swift in Sources */, EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */, EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */, + 443DBAFA2BDA303F0021497E /* TableCellItem.swift in Sources */, 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */, EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, @@ -1174,6 +1189,7 @@ EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */, EA0D1C3D2A6AD57600E5C127 /* Typography+Enums.swift in Sources */, EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */, + 440B84CA2BD8E0E9004A732A /* Table.swift in Sources */, EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */, EA8E40912A7D3F6300934ED3 /* UIView+Accessibility.swift in Sources */, EA6F330E2B911E9000BACAB9 /* TextView.swift in Sources */, diff --git a/VDS.xcodeproj/xcshareddata/xcschemes/VDS.xcscheme b/VDS.xcodeproj/xcshareddata/xcschemes/VDS.xcscheme index 470df395..d523a42c 100644 --- a/VDS.xcodeproj/xcshareddata/xcschemes/VDS.xcscheme +++ b/VDS.xcodeproj/xcshareddata/xcschemes/VDS.xcscheme @@ -1,7 +1,7 @@ + version = "1.8"> 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: [[Any]]? { 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) + 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: 50) + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { + //return padding.verticalValue() + return 0 + } + + public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { + //return padding.horizontalValue() + return 0 + } + +} + +final class MatrixFlowLayout : UICollectionViewFlowLayout { + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + guard let layoutAttributesObjects = super.layoutAttributesForElements(in: rect) else { return nil } + layoutAttributesObjects.forEach({ layoutAttributes in + if layoutAttributes.representedElementCategory == .cell, + let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { + layoutAttributes.frame = newFrame + } + }) + return layoutAttributesObjects + } + + override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + guard let collectionView = collectionView, + let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil } + let itemsCount = CGFloat(collectionView.numberOfItems(inSection: indexPath.section)) + layoutAttributes.frame.size.width = ceil(collectionView.safeAreaLayoutGuide.layoutFrame.width / itemsCount) + return layoutAttributes + } +} diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift new file mode 100644 index 00000000..da5a6ee1 --- /dev/null +++ b/VDS/Components/Table/TableCellItem.swift @@ -0,0 +1,80 @@ +// +// TableCellItem.swift +// VDS +// +// Created by Nadigadda, Sumanth on 25/04/24. +// + +import Foundation +import UIKit +import VDSTokens + +final class TableCellItem: UICollectionViewCell { + + static let Identifier: String = String(describing: TableCellItem.self) + + private let containerView = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } + + private var cellLabel = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) + $0.setContentHuggingPriority(.defaultHigh, for:.vertical) + $0.textAlignment = .left + $0.lineBreakMode = .byWordWrapping + } + + private let separator: Line = Line() + + private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) + private let stripedColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundSecondaryLight, VDSColor.backgroundSecondaryDark) + + + 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() + + containerView.addSubview(cellLabel) + cellLabel.pinToSuperView() + + containerView.addSubview(separator) + separator.pinLeading().pinTrailing().pinBottom() + } + + func updateCell(content: Any, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false) { + guard let info = content as? String else { return } + cellLabel.textStyle = textStyle(for: isHeader) + cellLabel.text = info + cellLabel.surface = surface + + containerView.surface = surface + containerView.backgroundColor = striped ? stripedColorConfiguration.getColor(surface) : backgroundColorConfiguration.getColor(surface) + + separator.isHidden = hideSeparator + separator.style = separatorStyle + separator.surface = surface + } + + private func textStyle(for header:Bool) -> TextStyle { + return header ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall + } + + override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { + let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) + layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) + return layoutAttributes + } +} From 39ef411559c7c5ea1b04d4ec5ad9b92f74280a61 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 2 May 2024 13:36:29 +0530 Subject: [PATCH 02/24] Adding padding related changes to table --- VDS/Components/Table/Table.swift | 17 ++++------------- VDS/Components/Table/TableCellItem.swift | 22 ++++++++++++++++++---- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index ded02e63..41945763 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -31,6 +31,8 @@ open class Table: View { private let flowLayout = MatrixFlowLayout().with { $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + $0.minimumLineSpacing = 0 + $0.minimumInteritemSpacing = 0 } //-------------------------------------------------- @@ -109,7 +111,7 @@ extension Table : UICollectionViewDelegate, UICollectionViewDataSource { 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) + cell.updateCell(content: currentItem, surface: surface, separatorStyle: style, isHeader: indexPath.section == 0, hideSeparator: hideSeparator, striped: shouldStrip, padding: padding) return cell } } @@ -119,19 +121,8 @@ 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: 50) + return CGSize(width: width, height: 100) } - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat { - //return padding.verticalValue() - return 0 - } - - public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat { - //return padding.horizontalValue() - return 0 - } - } final class MatrixFlowLayout : UICollectionViewFlowLayout { diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift index da5a6ee1..bfc5a430 100644 --- a/VDS/Components/Table/TableCellItem.swift +++ b/VDS/Components/Table/TableCellItem.swift @@ -30,6 +30,9 @@ final class TableCellItem: UICollectionViewCell { private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) private let stripedColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundSecondaryLight, VDSColor.backgroundSecondaryDark) + private var labelTopConstraint: NSLayoutConstraint? + private var labelBottomConstraint: NSLayoutConstraint? + private var labelTrailingConstraint: NSLayoutConstraint? override init(frame: CGRect) { super.init(frame: frame) @@ -48,13 +51,21 @@ final class TableCellItem: UICollectionViewCell { containerView.pinToSuperView() containerView.addSubview(cellLabel) - cellLabel.pinToSuperView() + cellLabel.pinLeading() + + labelTopConstraint = cellLabel.pinTop(anchor: containerView.topAnchor, constant: 0) + labelBottomConstraint = containerView.pinBottom(anchor: cellLabel.bottomAnchor, constant: 0) + labelTrailingConstraint = containerView.pinTrailing(anchor: cellLabel.trailingAnchor, constant: 0) + + labelTopConstraint?.activate() + labelBottomConstraint?.activate() + labelTrailingConstraint?.activate() containerView.addSubview(separator) separator.pinLeading().pinTrailing().pinBottom() } - func updateCell(content: Any, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false) { + func updateCell(content: Any, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false, padding: Table.Padding = .standard) { guard let info = content as? String else { return } cellLabel.textStyle = textStyle(for: isHeader) cellLabel.text = info @@ -66,6 +77,10 @@ final class TableCellItem: UICollectionViewCell { separator.isHidden = hideSeparator separator.style = separatorStyle separator.surface = surface + + labelTopConstraint?.constant = padding.verticalValue() + labelBottomConstraint?.constant = padding.verticalValue() + labelTrailingConstraint?.constant = padding.horizontalValue() } private func textStyle(for header:Bool) -> TextStyle { @@ -73,8 +88,7 @@ final class TableCellItem: UICollectionViewCell { } override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { - let targetSize = CGSize(width: layoutAttributes.frame.width, height: 0) - layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) + layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(layoutAttributes.frame.size, withHorizontalFittingPriority: .required, verticalFittingPriority: .required) return layoutAttributes } } From d94c845eb3aee196f1cd5d940042f034b7eb1f56 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 2 May 2024 18:47:30 +0530 Subject: [PATCH 03/24] Adding models for the tab cell items --- VDS.xcodeproj/project.pbxproj | 8 +++ VDS/Components/Table/Table.swift | 2 +- VDS/Components/Table/TableCellItem.swift | 60 ++++++++++++------- .../Table/TableCellLabelModel.swift | 39 ++++++++++++ VDS/Components/Table/TableCellModel.swift | 10 ++++ 5 files changed, 96 insertions(+), 23 deletions(-) create mode 100644 VDS/Components/Table/TableCellLabelModel.swift create mode 100644 VDS/Components/Table/TableCellModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index f4a3f1ac..24239140 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -25,6 +25,8 @@ 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; + 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableCellModel.swift */; }; + 44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 710607952B91A99500F2863F /* TitleletChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 710607942B91A99500F2863F /* TitleletChangeLog.txt */; }; @@ -216,6 +218,8 @@ 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; + 44A952D82BE384C40009F874 /* TableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellModel.swift; sourceTree = ""; }; + 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellLabelModel.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = ""; }; @@ -436,6 +440,8 @@ children = ( 440B84C92BD8E0E9004A732A /* Table.swift */, 443DBAF92BDA303F0021497E /* TableCellItem.swift */, + 44A952D82BE384C40009F874 /* TableCellModel.swift */, + 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */, ); path = Table; sourceTree = ""; @@ -1142,6 +1148,7 @@ EAACB89A2B927108006A3869 /* Valuing.swift in Sources */, EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, + 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */, EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */, 71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */, EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, @@ -1211,6 +1218,7 @@ EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */, EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, + 44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */, EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */, diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 41945763..32195467 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -77,7 +77,7 @@ open class Table: View { open var rowBottomLineType: Line.Style = .secondary { didSet { setNeedsUpdate() } } - open var tableData: [[Any]]? { didSet { setNeedsUpdate() } } + open var tableData: [[TableCellModel]]? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Overrides diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift index bfc5a430..7c2a1cdd 100644 --- a/VDS/Components/Table/TableCellItem.swift +++ b/VDS/Components/Table/TableCellItem.swift @@ -25,6 +25,10 @@ final class TableCellItem: UICollectionViewCell { $0.lineBreakMode = .byWordWrapping } + private var icon = Icon().with { + $0.size = UIDevice.isIPad ? .medium : .small + } + private let separator: Line = Line() private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) @@ -49,38 +53,50 @@ final class TableCellItem: UICollectionViewCell { addSubview(containerView) containerView.pinToSuperView() - - containerView.addSubview(cellLabel) - cellLabel.pinLeading() - - labelTopConstraint = cellLabel.pinTop(anchor: containerView.topAnchor, constant: 0) - labelBottomConstraint = containerView.pinBottom(anchor: cellLabel.bottomAnchor, constant: 0) - labelTrailingConstraint = containerView.pinTrailing(anchor: cellLabel.trailingAnchor, constant: 0) - - labelTopConstraint?.activate() - labelBottomConstraint?.activate() - labelTrailingConstraint?.activate() - - containerView.addSubview(separator) - separator.pinLeading().pinTrailing().pinBottom() } - func updateCell(content: Any, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false, padding: Table.Padding = .standard) { - guard let info = content as? String else { return } - cellLabel.textStyle = textStyle(for: isHeader) - cellLabel.text = info - cellLabel.surface = surface + func updateCell(content: TableCellModel, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false, padding: Table.Padding = .standard) { + + containerView.subviews.forEach({ $0.removeFromSuperview() }) containerView.surface = surface containerView.backgroundColor = striped ? stripedColorConfiguration.getColor(surface) : backgroundColorConfiguration.getColor(surface) + if let model = content as? Table.TableCellLabelModel { + addLabel(model: model, surface: surface, isHeader: isHeader, padding: padding) + } else if let model = content as? Table.TableCellImageModel { + addImage(model: model, surface: surface) + } + + containerView.addSubview(separator) + separator.pinLeading().pinTrailing().pinBottom() + separator.isHidden = hideSeparator separator.style = separatorStyle separator.surface = surface + } + + private func addLabel(model: Table.TableCellLabelModel, surface: Surface, isHeader: Bool, padding: Table.Padding) { + + containerView.addSubview(cellLabel) + cellLabel.pinLeading(VDSLayout.space1X) + NSLayoutConstraint.activate([ + cellLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: padding.verticalValue()), + containerView.bottomAnchor.constraint(equalTo: cellLabel.bottomAnchor, constant: padding.verticalValue()), + containerView.trailingAnchor.constraint(equalTo: cellLabel.trailingAnchor, constant: padding.horizontalValue()) + ]) - labelTopConstraint?.constant = padding.verticalValue() - labelBottomConstraint?.constant = padding.verticalValue() - labelTrailingConstraint?.constant = padding.horizontalValue() + cellLabel.textStyle = textStyle(for: isHeader) + cellLabel.text = model.text + cellLabel.surface = surface + } + + private func addImage(model: Table.TableCellImageModel, surface: Surface) { + containerView.addSubview(icon) + icon.pinLeading().pinCenterY() + + icon.name = model.name + icon.surface = surface } private func textStyle(for header:Bool) -> TextStyle { diff --git a/VDS/Components/Table/TableCellLabelModel.swift b/VDS/Components/Table/TableCellLabelModel.swift new file mode 100644 index 00000000..158c9bd4 --- /dev/null +++ b/VDS/Components/Table/TableCellLabelModel.swift @@ -0,0 +1,39 @@ +// +// TableCellLabelModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 02/05/24. +// + +import Foundation +extension Table { + public struct TableCellLabelModel: TableCellModel, Surfaceable { + + public var text: String + + public var accessibilityString: String? + + public var surface: Surface + + public init(text: String, accessibilityString: String? = "", surface: Surface = .light) { + self.text = text + self.accessibilityString = accessibilityString + self.surface = surface + } + } + + public struct TableCellImageModel: TableCellModel, Surfaceable { + + public var name: Icon.Name + + public var size: Icon.Size + + public var surface: Surface + + public init(name: Icon.Name, size: Icon.Size, surface: Surface = .light) { + self.name = name + self.size = size + self.surface = surface + } + } +} diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift new file mode 100644 index 00000000..38ac8a3f --- /dev/null +++ b/VDS/Components/Table/TableCellModel.swift @@ -0,0 +1,10 @@ +// +// TableCellModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 02/05/24. +// + +import Foundation + +public protocol TableCellModel { } From e1589577fef2a1f69e42f5a0b03b778e6f06df31 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 2 May 2024 19:59:22 +0530 Subject: [PATCH 04/24] Moving flow layout to a new class --- VDS.xcodeproj/project.pbxproj | 4 +++ VDS/Components/Table/Table.swift | 22 ---------------- VDS/Components/Table/TableFlowLayout.swift | 30 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 22 deletions(-) create mode 100644 VDS/Components/Table/TableFlowLayout.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 24239140..0d91c8f8 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableCellModel.swift */; }; 44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */; }; + 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 710607952B91A99500F2863F /* TitleletChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 710607942B91A99500F2863F /* TitleletChangeLog.txt */; }; @@ -220,6 +221,7 @@ 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; 44A952D82BE384C40009F874 /* TableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellModel.swift; sourceTree = ""; }; 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellLabelModel.swift; sourceTree = ""; }; + 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableFlowLayout.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = ""; }; @@ -440,6 +442,7 @@ children = ( 440B84C92BD8E0E9004A732A /* Table.swift */, 443DBAF92BDA303F0021497E /* TableCellItem.swift */, + 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */, 44A952D82BE384C40009F874 /* TableCellModel.swift */, 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */, ); @@ -1226,6 +1229,7 @@ EA985BF02968A93600F2FF2E /* TitleLockupEyebrowModel.swift in Sources */, EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */, EAD062B02A3B873E0015965D /* BadgeIndicator.swift in Sources */, + 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */, EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */, 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */, EA0B18062A9E2D2D00F2D0CD /* SelectorItemBase.swift in Sources */, diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 32195467..267ae6a5 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -124,25 +124,3 @@ extension Table: UICollectionViewDelegateFlowLayout { return CGSize(width: width, height: 100) } } - -final class MatrixFlowLayout : UICollectionViewFlowLayout { - - override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { - guard let layoutAttributesObjects = super.layoutAttributesForElements(in: rect) else { return nil } - layoutAttributesObjects.forEach({ layoutAttributes in - if layoutAttributes.representedElementCategory == .cell, - let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { - layoutAttributes.frame = newFrame - } - }) - return layoutAttributesObjects - } - - override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { - guard let collectionView = collectionView, - let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil } - let itemsCount = CGFloat(collectionView.numberOfItems(inSection: indexPath.section)) - layoutAttributes.frame.size.width = ceil(collectionView.safeAreaLayoutGuide.layoutFrame.width / itemsCount) - return layoutAttributes - } -} diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift new file mode 100644 index 00000000..8cb92de2 --- /dev/null +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -0,0 +1,30 @@ +// +// TableFlowLayout.swift +// VDS +// +// Created by Nadigadda, Sumanth on 02/05/24. +// + +import UIKit + +final class MatrixFlowLayout : UICollectionViewFlowLayout { + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + guard let layoutAttributesObjects = super.layoutAttributesForElements(in: rect) else { return nil } + layoutAttributesObjects.forEach({ layoutAttributes in + if layoutAttributes.representedElementCategory == .cell, + let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { + layoutAttributes.frame = newFrame + } + }) + return layoutAttributesObjects + } + + override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + guard let collectionView = collectionView, + let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil } + let itemsCount = CGFloat(collectionView.numberOfItems(inSection: indexPath.section)) + layoutAttributes.frame.size.width = ceil(collectionView.safeAreaLayoutGuide.layoutFrame.width / itemsCount) + return layoutAttributes + } +} From ed684acd620b6a51c6b76d879e25bc571b4887db Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 6 May 2024 16:00:35 +0530 Subject: [PATCH 05/24] Table component, changing the way collectionViewlayout measures the sizes of the cell & minor improvements --- VDS.xcodeproj/project.pbxproj | 4 + VDS/Components/Table/Table.swift | 30 ++--- .../Table/TableCellImageModel.swift | 28 +++++ VDS/Components/Table/TableCellItem.swift | 24 ++-- .../Table/TableCellLabelModel.swift | 18 +-- VDS/Components/Table/TableCellModel.swift | 4 +- VDS/Components/Table/TableFlowLayout.swift | 117 ++++++++++++++++-- 7 files changed, 166 insertions(+), 59 deletions(-) create mode 100644 VDS/Components/Table/TableCellImageModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 0d91c8f8..c9df4b12 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; + 446209482BE8E3AF003EBC19 /* TableCellImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */; }; 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableCellModel.swift */; }; 44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */; }; 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */; }; @@ -219,6 +220,7 @@ 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; + 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellImageModel.swift; sourceTree = ""; }; 44A952D82BE384C40009F874 /* TableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellModel.swift; sourceTree = ""; }; 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellLabelModel.swift; sourceTree = ""; }; 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableFlowLayout.swift; sourceTree = ""; }; @@ -445,6 +447,7 @@ 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */, 44A952D82BE384C40009F874 /* TableCellModel.swift */, 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */, + 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */, ); path = Table; sourceTree = ""; @@ -1242,6 +1245,7 @@ EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */, EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */, EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */, + 446209482BE8E3AF003EBC19 /* TableCellImageModel.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, EA33623E2892EE950071C351 /* UIDevice.swift in Sources */, EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */, diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 267ae6a5..40b3e089 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -29,10 +29,8 @@ open class Table: View { $0.backgroundColor = .clear } - private let flowLayout = MatrixFlowLayout().with { - $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize - $0.minimumLineSpacing = 0 - $0.minimumInteritemSpacing = 0 + private lazy var flowLayout = MatrixFlowLayout().with { + $0.delegate = self } //-------------------------------------------------- @@ -77,7 +75,7 @@ open class Table: View { open var rowBottomLineType: Line.Style = .secondary { didSet { setNeedsUpdate() } } - open var tableData: [[TableCellModel]]? { didSet { setNeedsUpdate() } } + open var tableData: [[TableCellModel]] = [] { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Overrides @@ -91,36 +89,32 @@ open class Table: View { open override func updateView() { super.updateView() + flowLayout.layoutPadding = padding matrixView.reloadData() + matrixView.collectionViewLayout.invalidateLayout() } } -extension Table : UICollectionViewDelegate, UICollectionViewDataSource { +extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableCollectionViewLayoutDataDelegate { public func numberOfSections(in collectionView: UICollectionView) -> Int { - return tableData?.count ?? 0 + return tableData.count } public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return tableData?[section].count ?? 0 + return tableData[section].count } 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() } + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TableCellItem.Identifier, for: indexPath) as? TableCellItem else { return UICollectionViewCell() } + let currentItem = tableData[indexPath.section][indexPath.row] 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) + func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel { + return tableData[indexPath.section][indexPath.row] } } diff --git a/VDS/Components/Table/TableCellImageModel.swift b/VDS/Components/Table/TableCellImageModel.swift new file mode 100644 index 00000000..883315f3 --- /dev/null +++ b/VDS/Components/Table/TableCellImageModel.swift @@ -0,0 +1,28 @@ +// +// TableCellImageModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 06/05/24. +// + +import Foundation + +extension Table { + + public struct TableCellImageModel: TableCellModel, Surfaceable { + + public var defaultHeight: CGFloat { return 50.0 } + + public var name: Icon.Name + + public var size: Icon.Size + + public var surface: Surface + + public init(name: Icon.Name, size: Icon.Size, surface: Surface = .light) { + self.name = name + self.size = size + self.surface = surface + } + } +} diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift index 7c2a1cdd..1d1c9255 100644 --- a/VDS/Components/Table/TableCellItem.swift +++ b/VDS/Components/Table/TableCellItem.swift @@ -13,9 +13,7 @@ final class TableCellItem: UICollectionViewCell { static let Identifier: String = String(describing: TableCellItem.self) - private let containerView = View().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } + private let containerView = View() private var cellLabel = Label().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -34,9 +32,7 @@ final class TableCellItem: UICollectionViewCell { private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) private let stripedColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundSecondaryLight, VDSColor.backgroundSecondaryDark) - private var labelTopConstraint: NSLayoutConstraint? - private var labelBottomConstraint: NSLayoutConstraint? - private var labelTrailingConstraint: NSLayoutConstraint? + private var padding: Table.Padding = .standard override init(frame: CGRect) { super.init(frame: frame) @@ -58,7 +54,7 @@ final class TableCellItem: UICollectionViewCell { func updateCell(content: TableCellModel, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false, padding: Table.Padding = .standard) { containerView.subviews.forEach({ $0.removeFromSuperview() }) - + self.padding = padding containerView.surface = surface containerView.backgroundColor = striped ? stripedColorConfiguration.getColor(surface) : backgroundColorConfiguration.getColor(surface) @@ -71,7 +67,7 @@ final class TableCellItem: UICollectionViewCell { containerView.addSubview(separator) separator.pinLeading().pinTrailing().pinBottom() - separator.isHidden = hideSeparator + separator.isHidden = !hideSeparator separator.style = separatorStyle separator.surface = surface } @@ -103,8 +99,12 @@ final class TableCellItem: UICollectionViewCell { return header ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall } - override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { - layoutAttributes.frame.size = contentView.systemLayoutSizeFitting(layoutAttributes.frame.size, withHorizontalFittingPriority: .required, verticalFittingPriority: .required) - return layoutAttributes - } +// override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { +// let labelWidth = layoutAttributes.frame.size.width - (2 * padding.horizontalValue()) +// let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) +// let labelSize = cellLabel.textRect(forBounds: CGRect(origin: .zero, size: maxbounds), limitedToNumberOfLines: cellLabel.numberOfLines) +// var labelHeight = max(labelSize.height, layoutAttributes.frame.size.height) + (2 * padding.horizontalValue()) +// layoutAttributes.frame.size = CGSize(width: layoutAttributes.frame.size.width, height: labelHeight) +// return layoutAttributes +// } } diff --git a/VDS/Components/Table/TableCellLabelModel.swift b/VDS/Components/Table/TableCellLabelModel.swift index 158c9bd4..2f2d4297 100644 --- a/VDS/Components/Table/TableCellLabelModel.swift +++ b/VDS/Components/Table/TableCellLabelModel.swift @@ -6,9 +6,12 @@ // import Foundation + extension Table { public struct TableCellLabelModel: TableCellModel, Surfaceable { + public var defaultHeight: CGFloat { return 50.0 } + public var text: String public var accessibilityString: String? @@ -21,19 +24,4 @@ extension Table { self.surface = surface } } - - public struct TableCellImageModel: TableCellModel, Surfaceable { - - public var name: Icon.Name - - public var size: Icon.Size - - public var surface: Surface - - public init(name: Icon.Name, size: Icon.Size, surface: Surface = .light) { - self.name = name - self.size = size - self.surface = surface - } - } } diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift index 38ac8a3f..5e92ebe8 100644 --- a/VDS/Components/Table/TableCellModel.swift +++ b/VDS/Components/Table/TableCellModel.swift @@ -7,4 +7,6 @@ import Foundation -public protocol TableCellModel { } +public protocol TableCellModel { + var defaultHeight: CGFloat { get } +} diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift index 8cb92de2..8b6f313b 100644 --- a/VDS/Components/Table/TableFlowLayout.swift +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -6,25 +6,116 @@ // import UIKit +import VDSTokens -final class MatrixFlowLayout : UICollectionViewFlowLayout { +protocol TableCollectionViewLayoutDataDelegate: AnyObject { + func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel +} + +class MatrixFlowLayout : UICollectionViewLayout { + + weak var delegate: TableCollectionViewLayoutDataDelegate? + + var layoutPadding: Table.Padding = .standard + + var itemCache: [UICollectionViewLayoutAttributes] = [] + + var layoutHeight: CGFloat = 0.0 + + override func prepare() { + super.prepare() + + itemCache.removeAll() + + layoutHeight = 0.0 + + guard let collectionView, let delegate else { return } + + let sections = collectionView.numberOfSections + + var yPos: CGFloat = 0.0 + + for currentSection in 0.. $1.frame.size.height }).first?.frame.size.height ?? 0.0 + + itemCache.filter({$0.indexPath.section == currentSection}).forEach { attributes in + attributes.frame.size.height = highestHeightForSection + } + + yPos += highestHeightForSection + } + + layoutHeight = yPos + } + + + private func estimateHeightFor(item: TableCellModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat { + + if let model = item as? Table.TableCellLabelModel { + return estimatedHeightForLabel(item: model, with: width, padding: padding, isHeader: isHeader) + } + return (item.defaultHeight + (2 * padding.verticalValue())) + } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { - guard let layoutAttributesObjects = super.layoutAttributesForElements(in: rect) else { return nil } - layoutAttributesObjects.forEach({ layoutAttributes in - if layoutAttributes.representedElementCategory == .cell, - let newFrame = layoutAttributesForItem(at: layoutAttributes.indexPath)?.frame { - layoutAttributes.frame = newFrame + var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = [] + for attributes in itemCache { + if attributes.frame.intersects(rect) { + visibleLayoutAttributes.append(attributes) } - }) - return layoutAttributesObjects + } + return visibleLayoutAttributes } override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { - guard let collectionView = collectionView, - let layoutAttributes = super.layoutAttributesForItem(at: indexPath) else { return nil } - let itemsCount = CGFloat(collectionView.numberOfItems(inSection: indexPath.section)) - layoutAttributes.frame.size.width = ceil(collectionView.safeAreaLayoutGuide.layoutFrame.width / itemsCount) - return layoutAttributes + return itemCache.filter({ $0.indexPath == indexPath}).first + } + + override var collectionViewContentSize: CGSize { + return CGSize(width: contentWidth, height: layoutHeight) + } + + private var contentWidth: CGFloat { + guard let collectionView = collectionView else { return 0 } + return collectionView.bounds.width + } +} + +extension MatrixFlowLayout { + + private func estimatedHeightForLabel(item: Table.TableCellLabelModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat { + + let cellLabel = Label() + cellLabel.textStyle = isHeader ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall + cellLabel.text = item.text + + let labelWidth = width - padding.horizontalValue() - VDSLayout.space1X + let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) + let labelSize = cellLabel.sizeThatFits(maxbounds) + return labelSize.height + (2 * padding.verticalValue()) } } From 0d421190a203444f3604bc066a3a3ef56914784d Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Thu, 9 May 2024 18:24:02 +0530 Subject: [PATCH 06/24] Table component refactoring --- VDS.xcodeproj/project.pbxproj | 8 --- VDS/Components/Table/Table.swift | 20 +++--- .../Table/TableCellImageModel.swift | 28 -------- VDS/Components/Table/TableCellItem.swift | 70 ++++--------------- .../Table/TableCellLabelModel.swift | 27 ------- VDS/Components/Table/TableCellModel.swift | 35 +++++++++- VDS/Components/Table/TableFlowLayout.swift | 28 ++------ 7 files changed, 62 insertions(+), 154 deletions(-) delete mode 100644 VDS/Components/Table/TableCellImageModel.swift delete mode 100644 VDS/Components/Table/TableCellLabelModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index c9df4b12..9cc1431b 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -25,9 +25,7 @@ 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; - 446209482BE8E3AF003EBC19 /* TableCellImageModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */; }; 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableCellModel.swift */; }; - 44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */; }; 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; @@ -220,9 +218,7 @@ 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; - 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellImageModel.swift; sourceTree = ""; }; 44A952D82BE384C40009F874 /* TableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellModel.swift; sourceTree = ""; }; - 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellLabelModel.swift; sourceTree = ""; }; 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableFlowLayout.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; @@ -446,8 +442,6 @@ 443DBAF92BDA303F0021497E /* TableCellItem.swift */, 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */, 44A952D82BE384C40009F874 /* TableCellModel.swift */, - 44A952DA2BE3852E0009F874 /* TableCellLabelModel.swift */, - 446209472BE8E3AF003EBC19 /* TableCellImageModel.swift */, ); path = Table; sourceTree = ""; @@ -1224,7 +1218,6 @@ EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */, EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, - 44A952DB2BE3852E0009F874 /* TableCellLabelModel.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */, EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */, @@ -1245,7 +1238,6 @@ EA0D1C392A6AD4DF00E5C127 /* Typography+SpacingConfig.swift in Sources */, EAB2376629E9952D00AABE9A /* UIApplication.swift in Sources */, EAB5FED429267EB300998C17 /* UIView+NSLayoutConstraint.swift in Sources */, - 446209482BE8E3AF003EBC19 /* TableCellImageModel.swift in Sources */, EAB2376829E9992800AABE9A /* TooltipAlertViewController.swift in Sources */, EA33623E2892EE950071C351 /* UIDevice.swift in Sources */, EA985C692971B90B00F2FF2E /* IconSize.swift in Sources */, diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 40b3e089..a7f89a7d 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -32,6 +32,10 @@ open class Table: View { private lazy var flowLayout = MatrixFlowLayout().with { $0.delegate = self } + + private var tableData: [[TableItemModel]] { + return tableHeader + tableRows + } //-------------------------------------------------- // MARK: - Enums @@ -67,15 +71,9 @@ open class Table: View { open var padding: Padding = .standard { didSet { setNeedsUpdate() } } - open var headerBottomLine: Bool = false { didSet { setNeedsUpdate() } } + open var tableHeader: [[TableItemModel]] = [] { 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() } } + open var tableRows: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Overrides @@ -108,13 +106,11 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TableCellItem.Identifier, for: indexPath) as? TableCellItem else { return UICollectionViewCell() } let currentItem = tableData[indexPath.section][indexPath.row] 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) + cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: padding) return cell } - func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel { + func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel { return tableData[indexPath.section][indexPath.row] } } diff --git a/VDS/Components/Table/TableCellImageModel.swift b/VDS/Components/Table/TableCellImageModel.swift deleted file mode 100644 index 883315f3..00000000 --- a/VDS/Components/Table/TableCellImageModel.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// TableCellImageModel.swift -// VDS -// -// Created by Nadigadda, Sumanth on 06/05/24. -// - -import Foundation - -extension Table { - - public struct TableCellImageModel: TableCellModel, Surfaceable { - - public var defaultHeight: CGFloat { return 50.0 } - - public var name: Icon.Name - - public var size: Icon.Size - - public var surface: Surface - - public init(name: Icon.Name, size: Icon.Size, surface: Surface = .light) { - self.name = name - self.size = size - self.surface = surface - } - } -} diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift index 1d1c9255..989e8eef 100644 --- a/VDS/Components/Table/TableCellItem.swift +++ b/VDS/Components/Table/TableCellItem.swift @@ -15,18 +15,6 @@ final class TableCellItem: UICollectionViewCell { private let containerView = View() - private var cellLabel = Label().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) - $0.setContentHuggingPriority(.defaultHigh, for:.vertical) - $0.textAlignment = .left - $0.lineBreakMode = .byWordWrapping - } - - private var icon = Icon().with { - $0.size = UIDevice.isIPad ? .medium : .small - } - private let separator: Line = Line() private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) @@ -51,60 +39,32 @@ final class TableCellItem: UICollectionViewCell { containerView.pinToSuperView() } - func updateCell(content: TableCellModel, surface: Surface, separatorStyle: Line.Style, isHeader: Bool = false, hideSeparator: Bool = false, striped: Bool = false, padding: Table.Padding = .standard) { + func updateCell(content: TableItemModel, surface: Surface, striped: Bool = false, padding: Table.Padding = .standard) { containerView.subviews.forEach({ $0.removeFromSuperview() }) self.padding = padding containerView.surface = surface containerView.backgroundColor = striped ? stripedColorConfiguration.getColor(surface) : backgroundColorConfiguration.getColor(surface) - if let model = content as? Table.TableCellLabelModel { - addLabel(model: model, surface: surface, isHeader: isHeader, padding: padding) - } else if let model = content as? Table.TableCellImageModel { - addImage(model: model, surface: surface) + containerView.addSubview(content.component) + + if var surfacedView = content.component as? Surfaceable { + surfacedView.surface = surface } + NSLayoutConstraint.activate([ + content.component.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: VDSLayout.space1X), + content.component.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: padding.verticalValue()), + containerView.bottomAnchor.constraint(greaterThanOrEqualTo: content.component.bottomAnchor, constant: padding.verticalValue()), + containerView.trailingAnchor.constraint(greaterThanOrEqualTo: content.component.trailingAnchor, constant: padding.horizontalValue()), + containerView.centerYAnchor.constraint(equalTo: content.component.centerYAnchor) + ]) + containerView.addSubview(separator) separator.pinLeading().pinTrailing().pinBottom() - separator.isHidden = !hideSeparator - separator.style = separatorStyle + separator.style = content.bottomLine ?? .primary + separator.isHidden = content.bottomLine == nil separator.surface = surface } - - private func addLabel(model: Table.TableCellLabelModel, surface: Surface, isHeader: Bool, padding: Table.Padding) { - - containerView.addSubview(cellLabel) - cellLabel.pinLeading(VDSLayout.space1X) - NSLayoutConstraint.activate([ - cellLabel.topAnchor.constraint(equalTo: containerView.topAnchor, constant: padding.verticalValue()), - containerView.bottomAnchor.constraint(equalTo: cellLabel.bottomAnchor, constant: padding.verticalValue()), - containerView.trailingAnchor.constraint(equalTo: cellLabel.trailingAnchor, constant: padding.horizontalValue()) - ]) - - cellLabel.textStyle = textStyle(for: isHeader) - cellLabel.text = model.text - cellLabel.surface = surface - } - - private func addImage(model: Table.TableCellImageModel, surface: Surface) { - containerView.addSubview(icon) - icon.pinLeading().pinCenterY() - - icon.name = model.name - icon.surface = surface - } - - private func textStyle(for header:Bool) -> TextStyle { - return header ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall - } - -// override func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { -// let labelWidth = layoutAttributes.frame.size.width - (2 * padding.horizontalValue()) -// let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) -// let labelSize = cellLabel.textRect(forBounds: CGRect(origin: .zero, size: maxbounds), limitedToNumberOfLines: cellLabel.numberOfLines) -// var labelHeight = max(labelSize.height, layoutAttributes.frame.size.height) + (2 * padding.horizontalValue()) -// layoutAttributes.frame.size = CGSize(width: layoutAttributes.frame.size.width, height: labelHeight) -// return layoutAttributes -// } } diff --git a/VDS/Components/Table/TableCellLabelModel.swift b/VDS/Components/Table/TableCellLabelModel.swift deleted file mode 100644 index 2f2d4297..00000000 --- a/VDS/Components/Table/TableCellLabelModel.swift +++ /dev/null @@ -1,27 +0,0 @@ -// -// TableCellLabelModel.swift -// VDS -// -// Created by Nadigadda, Sumanth on 02/05/24. -// - -import Foundation - -extension Table { - public struct TableCellLabelModel: TableCellModel, Surfaceable { - - public var defaultHeight: CGFloat { return 50.0 } - - public var text: String - - public var accessibilityString: String? - - public var surface: Surface - - public init(text: String, accessibilityString: String? = "", surface: Surface = .light) { - self.text = text - self.accessibilityString = accessibilityString - self.surface = surface - } - } -} diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift index 5e92ebe8..82e33500 100644 --- a/VDS/Components/Table/TableCellModel.swift +++ b/VDS/Components/Table/TableCellModel.swift @@ -6,7 +6,38 @@ // import Foundation +import UIKit +import VDSTokens -public protocol TableCellModel { - var defaultHeight: CGFloat { get } +public protocol ComponentHeight { + func estimatedHeight(for width: CGFloat) -> CGFloat? +} + +public struct TableItemModel { + + public var defaultHeight: CGFloat { return 50.0 } + + public var bottomLine: Line.Style? + + public var component: UIView & ComponentHeight + + public init(bottomLine: Line.Style? = nil, component: UIView & ComponentHeight) { + self.bottomLine = bottomLine + self.component = component + } +} + +extension Label: ComponentHeight { + + public func estimatedHeight(for width: CGFloat) -> CGFloat? { + let maxbounds = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) + return self.sizeThatFits(maxbounds).height + } +} + +extension Icon: ComponentHeight { + + public func estimatedHeight(for width: CGFloat) -> CGFloat? { + return intrinsicContentSize.height + } } diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift index 8b6f313b..a3d8e817 100644 --- a/VDS/Components/Table/TableFlowLayout.swift +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -9,7 +9,7 @@ import UIKit import VDSTokens protocol TableCollectionViewLayoutDataDelegate: AnyObject { - func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableCellModel + func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel } class MatrixFlowLayout : UICollectionViewLayout { @@ -47,7 +47,7 @@ class MatrixFlowLayout : UICollectionViewLayout { let selectedItem = delegate.collectionView(collectionView, dataForItemAt: indexPath) - let itemHeight = estimateHeightFor(item: selectedItem, with: itemWidth, padding: layoutPadding, isHeader: currentSection == 0) + let itemHeight = estimateHeightFor(item: selectedItem, with: itemWidth) let attribute = UICollectionViewLayoutAttributes(forCellWith: indexPath) @@ -73,12 +73,11 @@ class MatrixFlowLayout : UICollectionViewLayout { } - private func estimateHeightFor(item: TableCellModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat { + private func estimateHeightFor(item: TableItemModel, with width: CGFloat) -> CGFloat { - if let model = item as? Table.TableCellLabelModel { - return estimatedHeightForLabel(item: model, with: width, padding: padding, isHeader: isHeader) - } - return (item.defaultHeight + (2 * padding.verticalValue())) + let itemWidth = width - layoutPadding.horizontalValue() - VDSLayout.space1X + let height = item.component.estimatedHeight(for: itemWidth) ?? 0 + return height + (2 * layoutPadding.verticalValue()) } override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { @@ -104,18 +103,3 @@ class MatrixFlowLayout : UICollectionViewLayout { return collectionView.bounds.width } } - -extension MatrixFlowLayout { - - private func estimatedHeightForLabel(item: Table.TableCellLabelModel, with width: CGFloat, padding: Table.Padding, isHeader: Bool) -> CGFloat { - - let cellLabel = Label() - cellLabel.textStyle = isHeader ? .boldTitleSmall : UIDevice.isIPad ? .bodyLarge : .bodySmall - cellLabel.text = item.text - - let labelWidth = width - padding.horizontalValue() - VDSLayout.space1X - let maxbounds = CGSize(width: labelWidth, height: CGFloat.greatestFiniteMagnitude) - let labelSize = cellLabel.sizeThatFits(maxbounds) - return labelSize.height + (2 * padding.verticalValue()) - } -} From d4957e5aecd27f18b96d43ee35262bf7b33dd8ea Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Tue, 14 May 2024 19:09:03 +0530 Subject: [PATCH 07/24] Adding comments to the Table components implementation. --- VDS/Components/Table/Table.swift | 32 +++++++++++++++- VDS/Components/Table/TableCellItem.swift | 21 ++++++++++- VDS/Components/Table/TableCellModel.swift | 5 +++ VDS/Components/Table/TableFlowLayout.swift | 44 ++++++++++++++++++---- 4 files changed, 93 insertions(+), 9 deletions(-) diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index a7f89a7d..3c290a80 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -9,13 +9,15 @@ import Foundation import UIKit import VDSTokens +///Table is view composed of rows and columns, which takes any view into each cell and resizes based on the highest cell height. @objc(VDSTable) open class Table: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - + + /// CollectionView to show the rows and columns private lazy var matrixView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: flowLayout).with { $0.register(TableCellItem.self, forCellWithReuseIdentifier: TableCellItem.Identifier) $0.dataSource = self @@ -29,10 +31,12 @@ open class Table: View { $0.backgroundColor = .clear } + /// Custom flow layout to manage the height of the cells private lazy var flowLayout = MatrixFlowLayout().with { $0.delegate = self } + /// Array of ``TableItemModel`` by combining Header & Row items private var tableData: [[TableItemModel]] { return tableHeader + tableRows } @@ -41,6 +45,7 @@ open class Table: View { // MARK: - Enums //-------------------------------------------------- + /// Enums used to define the padding for the cell edge spacing. public enum Padding: String, CaseIterable { case standard, compact @@ -67,34 +72,55 @@ open class Table: View { // MARK: - Public Properties //-------------------------------------------------- + /// Parameter to set striped status for the table open var striped: Bool = false { didSet { setNeedsUpdate() } } + /// Parameter to set the padding for the cell open var padding: Padding = .standard { didSet { setNeedsUpdate() } } + /// Parameter to show the table header row open var tableHeader: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } + /// Parameter to show the all table rows open var tableRows: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- + ///Called upon initializing the table view open override func initialSetup() { super.initialSetup() 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.layoutPadding = padding matrixView.reloadData() matrixView.collectionViewLayout.invalidateLayout() } + + /// Resets to default settings. + open override func reset() { + super.reset() + striped = false + padding = .standard + tableHeader = [] + tableRows = [] + setNeedsUpdate() + } } extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableCollectionViewLayoutDataDelegate { + //-------------------------------------------------- + // MARK: - UICollectionViewDelegate & UICollectionViewDataSource + //-------------------------------------------------- + public func numberOfSections(in collectionView: UICollectionView) -> Int { return tableData.count } @@ -110,6 +136,10 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl return cell } + //-------------------------------------------------- + // MARK: - TableCollectionViewLayoutDataDelegate + //-------------------------------------------------- + func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel { return tableData[indexPath.section][indexPath.row] } diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift index 989e8eef..1366b0c7 100644 --- a/VDS/Components/Table/TableCellItem.swift +++ b/VDS/Components/Table/TableCellItem.swift @@ -11,17 +11,31 @@ import VDSTokens final class TableCellItem: UICollectionViewCell { + /// Identifier for TableCellItem static let Identifier: String = String(describing: TableCellItem.self) + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + + /// Main view which holds the content of the cell private let containerView = View() + /// Line seperator for cell private let separator: Line = Line() + /// Color configuration for default background color private let backgroundColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundPrimaryLight, VDSColor.backgroundPrimaryDark) + + /// Color configuration for striped background color private let stripedColorConfiguration = SurfaceColorConfiguration(VDSColor.backgroundSecondaryLight, VDSColor.backgroundSecondaryDark) + /// Padding parameter to maintain the edge spacing of the containerView private var padding: Table.Padding = .standard + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- override init(frame: CGRect) { super.init(frame: frame) setupCell() @@ -39,7 +53,12 @@ final class TableCellItem: UICollectionViewCell { containerView.pinToSuperView() } - func updateCell(content: TableItemModel, surface: Surface, striped: Bool = false, padding: Table.Padding = .standard) { + //-------------------------------------------------- + // MARK: - Public Methods + //-------------------------------------------------- + + /// Updates the cell content with ``TableItemModel`` and styling/padding attributes from other parameters + public func updateCell(content: TableItemModel, surface: Surface, striped: Bool = false, padding: Table.Padding = .standard) { containerView.subviews.forEach({ $0.removeFromSuperview() }) self.padding = padding diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift index 82e33500..5253c67f 100644 --- a/VDS/Components/Table/TableCellModel.swift +++ b/VDS/Components/Table/TableCellModel.swift @@ -9,16 +9,20 @@ import Foundation import UIKit import VDSTokens +/// Fetches the estimated height of component for said width public protocol ComponentHeight { func estimatedHeight(for width: CGFloat) -> CGFloat? } +/// Model that represent the content of each cell of Table component public struct TableItemModel { + /// Default cell height public var defaultHeight: CGFloat { return 50.0 } public var bottomLine: Line.Style? + /// Component to be show in the Table cell public var component: UIView & ComponentHeight public init(bottomLine: Line.Style? = nil, component: UIView & ComponentHeight) { @@ -27,6 +31,7 @@ public struct TableItemModel { } } +/// Confirming protocol ``ComponentHeight`` to determine the height, based on the width extension Label: ComponentHeight { public func estimatedHeight(for width: CGFloat) -> CGFloat? { diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift index a3d8e817..c66fa89e 100644 --- a/VDS/Components/Table/TableFlowLayout.swift +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -14,14 +14,33 @@ protocol TableCollectionViewLayoutDataDelegate: AnyObject { class MatrixFlowLayout : UICollectionViewLayout { + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + + ///Spacing between the pagination cells + private let defaultLeadingPadding: CGFloat = VDSLayout.space1X + + /// Parameter to store the layout attributes of cell, while calculate the size & position of the cell + private var itemCache: [UICollectionViewLayoutAttributes] = [] + + /// Parameter to store the total height of the collectionView + private var layoutHeight: CGFloat = 0.0 + + //-------------------------------------------------- + // MARK: - Internal Properties + //-------------------------------------------------- + weak var delegate: TableCollectionViewLayoutDataDelegate? + ///padding type to be set from Table component, which is used to calculate the size & position of the cell. var layoutPadding: Table.Padding = .standard - var itemCache: [UICollectionViewLayoutAttributes] = [] - - var layoutHeight: CGFloat = 0.0 + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + /// Calculates the layout attribute properties & total height of the collectionView override func prepare() { super.prepare() @@ -35,18 +54,22 @@ class MatrixFlowLayout : UICollectionViewLayout { var yPos: CGFloat = 0.0 + ///Looping through all the sections of the collectionView, visually these are rows for currentSection in 0.. $1.frame.size.height }).first?.frame.size.height ?? 0.0 + ///Set the highest height as height to all the cells in the row to make the row in uniform height. itemCache.filter({$0.indexPath.section == currentSection}).forEach { attributes in attributes.frame.size.height = highestHeightForSection } + ///Adds the height to y position for the next section yPos += highestHeightForSection } layoutHeight = yPos } - + /// Fetches estimated height by calling the cell's component estimated height and adding padding private func estimateHeightFor(item: TableItemModel, with width: CGFloat) -> CGFloat { - let itemWidth = width - layoutPadding.horizontalValue() - VDSLayout.space1X - let height = item.component.estimatedHeight(for: itemWidth) ?? 0 + let itemWidth = width - layoutPadding.horizontalValue() - defaultLeadingPadding + let height = item.component.estimatedHeight(for: itemWidth) ?? item.defaultHeight return height + (2 * layoutPadding.verticalValue()) } + ///This will return the layout attributes for the elements in the defined rect override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = [] for attributes in itemCache { @@ -89,15 +116,18 @@ class MatrixFlowLayout : UICollectionViewLayout { } return visibleLayoutAttributes } - + + ///This will return the layout attributes at particular indexPath override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { return itemCache.filter({ $0.indexPath == indexPath}).first } + ///Returns the collectionview content size override var collectionViewContentSize: CGSize { return CGSize(width: contentWidth, height: layoutHeight) } + /// Returns the width collectionView width private var contentWidth: CGFloat { guard let collectionView = collectionView else { return 0 } return collectionView.bounds.width From 7748a5eae408b231f31d7ba0fc034cdcb2ea5209 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Fri, 24 May 2024 20:49:58 +0530 Subject: [PATCH 08/24] Changes to accommodate any ui element into table cell and make its size dynamic. --- VDS/Components/Table/Table.swift | 21 ++++++++++++++- VDS/Components/Table/TableCellModel.swift | 30 +++------------------- VDS/Components/Table/TableFlowLayout.swift | 28 +++++++++++--------- 3 files changed, 39 insertions(+), 40 deletions(-) diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index 3c290a80..de03e8fc 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -24,7 +24,6 @@ open class Table: View { $0.delegate = self $0.translatesAutoresizingMaskIntoConstraints = false $0.allowsSelection = false - $0.isScrollEnabled = false $0.showsVerticalScrollIndicator = false $0.showsHorizontalScrollIndicator = false $0.isAccessibilityElement = true @@ -34,6 +33,7 @@ open class Table: View { /// Custom flow layout to manage the height of the cells private lazy var flowLayout = MatrixFlowLayout().with { $0.delegate = self + $0.scrollDirection = .horizontal } /// Array of ``TableItemModel`` by combining Header & Row items @@ -84,6 +84,9 @@ open class Table: View { /// Parameter to show the all table rows open var tableRows: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } + open var fillContainer: Bool = true { didSet { setNeedsUpdate() } } + + open var columnWidths: [CGFloat]? { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Overrides @@ -99,6 +102,9 @@ open class Table: View { /// Will update the table view, when called becasue of any changes in component parameters open override func updateView() { super.updateView() + if fillContainer == true || (fillContainer == false && columnWidths == nil) { + columnWidths = calculateColumnWidths() + } flowLayout.layoutPadding = padding matrixView.reloadData() matrixView.collectionViewLayout.invalidateLayout() @@ -111,8 +117,17 @@ open class Table: View { padding = .standard tableHeader = [] tableRows = [] + fillContainer = true + columnWidths = nil setNeedsUpdate() } + + func calculateColumnWidths() -> [CGFloat] { + guard let noOfColumns = tableData.first?.count else { return [] } + let itemWidth = floor(matrixView.safeAreaLayoutGuide.layoutFrame.width / CGFloat(noOfColumns)) + return Array(repeating: itemWidth, count: noOfColumns) + } + } extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableCollectionViewLayoutDataDelegate { @@ -143,4 +158,8 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel { return tableData[indexPath.section][indexPath.row] } + + func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat { + return columnWidths?[indexPath.row] ?? 0.0 + } } diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift index 5253c67f..01f03515 100644 --- a/VDS/Components/Table/TableCellModel.swift +++ b/VDS/Components/Table/TableCellModel.swift @@ -9,40 +9,16 @@ import Foundation import UIKit import VDSTokens -/// Fetches the estimated height of component for said width -public protocol ComponentHeight { - func estimatedHeight(for width: CGFloat) -> CGFloat? -} - /// Model that represent the content of each cell of Table component public struct TableItemModel { - - /// Default cell height - public var defaultHeight: CGFloat { return 50.0 } - + public var bottomLine: Line.Style? /// Component to be show in the Table cell - public var component: UIView & ComponentHeight + public var component: UIView - public init(bottomLine: Line.Style? = nil, component: UIView & ComponentHeight) { + public init(bottomLine: Line.Style? = nil, component: UIView) { self.bottomLine = bottomLine self.component = component } } - -/// Confirming protocol ``ComponentHeight`` to determine the height, based on the width -extension Label: ComponentHeight { - - public func estimatedHeight(for width: CGFloat) -> CGFloat? { - let maxbounds = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude) - return self.sizeThatFits(maxbounds).height - } -} - -extension Icon: ComponentHeight { - - public func estimatedHeight(for width: CGFloat) -> CGFloat? { - return intrinsicContentSize.height - } -} diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift index c66fa89e..0f3e231f 100644 --- a/VDS/Components/Table/TableFlowLayout.swift +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -10,9 +10,10 @@ import VDSTokens protocol TableCollectionViewLayoutDataDelegate: AnyObject { func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel + func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat } -class MatrixFlowLayout : UICollectionViewLayout { +class MatrixFlowLayout : UICollectionViewFlowLayout { //-------------------------------------------------- // MARK: - Private Properties @@ -27,6 +28,9 @@ class MatrixFlowLayout : UICollectionViewLayout { /// Parameter to store the total height of the collectionView private var layoutHeight: CGFloat = 0.0 + /// Parameter to store the total width of the collectionView + private var layoutWidth: CGFloat = 0.0 + //-------------------------------------------------- // MARK: - Internal Properties //-------------------------------------------------- @@ -57,6 +61,9 @@ class MatrixFlowLayout : UICollectionViewLayout { ///Looping through all the sections of the collectionView, visually these are rows for currentSection in 0.. $1.frame.size.height }).first?.frame.size.height ?? 0.0 + let highestHeightForSection = itemCache.filter({$0.indexPath.section == currentSection}).sorted(by: {$0.frame.size.height > $1.frame.size.height }).first?.frame.size.height ?? 0.0 ///Set the highest height as height to all the cells in the row to make the row in uniform height. itemCache.filter({$0.indexPath.section == currentSection}).forEach { attributes in @@ -102,8 +111,9 @@ class MatrixFlowLayout : UICollectionViewLayout { private func estimateHeightFor(item: TableItemModel, with width: CGFloat) -> CGFloat { let itemWidth = width - layoutPadding.horizontalValue() - defaultLeadingPadding - let height = item.component.estimatedHeight(for: itemWidth) ?? item.defaultHeight - return height + (2 * layoutPadding.verticalValue()) + let maxSize = CGSize(width: itemWidth, height: CGFloat.greatestFiniteMagnitude) + let estItemSize = item.component.systemLayoutSizeFitting(maxSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) + return estItemSize.height + (2 * layoutPadding.verticalValue()) } ///This will return the layout attributes for the elements in the defined rect @@ -124,12 +134,6 @@ class MatrixFlowLayout : UICollectionViewLayout { ///Returns the collectionview content size override var collectionViewContentSize: CGSize { - return CGSize(width: contentWidth, height: layoutHeight) - } - - /// Returns the width collectionView width - private var contentWidth: CGFloat { - guard let collectionView = collectionView else { return 0 } - return collectionView.bounds.width + return CGSize(width: layoutWidth, height: layoutHeight) } } From b88d76da419fa69ebcefe05cddc2d4babc016c73 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 27 May 2024 15:02:49 +0530 Subject: [PATCH 09/24] Table component refactoring, TableRowModel creation & table item will be able to take a empty view. --- VDS.xcodeproj/project.pbxproj | 12 ++++++--- VDS/Components/Table/Table.swift | 14 +++++------ VDS/Components/Table/TableCellItem.swift | 29 ++++++++++++---------- VDS/Components/Table/TableFlowLayout.swift | 2 +- VDS/Components/Table/TableItemModel.swift | 26 +++++++++++++++++++ VDS/Components/Table/TableRowModel.swift | 21 ++++++++++++++++ 6 files changed, 79 insertions(+), 25 deletions(-) create mode 100644 VDS/Components/Table/TableItemModel.swift create mode 100644 VDS/Components/Table/TableRowModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 9cc1431b..d0a6b550 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -25,8 +25,9 @@ 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; - 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableCellModel.swift */; }; + 44A952D92BE384C40009F874 /* TableItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableItemModel.swift */; }; 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */; }; + 44BD43B62C04866600644F87 /* TableRowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44BD43B52C04866600644F87 /* TableRowModel.swift */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 710607952B91A99500F2863F /* TitleletChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 710607942B91A99500F2863F /* TitleletChangeLog.txt */; }; @@ -218,8 +219,9 @@ 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; - 44A952D82BE384C40009F874 /* TableCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableCellModel.swift; sourceTree = ""; }; + 44A952D82BE384C40009F874 /* TableItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableItemModel.swift; sourceTree = ""; }; 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableFlowLayout.swift; sourceTree = ""; }; + 44BD43B52C04866600644F87 /* TableRowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableRowModel.swift; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = ""; }; @@ -441,7 +443,8 @@ 440B84C92BD8E0E9004A732A /* Table.swift */, 443DBAF92BDA303F0021497E /* TableCellItem.swift */, 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */, - 44A952D82BE384C40009F874 /* TableCellModel.swift */, + 44BD43B52C04866600644F87 /* TableRowModel.swift */, + 44A952D82BE384C40009F874 /* TableItemModel.swift */, ); path = Table; sourceTree = ""; @@ -1148,7 +1151,7 @@ EAACB89A2B927108006A3869 /* Valuing.swift in Sources */, EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, - 44A952D92BE384C40009F874 /* TableCellModel.swift in Sources */, + 44A952D92BE384C40009F874 /* TableItemModel.swift in Sources */, EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */, 71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */, EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, @@ -1178,6 +1181,7 @@ EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */, EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */, 443DBAFA2BDA303F0021497E /* TableCellItem.swift in Sources */, + 44BD43B62C04866600644F87 /* TableRowModel.swift in Sources */, 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */, EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, diff --git a/VDS/Components/Table/Table.swift b/VDS/Components/Table/Table.swift index de03e8fc..97452db9 100644 --- a/VDS/Components/Table/Table.swift +++ b/VDS/Components/Table/Table.swift @@ -37,7 +37,7 @@ open class Table: View { } /// Array of ``TableItemModel`` by combining Header & Row items - private var tableData: [[TableItemModel]] { + private var tableData: [TableRowModel] { return tableHeader + tableRows } @@ -79,10 +79,10 @@ open class Table: View { open var padding: Padding = .standard { didSet { setNeedsUpdate() } } /// Parameter to show the table header row - open var tableHeader: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } + open var tableHeader: [TableRowModel] = [] { didSet { setNeedsUpdate() } } /// Parameter to show the all table rows - open var tableRows: [[TableItemModel]] = [] { didSet { setNeedsUpdate() } } + open var tableRows: [TableRowModel] = [] { didSet { setNeedsUpdate() } } open var fillContainer: Bool = true { didSet { setNeedsUpdate() } } @@ -123,7 +123,7 @@ open class Table: View { } func calculateColumnWidths() -> [CGFloat] { - guard let noOfColumns = tableData.first?.count else { return [] } + guard let noOfColumns = tableData.first?.columnsCount else { return [] } let itemWidth = floor(matrixView.safeAreaLayoutGuide.layoutFrame.width / CGFloat(noOfColumns)) return Array(repeating: itemWidth, count: noOfColumns) } @@ -140,12 +140,12 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl return tableData.count } public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return tableData[section].count + return tableData[section].columnsCount } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TableCellItem.Identifier, for: indexPath) as? TableCellItem else { return UICollectionViewCell() } - let currentItem = tableData[indexPath.section][indexPath.row] + let currentItem = tableData[indexPath.section].columns[indexPath.row] let shouldStrip = striped ? (indexPath.section % 2 != 0) : false cell.updateCell(content: currentItem, surface: surface, striped: shouldStrip, padding: padding) return cell @@ -156,7 +156,7 @@ extension Table: UICollectionViewDelegate, UICollectionViewDataSource, TableColl //-------------------------------------------------- func collectionView(_ collectionView: UICollectionView, dataForItemAt indexPath: IndexPath) -> TableItemModel { - return tableData[indexPath.section][indexPath.row] + return tableData[indexPath.section].columns[indexPath.row] } func collectionView(_ collectionView: UICollectionView, widthForItemAt indexPath: IndexPath) -> CGFloat { diff --git a/VDS/Components/Table/TableCellItem.swift b/VDS/Components/Table/TableCellItem.swift index 1366b0c7..88b6c2d0 100644 --- a/VDS/Components/Table/TableCellItem.swift +++ b/VDS/Components/Table/TableCellItem.swift @@ -65,19 +65,6 @@ final class TableCellItem: UICollectionViewCell { containerView.surface = surface containerView.backgroundColor = striped ? stripedColorConfiguration.getColor(surface) : backgroundColorConfiguration.getColor(surface) - containerView.addSubview(content.component) - - if var surfacedView = content.component as? Surfaceable { - surfacedView.surface = surface - } - - NSLayoutConstraint.activate([ - content.component.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: VDSLayout.space1X), - content.component.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: padding.verticalValue()), - containerView.bottomAnchor.constraint(greaterThanOrEqualTo: content.component.bottomAnchor, constant: padding.verticalValue()), - containerView.trailingAnchor.constraint(greaterThanOrEqualTo: content.component.trailingAnchor, constant: padding.horizontalValue()), - containerView.centerYAnchor.constraint(equalTo: content.component.centerYAnchor) - ]) containerView.addSubview(separator) separator.pinLeading().pinTrailing().pinBottom() @@ -85,5 +72,21 @@ final class TableCellItem: UICollectionViewCell { separator.style = content.bottomLine ?? .primary separator.isHidden = content.bottomLine == nil separator.surface = surface + + guard let component = content.component else { return } + + containerView.addSubview(component) + + if var surfacedView = component as? Surfaceable { + surfacedView.surface = surface + } + + NSLayoutConstraint.activate([ + component.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: VDSLayout.space1X), + component.topAnchor.constraint(greaterThanOrEqualTo: containerView.topAnchor, constant: padding.verticalValue()), + containerView.bottomAnchor.constraint(greaterThanOrEqualTo: component.bottomAnchor, constant: padding.verticalValue()), + containerView.trailingAnchor.constraint(greaterThanOrEqualTo: component.trailingAnchor, constant: padding.horizontalValue()), + containerView.centerYAnchor.constraint(equalTo: component.centerYAnchor) + ]) } } diff --git a/VDS/Components/Table/TableFlowLayout.swift b/VDS/Components/Table/TableFlowLayout.swift index 0f3e231f..2e447187 100644 --- a/VDS/Components/Table/TableFlowLayout.swift +++ b/VDS/Components/Table/TableFlowLayout.swift @@ -112,7 +112,7 @@ class MatrixFlowLayout : UICollectionViewFlowLayout { let itemWidth = width - layoutPadding.horizontalValue() - defaultLeadingPadding let maxSize = CGSize(width: itemWidth, height: CGFloat.greatestFiniteMagnitude) - let estItemSize = item.component.systemLayoutSizeFitting(maxSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) + let estItemSize = item.component?.systemLayoutSizeFitting(maxSize, withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) ?? CGSize(width: itemWidth, height: item.defaultHeight) return estItemSize.height + (2 * layoutPadding.verticalValue()) } diff --git a/VDS/Components/Table/TableItemModel.swift b/VDS/Components/Table/TableItemModel.swift new file mode 100644 index 00000000..bd299d1b --- /dev/null +++ b/VDS/Components/Table/TableItemModel.swift @@ -0,0 +1,26 @@ +// +// TableItemModel.swift +// VDS +// +// Created by Nadigadda, Sumanth on 02/05/24. +// + +import Foundation +import UIKit +import VDSTokens + +/// Model that represent the content of each cell of Table component +public struct TableItemModel { + + public let defaultHeight: CGFloat = 50.0 + + public var bottomLine: Line.Style? + + /// Component to be show in the Table cell + public var component: UIView? + + public init(bottomLine: Line.Style? = nil, component: UIView? = nil) { + self.bottomLine = bottomLine + self.component = component + } +} diff --git a/VDS/Components/Table/TableRowModel.swift b/VDS/Components/Table/TableRowModel.swift new file mode 100644 index 00000000..a838438f --- /dev/null +++ b/VDS/Components/Table/TableRowModel.swift @@ -0,0 +1,21 @@ +// +// TableRowModel.swift +// VDS +// +// Created by Sumanth Nadigadda on 27/05/24. +// + +import Foundation + +public struct TableRowModel { + + public var columns: [TableItemModel] + + public var columnsCount: Int { + return columns.count + } + + public init(columns: [TableItemModel]) { + self.columns = columns + } +} From 35d3a7cdf79143e56eddba0eedb8d31e6a41a4b6 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 27 May 2024 15:03:29 +0530 Subject: [PATCH 10/24] Renaming file. --- VDS/Components/Table/TableCellModel.swift | 24 ----------------------- 1 file changed, 24 deletions(-) delete mode 100644 VDS/Components/Table/TableCellModel.swift diff --git a/VDS/Components/Table/TableCellModel.swift b/VDS/Components/Table/TableCellModel.swift deleted file mode 100644 index 01f03515..00000000 --- a/VDS/Components/Table/TableCellModel.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// TableCellModel.swift -// VDS -// -// Created by Nadigadda, Sumanth on 02/05/24. -// - -import Foundation -import UIKit -import VDSTokens - -/// Model that represent the content of each cell of Table component -public struct TableItemModel { - - public var bottomLine: Line.Style? - - /// Component to be show in the Table cell - public var component: UIView - - public init(bottomLine: Line.Style? = nil, component: UIView) { - self.bottomLine = bottomLine - self.component = component - } -} From d5b5285ec12b7322eccdc4fe94dcd7da697a6204 Mon Sep 17 00:00:00 2001 From: Sumanth Nadigadda Date: Mon, 27 May 2024 15:44:31 +0530 Subject: [PATCH 11/24] Adding Table change log file --- VDS.xcodeproj/project.pbxproj | 4 +++ VDS/Components/Table/TableChangeLog.txt | 33 +++++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 VDS/Components/Table/TableChangeLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 301c60d0..ffdb82c8 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -35,6 +35,7 @@ 44A952D92BE384C40009F874 /* TableItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952D82BE384C40009F874 /* TableItemModel.swift */; }; 44A952DD2BE3DA820009F874 /* TableFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */; }; 44BD43B62C04866600644F87 /* TableRowModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44BD43B52C04866600644F87 /* TableRowModel.swift */; }; + 44CCF4952C0493A1005C9C5E /* TableChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 44CCF4942C0493A1005C9C5E /* TableChangeLog.txt */; }; 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 710607952B91A99500F2863F /* TitleletChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 710607942B91A99500F2863F /* TitleletChangeLog.txt */; }; @@ -255,6 +256,7 @@ 44A952D82BE384C40009F874 /* TableItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableItemModel.swift; sourceTree = ""; }; 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableFlowLayout.swift; sourceTree = ""; }; 44BD43B52C04866600644F87 /* TableRowModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableRowModel.swift; sourceTree = ""; }; + 44CCF4942C0493A1005C9C5E /* TableChangeLog.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = TableChangeLog.txt; sourceTree = ""; }; 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 710607942B91A99500F2863F /* TitleletChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TitleletChangeLog.txt; sourceTree = ""; }; @@ -511,6 +513,7 @@ 44A952DC2BE3DA820009F874 /* TableFlowLayout.swift */, 44BD43B52C04866600644F87 /* TableRowModel.swift */, 44A952D82BE384C40009F874 /* TableItemModel.swift */, + 44CCF4942C0493A1005C9C5E /* TableChangeLog.txt */, ); path = Table; sourceTree = ""; @@ -1176,6 +1179,7 @@ EAEEECA42B1F934600531FC2 /* IconChangeLog.txt in Resources */, 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */, EA3362042891E14D0071C351 /* VerizonNHGeTX-Bold.otf in Resources */, + 44CCF4952C0493A1005C9C5E /* TableChangeLog.txt in Resources */, 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */, EAEEECA72B1F952000531FC2 /* TabsChangeLog.txt in Resources */, 186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */, diff --git a/VDS/Components/Table/TableChangeLog.txt b/VDS/Components/Table/TableChangeLog.txt new file mode 100644 index 00000000..36f168af --- /dev/null +++ b/VDS/Components/Table/TableChangeLog.txt @@ -0,0 +1,33 @@ +03/31/2022 +---------------- +- Initial Brand 3.0 handoff + +08/02/2022 +---------------- +- Included a VDS Note about the Padding prop name rationale + +08/10/2022 +---------------- +- Updated default and inverted prop to light and dark surface. + +08/29/2022 +---------------- +- Noted that Striped style is set to false as default. Clarified Anatomy description of line elements to say that both are configurable at both group and item level via bottomLine prop. + +09/02/2022 +---------------- +- Added dev note enhancment to fix vertical 1px height jumping + +09/13/2022 +---------------- +- Updated Anatomy element names per decisions made for design/dev docs. + +10/04/2022 +---------------- +- Added dev note to Viewport > Striped > Compact padding to specify that auto-indent also applies to striped tables with default padding. + +12/16/2022 +---------------- +- Updated border color values to use element tokens. +- Removed Line section from first position of Configurations. +- Replaced spacing values with tokens. From 40a31dfe259d5a282f143cc8ec9158f76391de68 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 5 Jun 2024 15:18:32 -0500 Subject: [PATCH 12/24] =?UTF-8?q?CXTDT-560823=20=E2=80=93=20TextArea=20?= =?UTF-8?q?=E2=80=93=20Accessibility=20Labels/Error/ReadyOnly/Disabled.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Matt Bruce --- VDS/Components/DatePicker/DatePicker.swift | 7 +------ .../DropdownSelect/DropdownSelect.swift | 7 +------ VDS/Components/TextFields/EntryFieldBase.swift | 17 +++++++++++++++++ .../TextFields/InputField/InputField.swift | 9 ++------- .../TextFields/TextArea/TextArea.swift | 7 +------ VDS/SupportingFiles/ReleaseNotes.txt | 1 + 6 files changed, 23 insertions(+), 25 deletions(-) diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index 7a158ff6..7645cce5 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -147,12 +147,7 @@ open class DatePicker: EntryFieldBase, DatePickerViewControllerDelegate, UIPopov open override func updateAccessibility() { super.updateAccessibility() - let label = "Date Picker, \(isReadOnly ? ", read only" : "")" - if let errorText, showError { - fieldStackView.accessibilityLabel = "\(label) ,error, \(errorText)" - } else { - fieldStackView.accessibilityLabel = label - } + fieldStackView.accessibilityLabel = "Date Picker, \(accessibilityLabelText)" fieldStackView.accessibilityHint = isReadOnly || !isEnabled ? "" : "Double tap to open." fieldStackView.accessibilityValue = value } diff --git a/VDS/Components/DropdownSelect/DropdownSelect.swift b/VDS/Components/DropdownSelect/DropdownSelect.swift index bad62536..e001d130 100644 --- a/VDS/Components/DropdownSelect/DropdownSelect.swift +++ b/VDS/Components/DropdownSelect/DropdownSelect.swift @@ -278,12 +278,7 @@ open class DropdownSelect: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() - let label = "Dropdown Select, \(isReadOnly ? ", read only" : "")" - if let errorText, showError { - fieldStackView.accessibilityLabel = "\(label) ,error, \(errorText)" - } else { - fieldStackView.accessibilityLabel = label - } + fieldStackView.accessibilityLabel = "Dropdown Select, \(accessibilityLabelText)" fieldStackView.accessibilityHint = isReadOnly || !isEnabled ? "" : "Double tap to open." fieldStackView.accessibilityValue = value } diff --git a/VDS/Components/TextFields/EntryFieldBase.swift b/VDS/Components/TextFields/EntryFieldBase.swift index ea023736..f56f78a2 100644 --- a/VDS/Components/TextFields/EntryFieldBase.swift +++ b/VDS/Components/TextFields/EntryFieldBase.swift @@ -241,6 +241,23 @@ open class EntryFieldBase: Control, Changeable, FormFieldInternalValidatable { open var rules = [AnyRule]() + open var accessibilityLabelText: String { + var accessibilityLabels = [String]() + if let text = titleLabel.text { + accessibilityLabels.append(text) + } + if isReadOnly { + accessibilityLabels.append("read only") + } + if !isEnabled { + accessibilityLabels.append("dimmed") + } + if let errorText, showError { + accessibilityLabels.append("error, \(errorText)") + } + return accessibilityLabels.joined(separator: ", ") + } + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index 516954cd..af358dbf 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -225,15 +225,10 @@ open class InputField: EntryFieldBase { textField.isUserInteractionEnabled = isEnabled && !isReadOnly textField.textColor = textFieldTextColorConfiguration.getColor(self) } - + open override func updateAccessibility() { super.updateAccessibility() - let label = "\(isReadOnly ? "read only" : "")" - if let errorText, showError { - textField.accessibilityLabel = "\(label) ,error, \(errorText)" - } else { - textField.accessibilityLabel = label - } + textField.accessibilityLabel = accessibilityLabelText textField.accessibilityHint = isReadOnly || !isEnabled ? "" : "Double tap to open." } diff --git a/VDS/Components/TextFields/TextArea/TextArea.swift b/VDS/Components/TextFields/TextArea/TextArea.swift index 870cf6b6..b0d858df 100644 --- a/VDS/Components/TextFields/TextArea/TextArea.swift +++ b/VDS/Components/TextFields/TextArea/TextArea.swift @@ -195,12 +195,7 @@ open class TextArea: EntryFieldBase { open override func updateAccessibility() { super.updateAccessibility() - let label = "\(isReadOnly ? "read only" : "")" - if let errorText, showError { - textView.accessibilityLabel = "\(label) ,error, \(errorText)" - } else { - textView.accessibilityLabel = label - } + textView.accessibilityLabel = accessibilityLabelText textView.accessibilityHint = isReadOnly || !isEnabled ? "" : "Double tap to open." } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index e39df158..3c1fee48 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -3,6 +3,7 @@ - CXTDT-565087 - Input Field - Text - OnDark colors - CXTDT-565112 - Input Field - Credit Card icons - CXTDT-565117 - Input Field - Overflow not clipped +- CXTDT-560823 – TextArea – Accessibility Labels/Error/ReadyOnly/Disabled 1.0.65 ---------------- From a71085f2b3401579d0802e035584dff2d3f1994f Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 5 Jun 2024 16:16:13 -0500 Subject: [PATCH 13/24] added release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 3c1fee48..2018da35 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -4,6 +4,8 @@ - CXTDT-565112 - Input Field - Credit Card icons - CXTDT-565117 - Input Field - Overflow not clipped - CXTDT-560823 – TextArea – Accessibility Labels/Error/ReadyOnly/Disabled +- CXTDT-553663 - DropdownSelect – Accessibility +- CXTDT-544662 - Breadcrumbs - Text Wrapping 1.0.65 ---------------- From f5380532ff26af9a0c0b24960be986fb243334db Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Wed, 5 Jun 2024 17:32:45 -0500 Subject: [PATCH 14/24] fixed bug for Accessibility Elements in Label Signed-off-by: Matt Bruce --- VDS/Components/Label/Label.swift | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Label/Label.swift b/VDS/Components/Label/Label.swift index 9e4dd18e..7d14a85f 100644 --- a/VDS/Components/Label/Label.swift +++ b/VDS/Components/Label/Label.swift @@ -314,8 +314,11 @@ open class Label: UILabel, ViewProtocol, UserInfoable { super.text = newValue return } - + + //clear out accessibility + accessibilityElements?.removeAll() accessibilityCustomActions = [] + //create the primary string let mutableText = NSMutableAttributedString.mutableText(for: newValue, textStyle: textStyle, @@ -337,6 +340,10 @@ open class Label: UILabel, ViewProtocol, UserInfoable { return } + //clear out accessibility + accessibilityElements?.removeAll() + accessibilityCustomActions = [] + let mutableText = NSMutableAttributedString(attributedString: newValue) applyAttributes(mutableText) @@ -348,7 +355,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { private func applyAttributes(_ mutableAttributedString: NSMutableAttributedString) { actions = [] - if let attributes = attributes { + if let attributes { mutableAttributedString.apply(attributes: attributes) } } @@ -359,7 +366,7 @@ open class Label: UILabel, ViewProtocol, UserInfoable { let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText) - if let attributes = attributes { + if let attributes { //loop through the models attributes for attribute in attributes { From 2e46759857e9b93e8f7ec680bd94295675fa70fd Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 6 Jun 2024 12:22:21 -0500 Subject: [PATCH 15/24] fixed credit card issues with formatting for different card types also added an min/max length based on card type. Signed-off-by: Matt Bruce --- .../InputField/FieldTypes/CreditCard.swift | 56 ++++++++++++++----- 1 file changed, 43 insertions(+), 13 deletions(-) diff --git a/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift b/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift index bd512b50..fef4c77a 100644 --- a/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift +++ b/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift @@ -9,7 +9,20 @@ import Foundation import UIKit extension InputField { - + class CreditCardNumberRule: Rule, Withable { + var cardType: CreditCardType? + var errorMessage: String = "You have exceeded the character limit." + + func isValid(value: String?) -> Bool { + guard let count = value?.count, let min = cardType?.minLength, let max = cardType?.maxLength else { return true } + if min == max { + return count == max + } else { + return count >= min && count <= max + } + } + } + public enum CreditCardType: String, CaseIterable { case generic case visa @@ -38,15 +51,22 @@ extension InputField { } } - var separatorIndices: [Int] { + func separatorIndices(_ length: Int) -> [Int] { + var indices: [Int] = [4, 8, 12] switch self { - case .dinersClub: - return [4, 10] + case .amex, .dinersClub: + indices = [4, 10] + case .unionPay: + if length == 19 { + indices = [5] + } default: - return [4, 8, 12] + break } + + return indices } - + var securityCodeLength: Int { if self == .amex { return 4 @@ -55,9 +75,21 @@ extension InputField { } } + var minLength: Int { + switch self { + case .visa: return 13 + case .amex: return 15 + case .dinersClub: return 14 + default: return 16 + } + } + var maxLength: Int { switch self { + case .visa: return 19 + case .amex: return 15 case .dinersClub: return 14 + case .unionPay: return 19 default: return 16 } } @@ -131,9 +163,8 @@ extension InputField { override func appendRules(_ inputField: InputField) { if let text = inputField.textField.text, text.count > 0 { - let rule = CharacterCountRule().copyWith { - $0.maxLength = inputField.cardType.maxLength - $0.compareType = .equals + let rule = CreditCardNumberRule().copyWith { + $0.cardType = inputField.cardType $0.errorMessage = "Enter a valid credit card." } inputField.rules.append(.init(rule)) @@ -205,8 +236,8 @@ extension InputField { /// Private internal func formatCreditCardNumber(_ cardType: CreditCardType, number: String) -> String { - let formattedInput = number.filter { $0.isNumber } // Remove any existing slashes - return String.format(formattedInput, indices: cardType.separatorIndices, with: " ") + let rawNumber = number.filter { $0.isNumber } // Remove any existing slashes + return String.format(rawNumber, indices: cardType.separatorIndices(rawNumber.count), with: " ") } internal func updateCardTypeIcon(_ inputField: InputField, rawNumber: String) { @@ -224,9 +255,8 @@ extension InputField { guard rawNumber.count == cardType.maxLength else { return formatCreditCardNumber(cardType, number: number) } let lastFourDigits = rawNumber.suffix(4) let maskedSection = String(repeating: "•", count: 12) - let formattedMaskSection = String.format(maskedSection, indices: cardType.separatorIndices, with: " ") + let formattedMaskSection = String.format(maskedSection, indices: cardType.separatorIndices(rawNumber.count), with: " ") return formattedMaskSection + " " + lastFourDigits } } - } From ba0989bb2ba4574d61e19c2b4de45f845229f25c Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 6 Jun 2024 15:54:56 -0500 Subject: [PATCH 16/24] updated credit card rule Signed-off-by: Matt Bruce --- .../TextFields/InputField/FieldTypes/CreditCard.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift b/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift index fef4c77a..bc3a289a 100644 --- a/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift +++ b/VDS/Components/TextFields/InputField/FieldTypes/CreditCard.swift @@ -9,11 +9,11 @@ import Foundation import UIKit extension InputField { - class CreditCardNumberRule: Rule, Withable { - var cardType: CreditCardType? - var errorMessage: String = "You have exceeded the character limit." + public class CreditCardNumberRule: Rule, Withable { + public var cardType: CreditCardType? + public var errorMessage: String = "You have exceeded the character limit." - func isValid(value: String?) -> Bool { + public func isValid(value: String?) -> Bool { guard let count = value?.count, let min = cardType?.minLength, let max = cardType?.maxLength else { return true } if min == max { return count == max From 8a686314f515312c1c661198be5dcc42f3aa729e Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 6 Jun 2024 16:18:03 -0500 Subject: [PATCH 17/24] added a format label Signed-off-by: Matt Bruce --- .../TextFields/InputField/TextField.swift | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/VDS/Components/TextFields/InputField/TextField.swift b/VDS/Components/TextFields/InputField/TextField.swift index b054741d..a2980b3b 100644 --- a/VDS/Components/TextFields/InputField/TextField.swift +++ b/VDS/Components/TextFields/InputField/TextField.swift @@ -47,6 +47,17 @@ open class TextField: UITextField, ViewProtocol, Errorable { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- + private var formatLabel = Label().with { + $0.tag = 999 + $0.textColorConfiguration = ViewColorConfiguration().with { + $0.setSurfaceColors(VDSColor.interactiveDisabledOnlight, VDSColor.interactiveDisabledOndark, forDisabled: true) + $0.setSurfaceColors(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark, forDisabled: false) + }.eraseToAnyColorable() + } + + /// Format String similar to placeholder + open var formatText: String? + /// TextStyle used on the titleLabel. open var textStyle: TextStyle = .defaultStyle { didSet { setNeedsUpdate() } } @@ -114,6 +125,37 @@ open class TextField: UITextField, ViewProtocol, Errorable { open func updateView() { updateLabel() + updateFormat() + } + + open func updateFormat() { + guard let formatText else { + formatLabel.text = "" + return + } + + if viewWithTag(999) == nil { + addSubview(formatLabel) + formatLabel.pinToSuperView() + } + + var attributes: [any LabelAttributeModel]? + var finalFormatText = formatText + + if let text, !text.isEmpty { + //make the color of the matching text clear + attributes = [ColorLabelAttribute(location: 0, length: text.count, color: .clear)] + + let startIndex = formatText.index(formatText.startIndex, offsetBy: text.count) + if startIndex < formatText.endIndex { + finalFormatText = text + formatText[startIndex...] + } + } + + //set the label + formatLabel.surface = surface + formatLabel.text = finalFormatText + formatLabel.attributes = attributes } open func updateAccessibility() { From f7ded238578468d1b0ea87ae28a5da43bd2fb276 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 6 Jun 2024 16:18:32 -0500 Subject: [PATCH 18/24] CXTDT-565105 - InputField - Date - Typeover text not working. Signed-off-by: Matt Bruce --- .../InputField/FieldTypes/Date.swift | 125 +++++++++++++++++- .../TextFields/InputField/InputField.swift | 11 +- 2 files changed, 125 insertions(+), 11 deletions(-) diff --git a/VDS/Components/TextFields/InputField/FieldTypes/Date.swift b/VDS/Components/TextFields/InputField/FieldTypes/Date.swift index 19656745..17decc96 100644 --- a/VDS/Components/TextFields/InputField/FieldTypes/Date.swift +++ b/VDS/Components/TextFields/InputField/FieldTypes/Date.swift @@ -10,6 +10,18 @@ import UIKit extension InputField { + public class DateRule: Rule, Withable { + public var dateFormat: DateFormat? + public var errorMessage: String = "Enter a valid date" + private let dateFormatter = DateFormatter() + + public func isValid(value: String?) -> Bool { + guard let value, let dateFormat, !value.isEmpty else { return true } + dateFormatter.dateFormat = dateFormat.formatString + return dateFormatter.date(from: value) != nil + } + } + public enum DateFormat: String, CaseIterable { case mmyy case mmddyy @@ -46,6 +58,102 @@ extension InputField { case .mmddyyyy: [2,4] } } + + public func isValid(_ date: String) -> Bool { + let allowedCharacters = CharacterSet(charactersIn: "0123456789/") + + // Check if the input contains only allowed characters + if date.rangeOfCharacter(from: allowedCharacters.inverted) != nil || date.isEmpty { + return false + } + + let components = date.split(separator: "/") + + + func isMonth(_ month: String) -> Bool { + switch month.count { + case 1: + guard let month = Int(month), (0...1).contains(month) else { return false } + return true + case 2: + guard let month = Int(month), (1...12).contains(month) else { return false } + return true + default: + return false + } + } + + func isDay(_ day: String) -> Bool { + switch day.count { + case 1: + guard let day = Int(day),(1...3).contains(day) else { return false } + return true + case 2: + guard let day = Int(day), (1...31).contains(day) else { return false } + return true + default: + return false + } + } + + func isYear(_ year: String, max: Int) -> Bool { + guard year.count <= max else { + return false + } + return true + } + + switch self { + case .mmyy: + if components.count > 2 { + return false + } + + // Validate month part + if components.count > 0, let monthPart = components.first { + if !isMonth(String(monthPart)) { + return false + } + } + + // Validate year part + if components.count > 1, let yearPart = components.last { + if !isYear(String(yearPart), max: 2) { + return false + } + } + + case .mmddyy, .mmddyyyy: + if components.count > 3 { + return false + } + + // Validate month part + if components.count > 0, let monthPart = components.first { + if !isMonth(String(monthPart)) { + return false + } + } + + // Validate day part + if components.count > 1 { + let dayPart = components[1] + if !isDay(String(dayPart)) { + return false + } + } + + // Validate year part + if components.count > 2, let yearPart = components.last { + if !isYear(String(yearPart), max: self == .mmddyy ? 2 : 4) { + return false + } + } + } + + return true + } + } class DateHandler: FieldTypeHandler { @@ -58,16 +166,15 @@ extension InputField { override func updateView(_ inputField: InputField) { minWidth = 114.0 - placeholderText = inputField.dateFormat.placeholderText - + //placeholderText = inputField.dateFormat.placeholderText + inputField.textField.formatText = inputField.dateFormat.placeholderText super.updateView(inputField) } override func appendRules(_ inputField: InputField) { if let text = inputField.textField.text, text.count > 0 { - let rule = CharacterCountRule().copyWith { - $0.maxLength = inputField.dateFormat.maxLength - $0.compareType = .equals + let rule = DateRule().copyWith { + $0.dateFormat = inputField.dateFormat $0.errorMessage = "Enter a valid date." } inputField.rules.append(.init(rule)) @@ -86,9 +193,13 @@ extension InputField { if newText.count > inputField.dateFormat.maxLength { return false } - + if newText.count <= inputField.dateFormat.maxLength { - textField.text = String.format(newText, indices: inputField.dateFormat.separatorIndices, with: "/") + let rawNumber = newText.filter { $0.isNumber } + let formatted = String.format(rawNumber, indices: inputField.dateFormat.separatorIndices, with: "/") + if inputField.dateFormat.isValid(formatted) || formatted.isEmpty { + textField.text = formatted + } return false } else { return true diff --git a/VDS/Components/TextFields/InputField/InputField.swift b/VDS/Components/TextFields/InputField/InputField.swift index af358dbf..a160420a 100644 --- a/VDS/Components/TextFields/InputField/InputField.swift +++ b/VDS/Components/TextFields/InputField/InputField.swift @@ -190,9 +190,11 @@ open class InputField: EntryFieldBase { successLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: .success) - - borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) + backgroundColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forState: [.success, .focused]) + borderColorConfiguration.setSurfaceColors(VDSColor.feedbackSuccessOnlight, VDSColor.feedbackSuccessOndark, forState: .success) + + textField.textColorConfiguration = textFieldTextColorConfiguration } open override func getFieldContainer() -> UIView { @@ -221,9 +223,9 @@ open class InputField: EntryFieldBase { super.updateView() + textField.surface = surface textField.isEnabled = isEnabled textField.isUserInteractionEnabled = isEnabled && !isReadOnly - textField.textColor = textFieldTextColorConfiguration.getColor(self) } open override func updateAccessibility() { @@ -248,7 +250,7 @@ open class InputField: EntryFieldBase { statusIcon.name = .checkmarkAlt statusIcon.color = iconColorConfiguration.getColor(self) statusIcon.surface = surface - statusIcon.isHidden = !isEnabled + statusIcon.isHidden = !isEnabled || state.contains(.focused) } else { successLabel.isHidden = true } @@ -303,6 +305,7 @@ extension InputField: UITextFieldDelegate { public func textFieldDidBeginEditing(_ textField: UITextField) { fieldType.handler().textFieldDidBeginEditing(self, textField: textField) updateContainerView() + updateErrorLabel() } public func textFieldDidEndEditing(_ textField: UITextField) { From a90cd23f11d96f8e09750b151c51a98ae9187849 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 6 Jun 2024 16:19:55 -0500 Subject: [PATCH 19/24] updated release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 2018da35..de8c62de 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -6,6 +6,8 @@ - CXTDT-560823 – TextArea – Accessibility Labels/Error/ReadyOnly/Disabled - CXTDT-553663 - DropdownSelect – Accessibility - CXTDT-544662 - Breadcrumbs - Text Wrapping +- CXTDT-565105 - InputField - Date - Typeover text not working +- CXTDT-565115 - InputField - CreditCard - China UnionPay does not allow longer numbers 1.0.65 ---------------- From 2bb1a24d7203a58986868fc9bf4227e24b7373a4 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 7 Jun 2024 14:34:46 +0530 Subject: [PATCH 20/24] Digital ACT-191 CXTDT-568409 defect: Width control missing - CXTDT-568398 - Calendar - Saturday missing - CXTDT-568402 - Calendar - Extra row --- VDS/Components/Calendar/Calendar.swift | 42 ++++++++++++++++++-------- VDS/SupportingFiles/ReleaseNotes.txt | 3 ++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index b023cf90..3736a52e 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -67,15 +67,20 @@ open class CalendarBase: Control, Changeable { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var containerSize: CGSize { CGSize(width: 328, height: 336) } + internal var containerSize: CGSize { CGSize(width: widthDefault, height: 336) } internal var calendar = Calendar.current private let cellItemSize = CGSize(width: 40, height: 40) private let headerHeight = 88.0 private let footerHeight = 40.0 private let calendarWidth = 304.0 + private let screenThreeSixty = 360.0 + private let widthDefault = 328.0 + private let widthTight = 320.0 - private var heightConstraint: NSLayoutConstraint? + private var collectionViewLeadingConstraint: NSLayoutConstraint? + private var collectionViewHeightConstraint: NSLayoutConstraint? + private var containerWidthConstraint: NSLayoutConstraint? private var containerHeightConstraint: NSLayoutConstraint? private var selectedIndexPath : IndexPath? private var dates: [Date] = [] @@ -133,21 +138,16 @@ open class CalendarBase: Control, Changeable { .pinTop() .pinBottom() .pinLeadingGreaterThanOrEqualTo() - .pinTrailingLessThanOrEqualTo() - .width(containerSize.width) .heightGreaterThanEqualTo(containerSize.height) containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() // Calendar View containerView.addSubview(collectionView) let calendarHeight = containerSize.height - (2 * VDSLayout.space4X) - let spacing = (containerSize.width - calendarWidth) / 2 collectionView .pinTop(VDSLayout.space4X) .pinBottom(VDSLayout.space4X) - .pinLeading(spacing) - .pinTrailing(spacing) .width(calendarWidth) .heightGreaterThanEqualTo(calendarHeight) @@ -191,8 +191,6 @@ open class CalendarBase: Control, Changeable { // MARK: - Private Methods //-------------------------------------------------- func fetchDates(with aDate: Date) { - heightConstraint?.isActive = false - containerHeightConstraint?.isActive = false days.removeAll() dates = aDate.calendarDisplayDays @@ -204,17 +202,35 @@ open class CalendarBase: Control, Changeable { days.append(date.getDay()) } } - + updateViewConstraints() + } + + func updateViewConstraints() { collectionView.reloadData() + // container width && collection view leading + collectionViewLeadingConstraint?.isActive = false + containerWidthConstraint?.isActive = false + var width = containerView.frame.size.width + width = ((width > 0) && (width < screenThreeSixty)) ? ((width > widthTight) && (width < screenThreeSixty)) ? widthTight : containerView.frame.size.width : widthDefault + let spacing = (width - calendarWidth) / 2 + collectionViewLeadingConstraint = collectionView.leadingAnchor.constraint(equalTo: containerView.leadingAnchor, constant: spacing) + containerWidthConstraint = containerView.widthAnchor.constraint(equalToConstant: calendarWidth + ( 2 * spacing)) + collectionViewLeadingConstraint?.isActive = true + containerWidthConstraint?.isActive = true + + + // container height && collection view height + collectionViewHeightConstraint?.isActive = false + containerHeightConstraint?.isActive = false var height = collectionView.collectionViewLayout.collectionViewContentSize.height height = height > 0 ? height : containerSize.height - heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: height) containerHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: height + (2 * VDSLayout.space4X)) - heightConstraint?.isActive = true + collectionViewHeightConstraint = collectionView.heightAnchor.constraint(equalToConstant: height) containerHeightConstraint?.isActive = true + collectionViewHeightConstraint?.isActive = true layoutIfNeeded() - } + } } extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index de8c62de..f45204f1 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -8,6 +8,9 @@ - CXTDT-544662 - Breadcrumbs - Text Wrapping - CXTDT-565105 - InputField - Date - Typeover text not working - CXTDT-565115 - InputField - CreditCard - China UnionPay does not allow longer numbers +- CXTDT-568398 - Calendar - Saturday missing (on smaller screen size devices) +- CXTDT-568402 - Calendar - Extra row (on smaller screen size devices) +- CXTDT-568409 - Calendar - Width control missing 1.0.65 ---------------- From c02ed371210ff9a819ac7f0c6301249c1dc32361 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 7 Jun 2024 17:35:28 +0530 Subject: [PATCH 21/24] Digital ACT-191 CXTDT-568419 defect: Calendar - When hideContainerBorder=true, corner radius disappears --- VDS/Components/Calendar/Calendar.swift | 3 +-- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index 3736a52e..b085de4c 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -165,14 +165,13 @@ open class CalendarBase: Control, Changeable { } containerView.layer.backgroundColor = backgroundColorConfiguration.getColor(self).cgColor + containerView.layer.cornerRadius = VDSFormControls.borderRadius if hideContainerBorder { containerView.layer.borderColor = nil containerView.layer.borderWidth = 0 - containerView.layer.cornerRadius = 0 } else { containerView.layer.borderColor = containerBorderColorConfiguration.getColor(self).cgColor containerView.layer.borderWidth = VDSFormControls.borderWidth - containerView.layer.cornerRadius = VDSFormControls.borderRadius } } diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index f45204f1..7ec07834 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -11,6 +11,7 @@ - CXTDT-568398 - Calendar - Saturday missing (on smaller screen size devices) - CXTDT-568402 - Calendar - Extra row (on smaller screen size devices) - CXTDT-568409 - Calendar - Width control missing +- CXTDT-568419 - Calendar - When hideContainerBorder=true, corner radius disappears 1.0.65 ---------------- From a3fe0b72788610a2822990c2a642ce5071865262 Mon Sep 17 00:00:00 2001 From: vasavk Date: Fri, 7 Jun 2024 17:59:29 +0530 Subject: [PATCH 22/24] Digital ACT-191 CXTDT-568413 defect: Calendar - Missing option for Transparent Background --- VDS/Components/Calendar/Calendar.swift | 5 ++--- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index b085de4c..04446252 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -120,7 +120,7 @@ open class CalendarBase: Control, Changeable { //-------------------------------------------------- internal var containerBorderColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight , VDSColor.elementsPrimaryOndark) internal var backgroundColorConfiguration = SurfaceColorConfiguration(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark) - + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -163,8 +163,7 @@ open class CalendarBase: Control, Changeable { displayDate = fallsBetween ? displayDate : minDate fetchDates(with: displayDate) } - - containerView.layer.backgroundColor = backgroundColorConfiguration.getColor(self).cgColor + containerView.backgroundColor = transparentBackground ? .clear : backgroundColorConfiguration.getColor(self) containerView.layer.cornerRadius = VDSFormControls.borderRadius if hideContainerBorder { containerView.layer.borderColor = nil diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index 7ec07834..1096dd39 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -12,6 +12,7 @@ - CXTDT-568402 - Calendar - Extra row (on smaller screen size devices) - CXTDT-568409 - Calendar - Width control missing - CXTDT-568419 - Calendar - When hideContainerBorder=true, corner radius disappears +- CXTDT-568413 - Calendar - Missing option for Transparent Background 1.0.65 ---------------- From f11b21a04bf8904f588e6231f248c49d71841750 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 7 Jun 2024 08:05:59 -0500 Subject: [PATCH 23/24] updated release notes Signed-off-by: Matt Bruce --- VDS/SupportingFiles/ReleaseNotes.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index de8c62de..5ccbc332 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,13 +1,13 @@ 1.0.66 ---------------- -- CXTDT-565087 - Input Field - Text - OnDark colors -- CXTDT-565112 - Input Field - Credit Card icons -- CXTDT-565117 - Input Field - Overflow not clipped +- CXTDT-565087 - InputField - Text - OnDark colors +- CXTDT-565112 - InputField - Credit Card icons +- CXTDT-565117 - InputField - Overflow not clipped +- CXTDT-565105 - InputField - Date - Typeover text not working +- CXTDT-565115 - InputField - CreditCard - China UnionPay does not allow longer numbers - CXTDT-560823 – TextArea – Accessibility Labels/Error/ReadyOnly/Disabled - CXTDT-553663 - DropdownSelect – Accessibility - CXTDT-544662 - Breadcrumbs - Text Wrapping -- CXTDT-565105 - InputField - Date - Typeover text not working -- CXTDT-565115 - InputField - CreditCard - China UnionPay does not allow longer numbers 1.0.65 ---------------- From fd4694db8dfd3e1edaaaf32dd0d252dbe1947ae8 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Fri, 7 Jun 2024 13:05:33 -0500 Subject: [PATCH 24/24] updated version Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 4 ++-- VDS/SupportingFiles/ReleaseNotes.txt | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 0962fe0a..02e8d284 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -1521,7 +1521,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; @@ -1559,7 +1559,7 @@ BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CODE_SIGN_IDENTITY = ""; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 65; + CURRENT_PROJECT_VERSION = 66; DEFINES_MODULE = YES; DEVELOPMENT_TEAM = ""; DYLIB_COMPATIBILITY_VERSION = 1; diff --git a/VDS/SupportingFiles/ReleaseNotes.txt b/VDS/SupportingFiles/ReleaseNotes.txt index f0e8e244..615f10df 100644 --- a/VDS/SupportingFiles/ReleaseNotes.txt +++ b/VDS/SupportingFiles/ReleaseNotes.txt @@ -1,5 +1,6 @@ 1.0.66 ---------------- +- ONEAPP-6325 - Table - Development finished - CXTDT-565087 - InputField - Text - OnDark colors - CXTDT-565112 - InputField - Credit Card icons - CXTDT-565117 - InputField - Overflow not clipped