From 40883825b5b72eba5c7ed0c30db2982e850512de Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Sat, 2 Mar 2024 18:26:00 +0530 Subject: [PATCH 01/31] added new Pagination component --- VDS.xcodeproj/project.pbxproj | 12 + VDS/Components/Pagination/Pagination.swift | 228 ++++++++++++++++++ .../Contents.json | 12 + .../pagination-arrow-left.svg | 10 + .../Contents.json | 12 + .../pagination-arrow-right.svg | 3 + 6 files changed, 277 insertions(+) create mode 100644 VDS/Components/Pagination/Pagination.swift create mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json create mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg create mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json create mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 366fca71..79deb46b 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; + 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */; }; 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; }; @@ -184,6 +185,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; + 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dropshadowable.swift; sourceTree = ""; }; 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = ""; }; @@ -384,6 +386,14 @@ path = Button; sourceTree = ""; }; + 71B23C2B2B91FA510027F7D9 /* Pagination */ = { + isa = PBXGroup; + children = ( + 71B23C2C2B91FA690027F7D9 /* Pagination.swift */, + ); + path = Pagination; + sourceTree = ""; + }; EA0B17FF2A9E21CA00F2D0CD /* Selector */ = { isa = PBXGroup; children = ( @@ -487,6 +497,7 @@ EA33619D288B1E330071C351 /* Components */ = { isa = PBXGroup; children = ( + 71B23C2B2B91FA510027F7D9 /* Pagination */, EA4DB2FE28DCBC1900103EE3 /* Badge */, EAD062AE2A3B87210015965D /* BadgeIndicator */, EA0FC2BE2912D18200DF80B4 /* Buttons */, @@ -1051,6 +1062,7 @@ EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */, 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */, EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */, + 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */, EA0D1C372A681CCE00E5C127 /* ToggleView.swift in Sources */, EAF7F0B9289C139800B287F5 /* ColorConfiguration.swift in Sources */, EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift new file mode 100644 index 00000000..4df0a034 --- /dev/null +++ b/VDS/Components/Pagination/Pagination.swift @@ -0,0 +1,228 @@ +// +// Pagination.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 01/03/24. +// + +import Foundation +import VDSColorTokens +import Combine + +@objc(VDSPagination) +open class Pagination: View { + + @Published var onPreviousTapped: PassthroughSubject = PassthroughSubject() + @Published var onNextTapped: PassthroughSubject = PassthroughSubject() + @Published var onPageWillChange: PassthroughSubject = PassthroughSubject() + @Published var onPageChanged: PassthroughSubject = PassthroughSubject() + + public var total: Int = 0 { + didSet { + setNeedsUpdate() + } + } + public var selectedPage: Int = 0 { didSet { setNeedsUpdate() } } + private var numberOfRows: Int = 0 { + didSet { + collectionView.collectionViewLayout.invalidateLayout() + setNeedsUpdate() + } + } + private let pageItemCellSize: CGSize = .init(width: 20, height: 16) + private let spacingBetweenCell: CGFloat = VDSLayout.Spacing.space1X.value + private let buttonTintColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) + private let buttonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) + + private lazy var collectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.itemSize = pageItemCellSize + layout.scrollDirection = .horizontal + layout.minimumInteritemSpacing = spacingBetweenCell + layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + layout.minimumLineSpacing = spacingBetweenCell + layout.sectionInset = .zero + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.isScrollEnabled = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.delegate = self + collectionView.dataSource = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.showsVerticalScrollIndicator = false + collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier) + collectionView.backgroundColor = .clear + return collectionView + }() + + //TODO: Need to check with textStyle with Matt as its getter only in ButtonBase + private lazy var previousButton: ButtonBase = { + let previousButton: ButtonBase + if #available(iOS 15.0, *) { + var configuration = ButtonBase.Configuration.plain() + configuration.imagePadding = VDSLayout.Spacing.space2X.value + configuration.attributedTitle = AttributedString("Previous", attributes: AttributeContainer([NSAttributedString.Key.font: TextStyle.boldBodySmall.font])) + configuration.titleAlignment = .leading + configuration.imagePlacement = .leading + configuration.contentInsets = .zero + previousButton = ButtonBase(configuration: configuration) + } else { + previousButton = ButtonBase() + previousButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value) + previousButton.setTitle("Previous", for: .normal) + previousButton.titleLabel?.font = TextStyle.boldBodySmall.font + } + previousButton.contentHorizontalAlignment = .leading + previousButton.translatesAutoresizingMaskIntoConstraints = false + previousButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + previousButton.setImage(BundleManager.shared.image(for: "pagination-arrow-left")?.withRenderingMode(.alwaysTemplate), for: .normal) + return previousButton + }() + + private let nextButton: ButtonBase = { + let nextButton: ButtonBase + if #available(iOS 15.0, *) { + var configuration = ButtonBase.Configuration.plain() + configuration.imagePadding = VDSLayout.Spacing.space2X.value + configuration.attributedTitle = AttributedString("Next", attributes: AttributeContainer([NSAttributedString.Key.font: TextStyle.boldBodySmall.font])) + configuration.imagePlacement = .trailing + configuration.titleAlignment = .trailing + configuration.contentInsets = .zero + nextButton = ButtonBase(configuration: configuration) + } else { + nextButton = ButtonBase() + nextButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value) + nextButton.semanticContentAttribute = .forceRightToLeft + nextButton.titleLabel?.font = TextStyle.boldBodySmall.font + nextButton.setTitle("Next", for: .normal) + } + //nextButton.textStyle = .boldBodySmall + nextButton.translatesAutoresizingMaskIntoConstraints = false + nextButton.contentHorizontalAlignment = .trailing + nextButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) + nextButton.setImage(BundleManager.shared.image(for: "pagination-arrow-right")?.withRenderingMode(.alwaysTemplate), for: .normal) + return nextButton + }() + + private let containerView: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } + + open override func initialSetup() { + super.initialSetup() + + addSubview(containerView) + containerView.pinToSuperView() + containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 288).activate() + containerView.heightAnchor.constraint(equalToConstant: 44).activate() + containerView.addSubview(previousButton) + containerView.addSubview(collectionView) + containerView.addSubview(nextButton) + + previousButton + .pinTop() + .pinBottom() + .pinLeading() + previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionView.leadingAnchor).activate() + collectionView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate() + collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() + collectionView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + collectionView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate() + collectionView.widthAnchor.constraint(equalToConstant: 92).activate() + nextButton + .pinTop() + .pinBottom() + .pinTrailing() + nextButton.onClick = onbuttonTapped + previousButton.onClick = onbuttonTapped + previousButton.isHidden = true + } + + open override func updateView() { + super.updateView() + + previousButton.tintColor = buttonTintColorConfiguration.getColor(surface) + nextButton.tintColor = buttonTintColorConfiguration.getColor(surface) + previousButton.setTitleColor(buttonTextColorConfiguration.getColor(surface), for: .normal) + nextButton.setTitleColor(buttonTextColorConfiguration.getColor(surface), for: .normal) + collectionView.reloadData() + } + + private func onbuttonTapped(_ sender: UIButton) { + let isNextAction = sender == nextButton + if isNextAction { + selectedPage += 1 + } else { + selectedPage -= 1 + } + updateSelection() + } + + private func updateSelection() { + collectionView.scrollToItem(at: IndexPath(row: max(selectedPage-1, 0), section: 0), at: .left, animated: false) + previousButton.isHidden = selectedPage == 0 + nextButton.isHidden = selectedPage == total - 1 + } +} + +extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { total } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PaginationCellItem.identifier, for: indexPath) as? PaginationCellItem else { return UICollectionViewCell() } + cell.update(selectedPage, currentIndex: indexPath.row, surface: surface) + return cell + } + + public func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool { + onPageWillChange.send(selectedPage) + return true + } + + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + selectedPage = indexPath.row + updateSelection() + onPageChanged.send(indexPath.row) + } +} + +internal final class PaginationCellItem: UICollectionViewCell { + + static let identifier: String = String(describing: PaginationCellItem.self) + private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + + private var indexLabel: Label = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .center + $0.numberOfLines = 1 + } + + override init(frame: CGRect) { + super.init(frame: frame) + setUp() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUp() + } + + private func setUp() { + let containerView = View() + containerView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(indexLabel) + contentView.addSubview(containerView) + containerView.pinToSuperView() + indexLabel.pinToSuperView() + indexLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: VDSLayout.Spacing.space5X.value).activate() + contentView.backgroundColor = .clear + containerView.backgroundColor = .clear + indexLabel.backgroundColor = .clear + } + + internal func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface) { + indexLabel.textStyle = selectedIndex == currentIndex ? .boldBodySmall : .bodySmall + indexLabel.text = "\(currentIndex)" + indexLabel.textColor = textColorConfiguration.getColor(surface) + } +} diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json new file mode 100644 index 00000000..6c37b40d --- /dev/null +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "pagination-arrow-left.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg new file mode 100644 index 00000000..a8c85c97 --- /dev/null +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json new file mode 100644 index 00000000..d294d555 --- /dev/null +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "pagination-arrow-right.svg", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg new file mode 100644 index 00000000..be02bedf --- /dev/null +++ b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg @@ -0,0 +1,3 @@ + + + From 8ed924c8056f582430ff8b1b3f5b08ce911e34cb Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Tue, 5 Mar 2024 16:48:26 +0530 Subject: [PATCH 02/31] Created PaginationButton and changelog --- VDS.xcodeproj/project.pbxproj | 12 ++ VDS/Components/Pagination/Pagination.swift | 165 +++++------------- .../Pagination/PaginationButton.swift | 87 +++++++++ .../Pagination/PaginationCellItem.swift | 51 ++++++ .../Pagination/PaginationChangeLog.txt | 34 ++++ 5 files changed, 227 insertions(+), 122 deletions(-) create mode 100644 VDS/Components/Pagination/PaginationButton.swift create mode 100644 VDS/Components/Pagination/PaginationCellItem.swift create mode 100644 VDS/Components/Pagination/PaginationChangeLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 79deb46b..d37e3f8c 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -17,8 +17,11 @@ 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; + 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; }; 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */; }; 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; + 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86D92B96F44C00700965 /* PaginationButton.swift */; }; + 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */; }; EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; }; EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */; }; EA0B18062A9E2D2D00F2D0CD /* SelectorItemBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18042A9E2D2D00F2D0CD /* SelectorItemBase.swift */; }; @@ -186,8 +189,11 @@ 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; + 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = ""; }; 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dropshadowable.swift; sourceTree = ""; }; 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; + 71FC86D92B96F44C00700965 /* PaginationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationButton.swift; sourceTree = ""; }; + 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationCellItem.swift; sourceTree = ""; }; EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = ""; }; EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = ""; }; EA0B18042A9E2D2D00F2D0CD /* SelectorItemBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorItemBase.swift; sourceTree = ""; }; @@ -390,6 +396,9 @@ isa = PBXGroup; children = ( 71B23C2C2B91FA690027F7D9 /* Pagination.swift */, + 71FC86D92B96F44C00700965 /* PaginationButton.swift */, + 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */, + 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */, ); path = Pagination; sourceTree = ""; @@ -981,6 +990,7 @@ EAEEECA92B1F969700531FC2 /* TooltipChangeLog.txt in Resources */, EAEEEC9C2B1F8F0700531FC2 /* TextLinkCaretChangeLog.txt in Resources */, EAA5EEE428F5B855003B3210 /* VerizonNHGDS-Light.otf in Resources */, + 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */, EAEEECAD2B1FC1A600531FC2 /* TitleLockupChangeLog.txt in Resources */, EAEEECAB2B1FBF2A00531FC2 /* ToggleChangeLog.txt in Resources */, ); @@ -1039,6 +1049,7 @@ EA985BEE2968A92400F2FF2E /* TitleLockupSubTitleModel.swift in Sources */, EA985BF22968B5BB00F2FF2E /* TitleLockupTextStyle.swift in Sources */, EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */, + 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */, EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */, EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */, EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */, @@ -1055,6 +1066,7 @@ EAC9258F2911C9DE00091998 /* EntryFieldBase.swift in Sources */, EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */, EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */, + 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */, EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 4df0a034..170e1935 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -12,37 +12,57 @@ import Combine @objc(VDSPagination) open class Pagination: View { - @Published var onPreviousTapped: PassthroughSubject = PassthroughSubject() - @Published var onNextTapped: PassthroughSubject = PassthroughSubject() - @Published var onPageWillChange: PassthroughSubject = PassthroughSubject() - @Published var onPageChanged: PassthroughSubject = PassthroughSubject() + open var onPageDidSelect: ((Int) -> Void)? + + public let previousButton: PaginationButton = .init(type: .previous) + public let nextButton: PaginationButton = .init(type: .next) public var total: Int = 0 { didSet { + previousButton.isHidden = true + nextButton.isHidden = total <= 1 + _selectedPage = 0 setNeedsUpdate() } } - public var selectedPage: Int = 0 { didSet { setNeedsUpdate() } } - private var numberOfRows: Int = 0 { - didSet { - collectionView.collectionViewLayout.invalidateLayout() + + public var selectedPage: Int { + set { + if newValue >= total { + _selectedPage = total - 1 + } else if newValue < 0 { + _selectedPage = 0 + } else { + _selectedPage = max(newValue - 1, 0) + } setNeedsUpdate() + updateSelection() + } + get { + _selectedPage } } + + private var _selectedPage: Int = 0 private let pageItemCellSize: CGSize = .init(width: 20, height: 16) private let spacingBetweenCell: CGFloat = VDSLayout.Spacing.space1X.value - private let buttonTintColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) - private let buttonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) - private lazy var collectionView: UICollectionView = { + private let containerView: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } + + private lazy var flowLayout: UICollectionViewFlowLayout = { let layout = UICollectionViewFlowLayout() - layout.itemSize = pageItemCellSize layout.scrollDirection = .horizontal layout.minimumInteritemSpacing = spacingBetweenCell - layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize layout.minimumLineSpacing = spacingBetweenCell layout.sectionInset = .zero - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + layout.estimatedItemSize = pageItemCellSize + return layout + }() + + private lazy var collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) collectionView.isScrollEnabled = false collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.delegate = self @@ -54,59 +74,6 @@ open class Pagination: View { return collectionView }() - //TODO: Need to check with textStyle with Matt as its getter only in ButtonBase - private lazy var previousButton: ButtonBase = { - let previousButton: ButtonBase - if #available(iOS 15.0, *) { - var configuration = ButtonBase.Configuration.plain() - configuration.imagePadding = VDSLayout.Spacing.space2X.value - configuration.attributedTitle = AttributedString("Previous", attributes: AttributeContainer([NSAttributedString.Key.font: TextStyle.boldBodySmall.font])) - configuration.titleAlignment = .leading - configuration.imagePlacement = .leading - configuration.contentInsets = .zero - previousButton = ButtonBase(configuration: configuration) - } else { - previousButton = ButtonBase() - previousButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value) - previousButton.setTitle("Previous", for: .normal) - previousButton.titleLabel?.font = TextStyle.boldBodySmall.font - } - previousButton.contentHorizontalAlignment = .leading - previousButton.translatesAutoresizingMaskIntoConstraints = false - previousButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - previousButton.setImage(BundleManager.shared.image(for: "pagination-arrow-left")?.withRenderingMode(.alwaysTemplate), for: .normal) - return previousButton - }() - - private let nextButton: ButtonBase = { - let nextButton: ButtonBase - if #available(iOS 15.0, *) { - var configuration = ButtonBase.Configuration.plain() - configuration.imagePadding = VDSLayout.Spacing.space2X.value - configuration.attributedTitle = AttributedString("Next", attributes: AttributeContainer([NSAttributedString.Key.font: TextStyle.boldBodySmall.font])) - configuration.imagePlacement = .trailing - configuration.titleAlignment = .trailing - configuration.contentInsets = .zero - nextButton = ButtonBase(configuration: configuration) - } else { - nextButton = ButtonBase() - nextButton.imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value) - nextButton.semanticContentAttribute = .forceRightToLeft - nextButton.titleLabel?.font = TextStyle.boldBodySmall.font - nextButton.setTitle("Next", for: .normal) - } - //nextButton.textStyle = .boldBodySmall - nextButton.translatesAutoresizingMaskIntoConstraints = false - nextButton.contentHorizontalAlignment = .trailing - nextButton.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - nextButton.setImage(BundleManager.shared.image(for: "pagination-arrow-right")?.withRenderingMode(.alwaysTemplate), for: .normal) - return nextButton - }() - - private let containerView: View = View().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } - open override func initialSetup() { super.initialSetup() @@ -140,27 +107,27 @@ open class Pagination: View { open override func updateView() { super.updateView() - previousButton.tintColor = buttonTintColorConfiguration.getColor(surface) - nextButton.tintColor = buttonTintColorConfiguration.getColor(surface) - previousButton.setTitleColor(buttonTextColorConfiguration.getColor(surface), for: .normal) - nextButton.setTitleColor(buttonTextColorConfiguration.getColor(surface), for: .normal) + nextButton.surface = surface + previousButton.surface = surface collectionView.reloadData() } private func onbuttonTapped(_ sender: UIButton) { let isNextAction = sender == nextButton if isNextAction { - selectedPage += 1 + _selectedPage += 1 } else { - selectedPage -= 1 + _selectedPage -= 1 } updateSelection() } private func updateSelection() { - collectionView.scrollToItem(at: IndexPath(row: max(selectedPage-1, 0), section: 0), at: .left, animated: false) + let indexPath = IndexPath(row: selectedPage, section: 0) + collectionView.scrollToItem(at: indexPath, at: .left, animated: false) previousButton.isHidden = selectedPage == 0 nextButton.isHidden = selectedPage == total - 1 + collectionView.reloadData() } } @@ -174,55 +141,9 @@ extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICo return cell } - public func collectionView(_ collectionView: UICollectionView, shouldHighlightItemAt indexPath: IndexPath) -> Bool { - onPageWillChange.send(selectedPage) - return true - } - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - selectedPage = indexPath.row + _selectedPage = indexPath.row updateSelection() - onPageChanged.send(indexPath.row) - } -} - -internal final class PaginationCellItem: UICollectionViewCell { - - static let identifier: String = String(describing: PaginationCellItem.self) - private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) - - private var indexLabel: Label = Label().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.textAlignment = .center - $0.numberOfLines = 1 - } - - override init(frame: CGRect) { - super.init(frame: frame) - setUp() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setUp() - } - - private func setUp() { - let containerView = View() - containerView.translatesAutoresizingMaskIntoConstraints = false - containerView.addSubview(indexLabel) - contentView.addSubview(containerView) - containerView.pinToSuperView() - indexLabel.pinToSuperView() - indexLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: VDSLayout.Spacing.space5X.value).activate() - contentView.backgroundColor = .clear - containerView.backgroundColor = .clear - indexLabel.backgroundColor = .clear - } - - internal func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface) { - indexLabel.textStyle = selectedIndex == currentIndex ? .boldBodySmall : .bodySmall - indexLabel.text = "\(currentIndex)" - indexLabel.textColor = textColorConfiguration.getColor(surface) + onPageDidSelect?(indexPath.row) } } diff --git a/VDS/Components/Pagination/PaginationButton.swift b/VDS/Components/Pagination/PaginationButton.swift new file mode 100644 index 00000000..6a1cd3fa --- /dev/null +++ b/VDS/Components/Pagination/PaginationButton.swift @@ -0,0 +1,87 @@ +// +// PaginationButton.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 05/03/24. +// + +import UIKit +import VDSColorTokens + +open class PaginationButton: ButtonBase { + + private let buttonTintColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) + private let buttonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) + + @available(iOS 15.0, *) + var buttonConfiguration: Button.Configuration { + var configuration = ButtonBase.Configuration.plain() + configuration.imagePadding = VDSLayout.Spacing.space2X.value + configuration.imagePlacement = type == .next ? .trailing : .leading + configuration.titleAlignment = type == .next ? .trailing : .leading + configuration.contentInsets = .zero + return configuration + } + + open override var textStyle: TextStyle { TextStyle.boldBodySmall } + + open override var textColor: UIColor { buttonTextColorConfiguration.getColor(surface) } + + private var type: Type = .next + + init(type: Type) { + self.type = type + super.init() + } + + required public init() { + super.init() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + open override func initialSetup() { + super.initialSetup() + if #available(iOS 15.0, *) { + configuration = buttonConfiguration + } else { + semanticContentAttribute = type == .next ? .forceRightToLeft : .forceLeftToRight + imageEdgeInsets = .init(top: 0, left: 0, bottom: 0, right: VDSLayout.Spacing.space2X.value) + } + contentHorizontalAlignment = type == .next ? .trailing : .leading + } + + open override func updateView() { + text = type.title + setImage(type.image, for: .normal) + tintColor = buttonTintColorConfiguration.getColor(surface) + super.updateView() + } +} + +extension PaginationButton { + + enum `Type` { + case previous, next + + var title: String { + switch self { + case .next: + "Next" + case .previous: + "Previous" + } + } + + var image: UIImage? { + switch self { + case .previous: + BundleManager.shared.image(for: "pagination-arrow-left")?.withRenderingMode(.alwaysTemplate) + case .next: + BundleManager.shared.image(for: "pagination-arrow-right")?.withRenderingMode(.alwaysTemplate) + } + } + } +} diff --git a/VDS/Components/Pagination/PaginationCellItem.swift b/VDS/Components/Pagination/PaginationCellItem.swift new file mode 100644 index 00000000..1a546551 --- /dev/null +++ b/VDS/Components/Pagination/PaginationCellItem.swift @@ -0,0 +1,51 @@ +// +// PaginationCellItem.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 05/03/24. +// + +import UIKit +import VDSColorTokens + +final class PaginationCellItem: UICollectionViewCell { + + static let identifier: String = String(describing: PaginationCellItem.self) + + private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + + private var indexLabel: Label = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .center + $0.numberOfLines = 1 + } + + override init(frame: CGRect) { + super.init(frame: frame) + setUp() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUp() + } + + private func setUp() { + let containerView = View() + containerView.translatesAutoresizingMaskIntoConstraints = false + containerView.addSubview(indexLabel) + contentView.addSubview(containerView) + containerView.pinToSuperView() + indexLabel.pinToSuperView() + indexLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: VDSLayout.Spacing.space5X.value).activate() + contentView.backgroundColor = .clear + containerView.backgroundColor = .clear + indexLabel.backgroundColor = .clear + } + + func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface) { + indexLabel.textStyle = selectedIndex == currentIndex ? .boldBodySmall : .bodySmall + indexLabel.text = "\(currentIndex + 1)" + indexLabel.textColor = textColorConfiguration.getColor(surface) + } +} diff --git a/VDS/Components/Pagination/PaginationChangeLog.txt b/VDS/Components/Pagination/PaginationChangeLog.txt new file mode 100644 index 00000000..66f0ac14 --- /dev/null +++ b/VDS/Components/Pagination/PaginationChangeLog.txt @@ -0,0 +1,34 @@ +MM/DD/YYYY +---------------- + +Initial Brand 3.0 handoff + +12/17/2021 +---------------- +- Replaced focusring colors (previously interactive/onlight/ondark) with accessibility/onlight/ondark colors +- Updated focus border name (previously interactive.focusring.onlight) with focusring.onlight/ondark + +02/28/2022 +---------------- +- Change Page Item Active to Page Item Selected. All Active references changed to Selected. + +03/01/2022 +---------------- +- Replaced Left and Right Arrow Non-Scaling icons with VDS Icon. +- Removed “weight” and “vector effect” from Anatomy frame. + +08/10/2022 +---------------- +- Updated default and inverted prop to light and dark surface. + +11/30/2022 +---------------- +- Added "(web only)" to any instance of "keyboard focus" + +12/13/2022 +---------------- +- Replaced focus border pixel and style & spacing values with tokens. + +01/12/2023 +---------------- +- Removed “Page Item Selected” from Anatomy. From cd85748a11732e632f0cb4e53e9641f42aac9f64 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Wed, 6 Mar 2024 21:25:18 +0530 Subject: [PATCH 03/31] Fixed bugs, added comments and created new flow layout --- VDS.xcodeproj/project.pbxproj | 8 + VDS/Components/Pagination/Pagination.swift | 174 ++++++++++++------ .../Pagination/PaginationButton.swift | 35 +++- .../Pagination/PaginationCellItem.swift | 15 +- .../Pagination/PaginationFlowLayout.swift | 91 +++++++++ VDS/Utilities/Clamping.swift | 24 +++ 6 files changed, 276 insertions(+), 71 deletions(-) create mode 100644 VDS/Components/Pagination/PaginationFlowLayout.swift create mode 100644 VDS/Utilities/Clamping.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index d37e3f8c..c70712cf 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86D92B96F44C00700965 /* PaginationButton.swift */; }; 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */; }; + 71FC86E22B97483000700965 /* Clamping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86E12B97483000700965 /* Clamping.swift */; }; + 71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */; }; EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; }; EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */; }; EA0B18062A9E2D2D00F2D0CD /* SelectorItemBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18042A9E2D2D00F2D0CD /* SelectorItemBase.swift */; }; @@ -194,6 +196,8 @@ 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; 71FC86D92B96F44C00700965 /* PaginationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationButton.swift; sourceTree = ""; }; 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationCellItem.swift; sourceTree = ""; }; + 71FC86E12B97483000700965 /* Clamping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clamping.swift; sourceTree = ""; }; + 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationFlowLayout.swift; sourceTree = ""; }; EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = ""; }; EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = ""; }; EA0B18042A9E2D2D00F2D0CD /* SelectorItemBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorItemBase.swift; sourceTree = ""; }; @@ -398,6 +402,7 @@ 71B23C2C2B91FA690027F7D9 /* Pagination.swift */, 71FC86D92B96F44C00700965 /* PaginationButton.swift */, 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */, + 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */, 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */, ); path = Pagination; @@ -603,6 +608,7 @@ isa = PBXGroup; children = ( EA3361BC288B2C760071C351 /* TypeAlias.swift */, + 71FC86E12B97483000700965 /* Clamping.swift */, ); path = Utilities; sourceTree = ""; @@ -1022,6 +1028,7 @@ EA3361C328902D960071C351 /* Toggle.swift in Sources */, EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */, EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */, + 71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */, EAC9258C2911C9DE00091998 /* InputField.swift in Sources */, EA3362402892EF6C0071C351 /* Label.swift in Sources */, EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */, @@ -1030,6 +1037,7 @@ 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */, EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */, EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */, + 71FC86E22B97483000700965 /* Clamping.swift in Sources */, EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */, EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */, EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 170e1935..f4bf8a60 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -9,58 +9,24 @@ import Foundation import VDSColorTokens import Combine +///Pagination is a control that enables customers to navigate multiple pages of content by selecting either a specific page or the next or previous set of four pages. @objc(VDSPagination) open class Pagination: View { - open var onPageDidSelect: ((Int) -> Void)? - - public let previousButton: PaginationButton = .init(type: .previous) - public let nextButton: PaginationButton = .init(type: .next) - - public var total: Int = 0 { - didSet { - previousButton.isHidden = true - nextButton.isHidden = total <= 1 - _selectedPage = 0 - setNeedsUpdate() - } - } - - public var selectedPage: Int { - set { - if newValue >= total { - _selectedPage = total - 1 - } else if newValue < 0 { - _selectedPage = 0 - } else { - _selectedPage = max(newValue - 1, 0) - } - setNeedsUpdate() - updateSelection() - } - get { - _selectedPage - } - } - - private var _selectedPage: Int = 0 - private let pageItemCellSize: CGSize = .init(width: 20, height: 16) - private let spacingBetweenCell: CGFloat = VDSLayout.Spacing.space1X.value - + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + ///Collectionview width anchor + private var collectionViewWidthAnchor: NSLayoutConstraint? + ///Selected page index + private var _selectedPageIndex: Int = 0 + ///Custom flow layout defined for the Pagination + private let flowLayout = PaginationFlowLayout() + ///A root view for the pagination private let containerView: View = View().with { $0.translatesAutoresizingMaskIntoConstraints = false } - - private lazy var flowLayout: UICollectionViewFlowLayout = { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .horizontal - layout.minimumInteritemSpacing = spacingBetweenCell - layout.minimumLineSpacing = spacingBetweenCell - layout.sectionInset = .zero - layout.estimatedItemSize = pageItemCellSize - return layout - }() - + ///Collectionview to render pagination indexes private lazy var collectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) collectionView.isScrollEnabled = false @@ -74,6 +40,48 @@ open class Pagination: View { return collectionView }() + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + ///Previous button to select previous page + public let previousButton: PaginationButton = .init(type: .previous) + ///Next button to select next page + public let nextButton: PaginationButton = .init(type: .next) + /// A callback when the page changes. Passes parameters (selectedPage). + public var onPageDidSelect: ((Int) -> Void)? + /// Total number of pages, allows limit ranging from 0 to 9999. + @Clamping(range: 0...9999) + public var total: Int { + didSet { + previousButton.isHidden = true + nextButton.isHidden = total <= 1 + _selectedPageIndex = 0 + setNeedsUpdate() + updateSelection() + } + } + ///Selected active page number and clips to total pages if selected index is greater than the total pages. + public var selectedPage: Int { + set { + if newValue >= total { + _selectedPageIndex = total - 1 + } else if newValue < 0 { + _selectedPageIndex = 0 + } else { + _selectedPageIndex = max(newValue - 1, 0) + } + setNeedsUpdate() + updateSelection() + } + get { + _selectedPageIndex + 1 //Returns selected page value not index + } + } + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + /// Executed on initialization for this View. open override func initialSetup() { super.initialSetup() @@ -94,56 +102,100 @@ open class Pagination: View { collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() collectionView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() collectionView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate() - collectionView.widthAnchor.constraint(equalToConstant: 92).activate() + collectionViewWidthAnchor = collectionView.widthAnchor.constraint(equalToConstant: 92) + collectionViewWidthAnchor?.activate() + nextButton .pinTop() .pinBottom() .pinTrailing() + nextButton.onClick = onbuttonTapped previousButton.onClick = onbuttonTapped previousButton.isHidden = true + + flowLayout.$collectionViewWidth + .receive(on: RunLoop.main) + .sink { [weak self] value in + self?.collectionViewWidthAnchor?.constant = value + }.store(in: &subscribers) } + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() - nextButton.surface = surface previousButton.surface = surface collectionView.reloadData() } + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + ///When previous/next button is tapped private func onbuttonTapped(_ sender: UIButton) { let isNextAction = sender == nextButton - if isNextAction { - _selectedPage += 1 - } else { - _selectedPage -= 1 - } + _selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 } updateSelection() } + ///Refreshing the UI based on the selected page private func updateSelection() { - let indexPath = IndexPath(row: selectedPage, section: 0) - collectionView.scrollToItem(at: indexPath, at: .left, animated: false) - previousButton.isHidden = selectedPage == 0 - nextButton.isHidden = selectedPage == total - 1 + guard _selectedPageIndex < total else { return } + collectionView.scrollToItem(at: IndexPath(row: _selectedPageIndex, section: 0), at: .left, animated: false) + previousButton.isHidden = _selectedPageIndex == 0 + nextButton.isHidden = _selectedPageIndex == total - 1 collectionView.reloadData() + verifyIfMaxDigitChanged() + } + + ///Identifying if there is any change in the digits of upcoming page + func verifyIfMaxDigitChanged() { + let upperLimitPage = _selectedPageIndex + flowLayout.maxNumberOfColumns + let upperLimitDigits = upperLimitPage.digitCount //future value digits + switch (flowLayout.numberOfColumns, upperLimitDigits) { + case (_, 3), (_, 4): + flowLayout.numberOfColumns = 3 + default: + flowLayout.numberOfColumns = 4 + } + if upperLimitDigits != flowLayout.upperLimitDigits { + flowLayout.upperLimitDigits = upperLimitDigits + flowLayout.invalidateLayout() + collectionView.reloadData() + collectionView.scrollToItem(at: IndexPath(row: self._selectedPageIndex, section: 0), at: .left, animated: false) + } } } extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { - + //-------------------------------------------------- + // MARK: - UICollectionView Delegate & Datasource + //-------------------------------------------------- public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { total } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PaginationCellItem.identifier, for: indexPath) as? PaginationCellItem else { return UICollectionViewCell() } - cell.update(selectedPage, currentIndex: indexPath.row, surface: surface) + cell.update(_selectedPageIndex, currentIndex: indexPath.row, surface: surface) return cell } public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - _selectedPage = indexPath.row + _selectedPageIndex = indexPath.row updateSelection() - onPageDidSelect?(indexPath.row) + onPageDidSelect?(selectedPage) + } +} + +fileprivate extension Int { + //-------------------------------------------------- + // MARK: - Extension on Int to identify number of digits in given number. + //-------------------------------------------------- + var digitCount: Int { + numberOfDigits(in: self) + } + + private func numberOfDigits(in number: Int) -> Int { + number < 10 && number >= 0 ? 1 : 1 + numberOfDigits(in: number/10) } } diff --git a/VDS/Components/Pagination/PaginationButton.swift b/VDS/Components/Pagination/PaginationButton.swift index 6a1cd3fa..3805051d 100644 --- a/VDS/Components/Pagination/PaginationButton.swift +++ b/VDS/Components/Pagination/PaginationButton.swift @@ -8,13 +8,20 @@ import UIKit import VDSColorTokens +///This is customised button for Pagination view open class PaginationButton: ButtonBase { - + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + /// Type of the PaginationButton + private var type: Type = .next + /// Button tint color configuration private let buttonTintColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) + /// Button title color configuration private let buttonTextColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteBlack, VDSColor.paletteWhite) - + /// Button configuration for iOS 15+ @available(iOS 15.0, *) - var buttonConfiguration: Button.Configuration { + private var buttonConfiguration: Button.Configuration { var configuration = ButtonBase.Configuration.plain() configuration.imagePadding = VDSLayout.Spacing.space2X.value configuration.imagePlacement = type == .next ? .trailing : .leading @@ -23,12 +30,17 @@ open class PaginationButton: ButtonBase { return configuration } + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// TextStyle used on the titleLabel. open override var textStyle: TextStyle { TextStyle.boldBodySmall } - + /// UIColor used on the titleLabel text. open override var textColor: UIColor { buttonTextColorConfiguration.getColor(surface) } - private var type: Type = .next - + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- init(type: Type) { self.type = type super.init() @@ -42,6 +54,10 @@ open class PaginationButton: ButtonBase { super.init(coder: coder) } + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + /// Executed on initialization for this View. open override func initialSetup() { super.initialSetup() if #available(iOS 15.0, *) { @@ -53,6 +69,7 @@ open class PaginationButton: ButtonBase { contentHorizontalAlignment = type == .next ? .trailing : .leading } + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { text = type.title setImage(type.image, for: .normal) @@ -62,7 +79,9 @@ open class PaginationButton: ButtonBase { } extension PaginationButton { - + //-------------------------------------------------- + // MARK: - Enum to configure PaginationButton + //-------------------------------------------------- enum `Type` { case previous, next @@ -74,7 +93,7 @@ extension PaginationButton { "Previous" } } - + ///Image for the configuration type var image: UIImage? { switch self { case .previous: diff --git a/VDS/Components/Pagination/PaginationCellItem.swift b/VDS/Components/Pagination/PaginationCellItem.swift index 1a546551..68fa7271 100644 --- a/VDS/Components/Pagination/PaginationCellItem.swift +++ b/VDS/Components/Pagination/PaginationCellItem.swift @@ -8,18 +8,27 @@ import UIKit import VDSColorTokens +///This is customised view for Pagination cell item final class PaginationCellItem: UICollectionViewCell { + ///Identifier for the PaginationCellItem static let identifier: String = String(describing: PaginationCellItem.self) - + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + ///Text color configuration for the element private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) - + ///Pagination index label private var indexLabel: Label = Label().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.textAlignment = .center $0.numberOfLines = 1 } + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- override init(frame: CGRect) { super.init(frame: frame) setUp() @@ -30,6 +39,7 @@ final class PaginationCellItem: UICollectionViewCell { setUp() } + ///Configuring the cell with default setup private func setUp() { let containerView = View() containerView.translatesAutoresizingMaskIntoConstraints = false @@ -43,6 +53,7 @@ final class PaginationCellItem: UICollectionViewCell { indexLabel.backgroundColor = .clear } + ///Updating UI based on selected index, current index along with surface func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface) { indexLabel.textStyle = selectedIndex == currentIndex ? .boldBodySmall : .bodySmall indexLabel.text = "\(currentIndex + 1)" diff --git a/VDS/Components/Pagination/PaginationFlowLayout.swift b/VDS/Components/Pagination/PaginationFlowLayout.swift new file mode 100644 index 00000000..89debfe2 --- /dev/null +++ b/VDS/Components/Pagination/PaginationFlowLayout.swift @@ -0,0 +1,91 @@ +// +// PaginationFlowLayout.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 06/03/24. +// + +import Foundation +import UIKit + +///Customised flow layout for Pagination view +final class PaginationFlowLayout : UICollectionViewLayout { + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + ///Spacing between the pagination cells + private let spacingBetweenCell: CGFloat = VDSLayout.Spacing.space1X.value + ///Pre-defined sizes of the pagination cell based on number of digits. + private var upperLimitSize: CGSize { + switch upperLimitDigits { + case 3: .init(width: 28, height: 16) + case 4: .init(width: 34, height: 16) + default: .init(width: 20, height: 16) + } + } + ///Property to store the defined layout attributes. + private var itemCache : [UICollectionViewLayoutAttributes] = [] + + //-------------------------------------------------- + // MARK: - Internal Properties + //-------------------------------------------------- + ///Maximum number of page indexes shown on UI + let maxNumberOfColumns: Int = 4 + ///Number of digits of the maximum page index. + var upperLimitDigits: Int = 0 + ///Number of page indexes shown on UI. + var numberOfColumns: Int = 4 + ///A property that publishes when there is change in collection view width. + @Published var collectionViewWidth: CGFloat = 0 + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + ///Preparing the layout collection attributes for pagination and updating the collectionview width. + override func prepare() { + + guard let collectionView else { return } + + itemCache.removeAll() + var xPos : CGFloat = 0 + for item in 0.. [UICollectionViewLayoutAttributes]? { + var visibleLayoutAttributes: [UICollectionViewLayoutAttributes] = [] + for attributes in itemCache { + if attributes.frame.intersects(rect) { + visibleLayoutAttributes.append(attributes) + } + } + return visibleLayoutAttributes + } + + ///This will return the layout attributes at particular indexPath + override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { + return itemCache[indexPath.row] + } + + ///Returns the collectionview content size + override var collectionViewContentSize: CGSize { + guard let lastAttribute = itemCache.last else { return super.collectionViewContentSize } + return .init(width: lastAttribute.frame.width + lastAttribute.frame.origin.x, height: 16) + } +} diff --git a/VDS/Utilities/Clamping.swift b/VDS/Utilities/Clamping.swift new file mode 100644 index 00000000..c8213828 --- /dev/null +++ b/VDS/Utilities/Clamping.swift @@ -0,0 +1,24 @@ +// +// Clamping.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 05/03/24. +// + +import Foundation + +@propertyWrapper public struct Clamping { + + private var value: Value + private let range: ClosedRange + + public init(range: ClosedRange) { + self.value = range.lowerBound + self.range = range + } + + public var wrappedValue: Value { + get { value } + set { value = min(max(range.lowerBound, newValue), range.upperBound) } + } +} From ae12db4a2497738a2f2dc6c07fb3438fa6ad1382 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Mon, 11 Mar 2024 16:25:32 +0530 Subject: [PATCH 04/31] reordering the Pagination folder & made selected index as second element --- VDS.xcodeproj/project.pbxproj | 18 +++++++----------- VDS/Components/Pagination/Pagination.swift | 7 +++++-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 82643d0f..0b263712 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -18,16 +18,14 @@ 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; }; - 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */; }; + 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; 71FC86DA2B96F44C00700965 /* PaginationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86D92B96F44C00700965 /* PaginationButton.swift */; }; 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */; }; - 71FC86E22B97483000700965 /* Clamping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86E12B97483000700965 /* Clamping.swift */; }; - 71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */; }; - 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; - 71C02B382B7BD98F00E93E66 /* NotificationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */; }; 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86DD2B9738B900700965 /* SurfaceConfigurationValue.swift */; }; 71FC86E02B973AE500700965 /* DropShadowConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86DF2B973AE500700965 /* DropShadowConfiguration.swift */; }; + 71FC86E22B97483000700965 /* Clamping.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86E12B97483000700965 /* Clamping.swift */; }; + 71FC86E42B9841AC00700965 /* PaginationFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */; }; EA0B18022A9E236900F2D0CD /* SelectorGroupBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */; }; EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */; }; EA0B18062A9E2D2D00F2D0CD /* SelectorItemBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA0B18042A9E2D2D00F2D0CD /* SelectorItemBase.swift */; }; @@ -196,16 +194,14 @@ 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = ""; }; - 71BFA7092B7F70E6000DCE33 /* Dropshadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dropshadowable.swift; sourceTree = ""; }; + 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; 71FC86D92B96F44C00700965 /* PaginationButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationButton.swift; sourceTree = ""; }; 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationCellItem.swift; sourceTree = ""; }; - 71FC86E12B97483000700965 /* Clamping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clamping.swift; sourceTree = ""; }; - 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationFlowLayout.swift; sourceTree = ""; }; - 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; - 71C02B372B7BD98F00E93E66 /* NotificationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = NotificationChangeLog.txt; sourceTree = ""; }; 71FC86DD2B9738B900700965 /* SurfaceConfigurationValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SurfaceConfigurationValue.swift; sourceTree = ""; }; 71FC86DF2B973AE500700965 /* DropShadowConfiguration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowConfiguration.swift; sourceTree = ""; }; + 71FC86E12B97483000700965 /* Clamping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clamping.swift; sourceTree = ""; }; + 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationFlowLayout.swift; sourceTree = ""; }; EA0B18012A9E236900F2D0CD /* SelectorGroupBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorGroupBase.swift; sourceTree = ""; }; EA0B18032A9E2D2D00F2D0CD /* SelectorBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorBase.swift; sourceTree = ""; }; EA0B18042A9E2D2D00F2D0CD /* SelectorItemBase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SelectorItemBase.swift; sourceTree = ""; }; @@ -519,7 +515,6 @@ EA33619D288B1E330071C351 /* Components */ = { isa = PBXGroup; children = ( - 71B23C2B2B91FA510027F7D9 /* Pagination */, EA4DB2FE28DCBC1900103EE3 /* Badge */, EAD062AE2A3B87210015965D /* BadgeIndicator */, EA0FC2BE2912D18200DF80B4 /* Buttons */, @@ -529,6 +524,7 @@ 44604AD529CE195300E62B51 /* Line */, EAD0688C2A55F801002E3A2D /* Loader */, 445BA07629C07ABA0036A7C5 /* Notification */, + 71B23C2B2B91FA510027F7D9 /* Pagination */, EA89200B28B530F0006B9984 /* RadioBox */, EAF7F11428A1470D00B287F5 /* RadioButton */, EA596ABB2A16B4D500300C4B /* Tabs */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index f4bf8a60..1f00b949 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -142,7 +142,8 @@ open class Pagination: View { ///Refreshing the UI based on the selected page private func updateSelection() { guard _selectedPageIndex < total else { return } - collectionView.scrollToItem(at: IndexPath(row: _selectedPageIndex, section: 0), at: .left, animated: false) + //Need to make selected page as second element so scrolling previous index of the selected page to left + collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) previousButton.isHidden = _selectedPageIndex == 0 nextButton.isHidden = _selectedPageIndex == total - 1 collectionView.reloadData() @@ -163,7 +164,8 @@ open class Pagination: View { flowLayout.upperLimitDigits = upperLimitDigits flowLayout.invalidateLayout() collectionView.reloadData() - collectionView.scrollToItem(at: IndexPath(row: self._selectedPageIndex, section: 0), at: .left, animated: false) + //Need to make selected page as second element so scrolling previous index of the selected page to left + collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) } } } @@ -181,6 +183,7 @@ extension Pagination: UICollectionViewDelegate, UICollectionViewDataSource, UICo } public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + guard _selectedPageIndex != indexPath.row else { return } _selectedPageIndex = indexPath.row updateSelection() onPageDidSelect?(selectedPage) From 3a064c914ce016a43c6e723ac8fbe18931c2f137 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Mon, 11 Mar 2024 18:08:33 +0530 Subject: [PATCH 05/31] added Pagination in VDS.md --- VDS/VDS.docc/VDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index 8beb9255..dae2c72a 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -33,6 +33,7 @@ Using the system allows designers and developers to collaborate more easily and - ``Line`` - ``Loader`` - ``Notification`` +- ``Pagination`` - ``RadioBoxItem`` - ``RadioBoxGroup`` - ``RadioButton`` From 024194e7e56a9c8a6bff0ebb75a9d6d9003febbb Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Tue, 12 Mar 2024 18:24:48 +0530 Subject: [PATCH 06/31] Updated accessibility, add addressed review comments --- VDS.xcodeproj/project.pbxproj | 4 + VDS/Components/Pagination/Pagination.swift | 82 ++++++++++++------- .../Pagination/PaginationCellItem.swift | 1 + .../Pagination/PaginationCollectionView.swift | 66 +++++++++++++++ 4 files changed, 122 insertions(+), 31 deletions(-) create mode 100644 VDS/Components/Pagination/PaginationCollectionView.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 0b263712..38a79f1e 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -16,6 +16,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; + 71ACE89C2BA0451200FB6ADC /* PaginationCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */; }; 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; }; 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; @@ -192,6 +193,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; + 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationCollectionView.swift; sourceTree = ""; }; 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = ""; }; 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; @@ -404,6 +406,7 @@ isa = PBXGroup; children = ( 71B23C2C2B91FA690027F7D9 /* Pagination.swift */, + 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */, 71FC86D92B96F44C00700965 /* PaginationButton.swift */, 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */, 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */, @@ -1056,6 +1059,7 @@ EAC925842911C63100091998 /* Colorable.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */, + 71ACE89C2BA0451200FB6ADC /* PaginationCollectionView.swift in Sources */, EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */, EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 1f00b949..754935b7 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -21,24 +21,16 @@ open class Pagination: View { ///Selected page index private var _selectedPageIndex: Int = 0 ///Custom flow layout defined for the Pagination - private let flowLayout = PaginationFlowLayout() + private var flowLayout: PaginationFlowLayout { + guard let flowLayout = collectionContainerView.collectionView.collectionViewLayout as? PaginationFlowLayout else { fatalError("Flow layout should be PaginationFlowLayout class") } + return flowLayout + } ///A root view for the pagination private let containerView: View = View().with { $0.translatesAutoresizingMaskIntoConstraints = false } - ///Collectionview to render pagination indexes - private lazy var collectionView: UICollectionView = { - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) - collectionView.isScrollEnabled = false - collectionView.translatesAutoresizingMaskIntoConstraints = false - collectionView.delegate = self - collectionView.dataSource = self - collectionView.showsHorizontalScrollIndicator = false - collectionView.showsVerticalScrollIndicator = false - collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier) - collectionView.backgroundColor = .clear - return collectionView - }() + ///Container view to hold collectionview to render pagination indexes + private let collectionContainerView = PaginationCollectionView() //-------------------------------------------------- // MARK: - Public Properties @@ -86,24 +78,32 @@ open class Pagination: View { super.initialSetup() addSubview(containerView) - containerView.pinToSuperView() - containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 288).activate() + containerView + .pinTop() + .pinBottom() + containerView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor).activate() + trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor).activate() + containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + containerView.widthAnchor.constraint(equalToConstant: 288).activate() containerView.heightAnchor.constraint(equalToConstant: 44).activate() containerView.addSubview(previousButton) - containerView.addSubview(collectionView) + containerView.addSubview(collectionContainerView) containerView.addSubview(nextButton) previousButton .pinTop() .pinBottom() .pinLeading() - previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionView.leadingAnchor).activate() - collectionView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate() - collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() - collectionView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() - collectionView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate() - collectionViewWidthAnchor = collectionView.widthAnchor.constraint(equalToConstant: 92) + + previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionContainerView.leadingAnchor).activate() + collectionContainerView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate() + collectionContainerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() + collectionContainerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + collectionContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate() + collectionViewWidthAnchor = collectionContainerView.widthAnchor.constraint(equalToConstant: 92) collectionViewWidthAnchor?.activate() + collectionContainerView.collectionView.delegate = self + collectionContainerView.collectionView.dataSource = self nextButton .pinTop() @@ -117,8 +117,24 @@ open class Pagination: View { flowLayout.$collectionViewWidth .receive(on: RunLoop.main) .sink { [weak self] value in - self?.collectionViewWidthAnchor?.constant = value - }.store(in: &subscribers) + self?.collectionViewWidthAnchor?.constant = value //As cell width is dynamic i.e cell may contain 2 or 3 or 4 charcters. Make sure that all the visible cells are displayed. + }.store(in: &subscribers) + collectionContainerView.onAccessibilityIncrement = { [weak self] in + guard let self else { return } + self.selectedPage = max(0, self.selectedPage + 1) + } + collectionContainerView.onAccessibilityDecrement = { [weak self] in + guard let self else { return } + self.selectedPage = max(0, self.selectedPage - 1) + } + } + + ///Updating the accessiblity values i.e elements, label, value other items for the component. + open override func updateAccessibility() { + super.updateAccessibility() + accessibilityElements = [previousButton, collectionContainerView, nextButton] + collectionContainerView.accessibilityLabel = "Pagination containing \(total) pages" + collectionContainerView.accessibilityValue = "Page \(selectedPage) of \(total) selected" } /// Used to make changes to the View based off a change events or from local properties. @@ -126,7 +142,7 @@ open class Pagination: View { super.updateView() nextButton.surface = surface previousButton.surface = surface - collectionView.reloadData() + collectionContainerView.collectionView.reloadData() } //-------------------------------------------------- @@ -137,21 +153,25 @@ open class Pagination: View { let isNextAction = sender == nextButton _selectedPageIndex = if isNextAction { _selectedPageIndex + 1 } else { _selectedPageIndex - 1 } updateSelection() + DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) { [weak self] in + guard let self else { return } + UIAccessibility.post(notification: .announcement, argument: "Page \(self.selectedPage) of \(self.total) selected") + } } ///Refreshing the UI based on the selected page private func updateSelection() { guard _selectedPageIndex < total else { return } //Need to make selected page as second element so scrolling previous index of the selected page to left - collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) + collectionContainerView.collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) previousButton.isHidden = _selectedPageIndex == 0 nextButton.isHidden = _selectedPageIndex == total - 1 - collectionView.reloadData() + collectionContainerView.collectionView.reloadData() verifyIfMaxDigitChanged() } ///Identifying if there is any change in the digits of upcoming page - func verifyIfMaxDigitChanged() { + private func verifyIfMaxDigitChanged() { let upperLimitPage = _selectedPageIndex + flowLayout.maxNumberOfColumns let upperLimitDigits = upperLimitPage.digitCount //future value digits switch (flowLayout.numberOfColumns, upperLimitDigits) { @@ -163,9 +183,9 @@ open class Pagination: View { if upperLimitDigits != flowLayout.upperLimitDigits { flowLayout.upperLimitDigits = upperLimitDigits flowLayout.invalidateLayout() - collectionView.reloadData() + collectionContainerView.collectionView.reloadData() //Need to make selected page as second element so scrolling previous index of the selected page to left - collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) + collectionContainerView.collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) } } } diff --git a/VDS/Components/Pagination/PaginationCellItem.swift b/VDS/Components/Pagination/PaginationCellItem.swift index 68fa7271..68f51142 100644 --- a/VDS/Components/Pagination/PaginationCellItem.swift +++ b/VDS/Components/Pagination/PaginationCellItem.swift @@ -23,6 +23,7 @@ final class PaginationCellItem: UICollectionViewCell { private var indexLabel: Label = Label().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.textAlignment = .center + $0.isAccessibilityElement = false $0.numberOfLines = 1 } diff --git a/VDS/Components/Pagination/PaginationCollectionView.swift b/VDS/Components/Pagination/PaginationCollectionView.swift new file mode 100644 index 00000000..a41c65ef --- /dev/null +++ b/VDS/Components/Pagination/PaginationCollectionView.swift @@ -0,0 +1,66 @@ +// +// PaginationCollectionView.swift +// VDS +// +// Created by Bandaru, Krishna Kishore on 12/03/24. +// + +import UIKit + +///PaginationCollectionView is a container view that holds collectionview for displaying page indexes +final class PaginationCollectionView: View { + + //-------------------------------------------------- + // MARK: - Internal Properties + //-------------------------------------------------- + ///Notifies when accessibility increment is happend when user swipes up + var onAccessibilityIncrement: (() -> Void)? + ///Notifies when accessibility decrement is happend when user swipes down + var onAccessibilityDecrement: (() -> Void)? + ///Collectionview to render pagination indexes + lazy var collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) + collectionView.isScrollEnabled = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.showsHorizontalScrollIndicator = false + collectionView.showsVerticalScrollIndicator = false + collectionView.isAccessibilityElement = true + collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier) + collectionView.backgroundColor = .clear + return collectionView + }() + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + ///Custom flow layout defined for the Pagination + private let flowLayout = PaginationFlowLayout() + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + ///Accessibilty traits for the Pagination view + override var accessibilityTraits: UIAccessibilityTraits { + get { [.adjustable] } + set { } + } + + ///Accessibilty increment + override func accessibilityIncrement() { + onAccessibilityIncrement?() + } + + ///Accessibilty decrement + override func accessibilityDecrement() { + onAccessibilityDecrement?() + } + + /// Executed on initialization for this View. + override func setup() { + super.setup() + addSubview(collectionView) + collectionView.pinToSuperView() + isAccessibilityElement = true + accessibilityElements = [collectionView] + } +} From 7b6334f28d7a1fd5a381ff66f73c60729bdfc3b7 Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 13 Mar 2024 07:24:27 +0530 Subject: [PATCH 07/31] Digital ACT-191 ONEAPP-6827 story: added new breadcrumbItem component --- VDS.xcodeproj/project.pbxproj | 20 +++ .../Breadcrumbs/BreadcrumbCellItem.swift | 17 +++ .../Breadcrumbs/BreadcrumbItem.swift | 125 ++++++++++++++++++ VDS/Components/Breadcrumbs/Breadcrumbs.swift | 18 +++ 4 files changed, 180 insertions(+) create mode 100644 VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift create mode 100644 VDS/Components/Breadcrumbs/BreadcrumbItem.swift create mode 100644 VDS/Components/Breadcrumbs/Breadcrumbs.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 366fca71..66ac0ba3 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -7,8 +7,11 @@ objects = { /* Begin PBXBuildFile section */ + 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; 186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; + 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; + 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; @@ -175,8 +178,11 @@ /* End PBXContainerItemProxy section */ /* Begin PBXFileReference section */ + 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = ""; }; 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; + 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; + 18A65A032B96F050006602CC /* BreadcrumbItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItem.swift; sourceTree = ""; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; 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 = ""; }; @@ -356,6 +362,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 18A65A002B96E7E1006602CC /* Breadcrumbs */ = { + isa = PBXGroup; + children = ( + 18A65A012B96E848006602CC /* Breadcrumbs.swift */, + 18A65A032B96F050006602CC /* BreadcrumbItem.swift */, + 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */, + ); + path = Breadcrumbs; + sourceTree = ""; + }; 445BA07629C07ABA0036A7C5 /* Notification */ = { isa = PBXGroup; children = ( @@ -489,6 +505,7 @@ children = ( EA4DB2FE28DCBC1900103EE3 /* Badge */, EAD062AE2A3B87210015965D /* BadgeIndicator */, + 18A65A002B96E7E1006602CC /* Breadcrumbs */, EA0FC2BE2912D18200DF80B4 /* Buttons */, EAF7F092289985E200B287F5 /* Checkbox */, EA985BF3296C609E00F2FF2E /* Icon */, @@ -994,10 +1011,12 @@ EAF7F0A6289B0CE000B287F5 /* Resetable.swift in Sources */, EA985C2D296F03FE00F2FF2E /* TileletIconModels.swift in Sources */, EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */, + 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */, EA0D1C3F2A6AD5E200E5C127 /* Typography+ContentSizeCategory.swift in Sources */, EA5F86C82A1BD99100BC83E4 /* TabModel.swift in Sources */, EA0D1C432A6AD70900E5C127 /* VDSTypography.swift in Sources */, EA297A5729FB0A360031ED56 /* AppleGuidelinesTouchable.swift in Sources */, + 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */, EA3361C328902D960071C351 /* Toggle.swift in Sources */, EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */, EA89201328B568D8006B9984 /* RadioBoxItem.swift in Sources */, @@ -1005,6 +1024,7 @@ EA3362402892EF6C0071C351 /* Label.swift in Sources */, EAB2376229E9880400AABE9A /* TrailingTooltipLabel.swift in Sources */, EAB2376A29E9E59100AABE9A /* TooltipLaunchable.swift in Sources */, + 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */, EAB2375D29E8789100AABE9A /* Tooltip.swift in Sources */, 71BFA70A2B7F70E6000DCE33 /* Dropshadowable.swift in Sources */, EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */, diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift new file mode 100644 index 00000000..5bb6b03a --- /dev/null +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -0,0 +1,17 @@ +// +// BreadcrumbCellItem.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 11/03/24. +// + +import UIKit +import VDSColorTokens + +///This is customised view for Breadcrumb cell item +final class BreadcrumbCellItem: UICollectionViewCell { + + ///Identifier for the PaginationCellItem + static let identifier: String = String(describing: BreadcrumbCellItem.self) + +} diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift new file mode 100644 index 00000000..ac8951cb --- /dev/null +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -0,0 +1,125 @@ +// +// BreadcrumbItem.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 05/03/24. +// + +import Foundation +import VDSColorTokens +import VDSFormControlsTokens +import Combine + +/// A Breadcrumb Item contains href(link) and selected flag. +/// Breadcrumb links to its respective page if it is not disabled. +/// Breadcrumb contains text with a separator by default, highlights text in bold without a separator if selected. +@objc (VDSBreadcrumbItem) +open class BreadcrumbItem: ButtonBase { + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// The Breadcrumb link to links to its respective page. + open var link: String? { didSet { setNeedsUpdate() } } + + /// TextStyle used on the titleLabel. + open override var textStyle: TextStyle { isSelected ? TextStyle.boldBodySmall : TextStyle.bodySmall } + + /// If true, it will be rendered as selected. + open var selectable: Bool = false { + didSet { + //update selected state + if selectable{ + isSelected = true + } else { + isSelected = false + } + setNeedsUpdate() + } + } + + /// UIColor used on the titleLabel text. + open override var textColor: UIColor { + textColorConfiguration.getColor(self) + } + + /// The natural size for the receiving view, considering only properties of the view itself. + open override var intrinsicContentSize: CGSize { + return titleLabel?.intrinsicContentSize ?? super.intrinsicContentSize + } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + var separator = " /" + + private var textColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + } + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. + open override func setup() { + super.setup() + isAccessibilityElement = true + accessibilityTraits = .button + accessibilityLabel = "Breadcrumb" + } + + /// Used to make changes to the View based off a change events or from local properties. + open override func updateView() { + //always call last so the label is rendered + if (text != nil) { + var newText: String = text ?? "" + if isSelected { + if newText.contains(separator) { + let result = newText.dropLast(2) + newText = String(result) + } + } else { + if !newText.contains(separator) { + newText = (text ?? "") + separator + } + } + print("newText:\(newText), isSelected: \(isSelected)") + text = newText + if let titleLabel { + titleLabel.text = text + } + } + super.updateView() + + } + + /// Resets to default settings. + open override func reset() { + super.reset() + shouldUpdateView = false + text = nil + link = nil + accessibilityCustomActions = [] + isAccessibilityElement = true + accessibilityTraits = .button + shouldUpdateView = true + setNeedsUpdate() + } +} diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift new file mode 100644 index 00000000..a8269ac9 --- /dev/null +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -0,0 +1,18 @@ +// +// Breadcrumbs.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 11/03/24. +// + +import Foundation +import VDSColorTokens +import Combine + +/// A Breadcrumbs contains BreadcrumbItems. +/// It contains Breadcrumb Item Default, Breadcrumb Item Selected, Separator. +/// Breadcrumbs are secondary navigation that use a hierarchy of internal links to tell customers where they are in an experience. Each breadcrumb links to its respective page, except for that of current page. +@objc(VDSBreadcrumbs) +open class Breadcrumbs: View { + +} From 28e9f79f40e9cd10c75b45423a3513b05b0473b0 Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 13 Mar 2024 07:33:36 +0530 Subject: [PATCH 08/31] Digital ACT-191 ONEAPP-6827 story: added Breadcrumbs in VDS.md --- VDS/VDS.docc/VDS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/VDS.docc/VDS.md b/VDS/VDS.docc/VDS.md index 8beb9255..6b6dbeb6 100755 --- a/VDS/VDS.docc/VDS.md +++ b/VDS/VDS.docc/VDS.md @@ -21,6 +21,7 @@ Using the system allows designers and developers to collaborate more easily and ### Components - ``Badge`` - ``BadgeIndicator`` +- ``Breadcrumbs`` - ``Button`` - ``ButtonIcon`` - ``ButtonGroup`` From 4cc1d5287d70815089dfdbf238946d2ceb0a63ac Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Wed, 13 Mar 2024 12:59:05 +0530 Subject: [PATCH 09/31] updated cell size for 3 & 4 digits --- VDS/Components/Pagination/PaginationFlowLayout.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/VDS/Components/Pagination/PaginationFlowLayout.swift b/VDS/Components/Pagination/PaginationFlowLayout.swift index 89debfe2..542e4eff 100644 --- a/VDS/Components/Pagination/PaginationFlowLayout.swift +++ b/VDS/Components/Pagination/PaginationFlowLayout.swift @@ -18,8 +18,7 @@ final class PaginationFlowLayout : UICollectionViewLayout { ///Pre-defined sizes of the pagination cell based on number of digits. private var upperLimitSize: CGSize { switch upperLimitDigits { - case 3: .init(width: 28, height: 16) - case 4: .init(width: 34, height: 16) + case 3, 4: .init(width: 34, height: 16) default: .init(width: 20, height: 16) } } From 663b1b1fede334e29432a5c02e882a6f2115ecc6 Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 13 Mar 2024 16:41:21 +0530 Subject: [PATCH 10/31] Digital ACT-191 ONEAPP-6827 story: added Breadcrumbs change log, modified BreadcrumbCellItem --- VDS.xcodeproj/project.pbxproj | 4 + .../Breadcrumbs/BreadcrumbCellItem.swift | 68 +++++++++++++- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 94 +++++++++++++++++++ .../Breadcrumbs/BreadcrumbsChangeLog.txt | 36 +++++++ 4 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 VDS/Components/Breadcrumbs/BreadcrumbsChangeLog.txt diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 66ac0ba3..c86f3116 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; + 18450CF12BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */; }; 186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; @@ -179,6 +180,7 @@ /* Begin PBXFileReference section */ 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = ""; }; + 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BreadcrumbsChangeLog.txt; sourceTree = ""; }; 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; @@ -368,6 +370,7 @@ 18A65A012B96E848006602CC /* Breadcrumbs.swift */, 18A65A032B96F050006602CC /* BreadcrumbItem.swift */, 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */, + 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */, ); path = Breadcrumbs; sourceTree = ""; @@ -982,6 +985,7 @@ 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */, EA3362062891E14D0071C351 /* VerizonNHGeTX-Regular.otf in Resources */, EA3362052891E14D0071C351 /* VerizonNHGeDS-Bold.otf in Resources */, + 18450CF12BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt in Resources */, EAEEECA02B1F908200531FC2 /* BadgeIndicatorChangeLog.txt in Resources */, EAA5EEB928ECD24B003B3210 /* Icons.xcassets in Resources */, EAEEECA92B1F969700531FC2 /* TooltipChangeLog.txt in Resources */, diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 5bb6b03a..91cd9945 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -11,7 +11,73 @@ import VDSColorTokens ///This is customised view for Breadcrumb cell item final class BreadcrumbCellItem: UICollectionViewCell { - ///Identifier for the PaginationCellItem + ///Identifier for the BreadcrumbCellItem static let identifier: String = String(describing: BreadcrumbCellItem.self) + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + + internal var stackView: UIStackView = { + return UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.axis = .horizontal + $0.distribution = .fill + $0.alignment = .top + } + }() + + internal var breadcrumb = BreadcrumbItem().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.titleLabel?.numberOfLines = 0 + } + + ///separator label + private var separator: Label = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .left + $0.numberOfLines = 0 + $0.text = "/" + } + + private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + override init(frame: CGRect) { + super.init(frame: frame) + setUp() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setUp() + } + + ///Configuring the cell with default setup + private func setUp() { + //add stackview + //this is the horizontal stack that contains breadcrumb and separator + stackView.addArrangedSubview(breadcrumb) + stackView.addArrangedSubview(separator) + stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadcrumb) + stackView + .pinTop() + .pinLeading() + .pinTrailing(0, .defaultHigh) + .pinBottom(0, .defaultHigh) + contentView.addSubview(stackView) + separator.backgroundColor = .clear + + stackView.backgroundColor = .red + breadcrumb.backgroundColor = .green + separator.backgroundColor = .yellow + } + + ///Updating UI based on selected index, current index along with surface + func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface, showSlash: Bool) { + separator.textColor = textColorConfiguration.getColor(surface) + separator.isHidden = showSlash + } } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index a8269ac9..4777d3c6 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -15,4 +15,98 @@ import Combine @objc(VDSBreadcrumbs) open class Breadcrumbs: View { + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + ///Collectionview width anchor + private var collectionViewWidthAnchor: NSLayoutConstraint? + ///Selected page index + private var _selectedPageIndex: Int = 0 + ///A root view for the Breadcrumbs + private let containerView: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + } + + let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() + + ///Collectionview to render Breadcrumbs indexes + private lazy var collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + layout.itemSize = CGSize(width: 50, height: 25) + layout.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value + collectionView.isScrollEnabled = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.delegate = self + collectionView.dataSource = self + collectionView.showsHorizontalScrollIndicator = false + collectionView.showsVerticalScrollIndicator = false + collectionView.register(BreadcrumbCellItem.self, forCellWithReuseIdentifier: BreadcrumbCellItem.identifier) + collectionView.backgroundColor = .clear + return collectionView + }() + + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- +// /// Array of Breadcrumb Items Titles that are shown as Breadcrumbs. +// open var breadcrumbs: [String?] = [] { didSet { setNeedsUpdate() } } + + /// Array of Breadcrumb Items that are shown in the group. + open var breadcrumbItems: [ButtonBase] = [] { didSet { setNeedsUpdate() } } + + /// Whether this object is enabled or not + open var selected: Bool = false { didSet { setNeedsUpdate() } } + + /// Current Surface and this is used to pass down to child objects that implement Surfacable + override open var surface: Surface { + didSet { + breadcrumbItems.forEach { $0.surface = surface } + } + } + + //-------------------------------------------------- + // MARK: - Overrides + //-------------------------------------------------- + /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. + open override func setup() { + super.setup() + } + + /// Executed on initialization for this View. + open override func initialSetup() { + super.initialSetup() + } + + /// Resets to default settings. + open override func reset() { + super.reset() + setNeedsUpdate() + } + + /// Used to make changes to the View based off a change events or from local properties. + open override func updateView() { + super.updateView() + } +} + +extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + //-------------------------------------------------- + // MARK: - UICollectionView Delegate & Datasource + //-------------------------------------------------- + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { breadcrumbItems.count } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } + + var showSlash = (indexPath.row == (breadcrumbItems.count - 1)) + cell.update(_selectedPageIndex, currentIndex: indexPath.row, surface: surface, showSlash: showSlash) + return cell + } + + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { +// _selectedPageIndex = indexPath.row +// updateSelection() +// onPageDidSelect?(selectedPage) + } } diff --git a/VDS/Components/Breadcrumbs/BreadcrumbsChangeLog.txt b/VDS/Components/Breadcrumbs/BreadcrumbsChangeLog.txt new file mode 100644 index 00000000..3fae7754 --- /dev/null +++ b/VDS/Components/Breadcrumbs/BreadcrumbsChangeLog.txt @@ -0,0 +1,36 @@ +MM/DD/YYYY +---------------- +- Initial Brand 3.0 handoff + +12/17/2021 +---------------- +- Replaced focusring colors (previously interactive/onlight/ondark) with accessibility/onlight/ondark colors +- Updated focus border name (previously interactive.focusring.onlight) with focusring.onlight/ondark + +2/28/2022 +---------------- +- Changed Last Breadcrumb Item to Selected Item + +03/08/2022 +---------------- +- Added dev note for Active and Hover states. + +08/04/2022 +---------------- +- Updated default and inverted prop to light and dark surface. + +11/30/2022 +---------------- +- Added "(web only)" to any instance of "keyboard focus" + +12/13/2022 +---------------- +- Replaced focus border pixel and style & spacing values with tokens. + +01/03/2022 +---------------- +- Updated Specs to use new SPEC Templates and SPEC DOC Components. + +01/06/2023 +---------------- +- Tweaked anatomy element naming to align with design doc and dev doc From f25e9af766b216724ae882c8fb27a4e9c3252d6f Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 13 Mar 2024 17:50:19 +0530 Subject: [PATCH 11/31] Digital ACT-191 ONEAPP-6827 story: minor changes to see form fields --- VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift | 7 +++---- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 9 ++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 91cd9945..74e35961 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -17,7 +17,6 @@ final class BreadcrumbCellItem: UICollectionViewCell { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var stackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -70,9 +69,9 @@ final class BreadcrumbCellItem: UICollectionViewCell { contentView.addSubview(stackView) separator.backgroundColor = .clear - stackView.backgroundColor = .red - breadcrumb.backgroundColor = .green - separator.backgroundColor = .yellow +// stackView.backgroundColor = .red +// breadcrumb.backgroundColor = .green +// separator.backgroundColor = .yellow } ///Updating UI based on selected index, current index along with surface diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 4777d3c6..cfef9936 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -76,6 +76,13 @@ open class Breadcrumbs: View { /// Executed on initialization for this View. open override func initialSetup() { super.initialSetup() + + addSubview(containerView) + containerView.pinToSuperView() + //for TEST + containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 288).activate() + containerView.heightAnchor.constraint(equalToConstant: 150).activate() + containerView.addSubview(collectionView) } /// Resets to default settings. @@ -99,7 +106,7 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, UIC public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } - var showSlash = (indexPath.row == (breadcrumbItems.count - 1)) + let showSlash = (indexPath.row == (breadcrumbItems.count - 1)) cell.update(_selectedPageIndex, currentIndex: indexPath.row, surface: surface, showSlash: showSlash) return cell } From 9c8437fe6c1dc482fad0419716f611a47d952fb2 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Wed, 13 Mar 2024 22:28:52 +0530 Subject: [PATCH 12/31] Fixed layout issues --- VDS.xcodeproj/project.pbxproj | 8 +-- VDS/Components/Pagination/Pagination.swift | 62 ++++++++++++------- ...ew.swift => PaginationContainerView.swift} | 25 +------- .../Pagination/PaginationFlowLayout.swift | 5 +- 4 files changed, 48 insertions(+), 52 deletions(-) rename VDS/Components/Pagination/{PaginationCollectionView.swift => PaginationContainerView.swift} (52%) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 38a79f1e..f57edb0f 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; - 71ACE89C2BA0451200FB6ADC /* PaginationCollectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */; }; + 71ACE89C2BA0451200FB6ADC /* PaginationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationContainerView.swift */; }; 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; }; 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; @@ -193,7 +193,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; - 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationCollectionView.swift; sourceTree = ""; }; + 71ACE89B2BA0451200FB6ADC /* PaginationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainerView.swift; sourceTree = ""; }; 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = ""; }; 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; @@ -406,7 +406,7 @@ isa = PBXGroup; children = ( 71B23C2C2B91FA690027F7D9 /* Pagination.swift */, - 71ACE89B2BA0451200FB6ADC /* PaginationCollectionView.swift */, + 71ACE89B2BA0451200FB6ADC /* PaginationContainerView.swift */, 71FC86D92B96F44C00700965 /* PaginationButton.swift */, 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */, 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */, @@ -1059,7 +1059,7 @@ EAC925842911C63100091998 /* Colorable.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */, - 71ACE89C2BA0451200FB6ADC /* PaginationCollectionView.swift in Sources */, + 71ACE89C2BA0451200FB6ADC /* PaginationContainerView.swift in Sources */, EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */, EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 754935b7..7728d6dc 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -16,21 +16,36 @@ open class Pagination: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + ///Maximum component width + private let maxWidth: CGFloat = 288.0 ///Collectionview width anchor private var collectionViewWidthAnchor: NSLayoutConstraint? + ///Collectionview container Center X constraint + private var collectionContainerViewCenterXConstraint: NSLayoutConstraint? ///Selected page index private var _selectedPageIndex: Int = 0 ///Custom flow layout defined for the Pagination - private var flowLayout: PaginationFlowLayout { - guard let flowLayout = collectionContainerView.collectionView.collectionViewLayout as? PaginationFlowLayout else { fatalError("Flow layout should be PaginationFlowLayout class") } - return flowLayout - } + private let flowLayout = PaginationFlowLayout() ///A root view for the pagination - private let containerView: View = View().with { + public let containerView: View = View().with { $0.translatesAutoresizingMaskIntoConstraints = false } - ///Container view to hold collectionview to render pagination indexes - private let collectionContainerView = PaginationCollectionView() + ///Collectionview to render pagination indexes + private lazy var collectionView: UICollectionView = { + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) + collectionView.isScrollEnabled = false + collectionView.translatesAutoresizingMaskIntoConstraints = false + collectionView.showsHorizontalScrollIndicator = false + collectionView.showsVerticalScrollIndicator = false + collectionView.isAccessibilityElement = true + collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier) + collectionView.backgroundColor = .clear + collectionView.delegate = self + collectionView.dataSource = self + return collectionView + }() + ///Container view to hold collectionview to render pagination indexes and to handler accessibility. + private let collectionContainerView = PaginationContainerView() //-------------------------------------------------- // MARK: - Public Properties @@ -84,26 +99,27 @@ open class Pagination: View { containerView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor).activate() trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor).activate() containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() - containerView.widthAnchor.constraint(equalToConstant: 288).activate() + containerView.widthAnchor.constraint(equalToConstant: maxWidth).activate() containerView.heightAnchor.constraint(equalToConstant: 44).activate() containerView.addSubview(previousButton) containerView.addSubview(collectionContainerView) containerView.addSubview(nextButton) - + collectionContainerView.addSubview(collectionView) previousButton .pinTop() .pinBottom() .pinLeading() previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionContainerView.leadingAnchor).activate() - collectionContainerView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate() - collectionContainerView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() - collectionContainerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() collectionContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate() - collectionViewWidthAnchor = collectionContainerView.widthAnchor.constraint(equalToConstant: 92) + collectionContainerView + .pinTop() + .pinBottom() + collectionView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate() + collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() + collectionView.centerXAnchor.constraint(equalTo: collectionContainerView.centerXAnchor).activate() + collectionViewWidthAnchor = collectionView.widthAnchor.constraint(equalToConstant: 92) collectionViewWidthAnchor?.activate() - collectionContainerView.collectionView.delegate = self - collectionContainerView.collectionView.dataSource = self nextButton .pinTop() @@ -142,7 +158,7 @@ open class Pagination: View { super.updateView() nextButton.surface = surface previousButton.surface = surface - collectionContainerView.collectionView.reloadData() + collectionView.reloadData() } //-------------------------------------------------- @@ -163,10 +179,10 @@ open class Pagination: View { private func updateSelection() { guard _selectedPageIndex < total else { return } //Need to make selected page as second element so scrolling previous index of the selected page to left - collectionContainerView.collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) + collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) previousButton.isHidden = _selectedPageIndex == 0 nextButton.isHidden = _selectedPageIndex == total - 1 - collectionContainerView.collectionView.reloadData() + collectionView.reloadData() verifyIfMaxDigitChanged() } @@ -175,17 +191,17 @@ open class Pagination: View { let upperLimitPage = _selectedPageIndex + flowLayout.maxNumberOfColumns let upperLimitDigits = upperLimitPage.digitCount //future value digits switch (flowLayout.numberOfColumns, upperLimitDigits) { - case (_, 3), (_, 4): - flowLayout.numberOfColumns = 3 - default: + case (_, 1), (_, 2): flowLayout.numberOfColumns = 4 + default: + flowLayout.numberOfColumns = 3 } if upperLimitDigits != flowLayout.upperLimitDigits { flowLayout.upperLimitDigits = upperLimitDigits flowLayout.invalidateLayout() - collectionContainerView.collectionView.reloadData() + collectionView.reloadData() //Need to make selected page as second element so scrolling previous index of the selected page to left - collectionContainerView.collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) + collectionView.scrollToItem(at: IndexPath(row: max(_selectedPageIndex - 1, 0), section: 0), at: .left, animated: false) } } } diff --git a/VDS/Components/Pagination/PaginationCollectionView.swift b/VDS/Components/Pagination/PaginationContainerView.swift similarity index 52% rename from VDS/Components/Pagination/PaginationCollectionView.swift rename to VDS/Components/Pagination/PaginationContainerView.swift index a41c65ef..b79a2fe2 100644 --- a/VDS/Components/Pagination/PaginationCollectionView.swift +++ b/VDS/Components/Pagination/PaginationContainerView.swift @@ -1,5 +1,5 @@ // -// PaginationCollectionView.swift +// PaginationContainerView.swift // VDS // // Created by Bandaru, Krishna Kishore on 12/03/24. @@ -8,7 +8,7 @@ import UIKit ///PaginationCollectionView is a container view that holds collectionview for displaying page indexes -final class PaginationCollectionView: View { +final class PaginationContainerView: View { //-------------------------------------------------- // MARK: - Internal Properties @@ -17,24 +17,6 @@ final class PaginationCollectionView: View { var onAccessibilityIncrement: (() -> Void)? ///Notifies when accessibility decrement is happend when user swipes down var onAccessibilityDecrement: (() -> Void)? - ///Collectionview to render pagination indexes - lazy var collectionView: UICollectionView = { - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout) - collectionView.isScrollEnabled = false - collectionView.translatesAutoresizingMaskIntoConstraints = false - collectionView.showsHorizontalScrollIndicator = false - collectionView.showsVerticalScrollIndicator = false - collectionView.isAccessibilityElement = true - collectionView.register(PaginationCellItem.self, forCellWithReuseIdentifier: PaginationCellItem.identifier) - collectionView.backgroundColor = .clear - return collectionView - }() - - //-------------------------------------------------- - // MARK: - Private Properties - //-------------------------------------------------- - ///Custom flow layout defined for the Pagination - private let flowLayout = PaginationFlowLayout() //-------------------------------------------------- // MARK: - Overrides @@ -58,9 +40,6 @@ final class PaginationCollectionView: View { /// Executed on initialization for this View. override func setup() { super.setup() - addSubview(collectionView) - collectionView.pinToSuperView() isAccessibilityElement = true - accessibilityElements = [collectionView] } } diff --git a/VDS/Components/Pagination/PaginationFlowLayout.swift b/VDS/Components/Pagination/PaginationFlowLayout.swift index 542e4eff..c6bd02c3 100644 --- a/VDS/Components/Pagination/PaginationFlowLayout.swift +++ b/VDS/Components/Pagination/PaginationFlowLayout.swift @@ -18,8 +18,9 @@ final class PaginationFlowLayout : UICollectionViewLayout { ///Pre-defined sizes of the pagination cell based on number of digits. private var upperLimitSize: CGSize { switch upperLimitDigits { - case 3, 4: .init(width: 34, height: 16) - default: .init(width: 20, height: 16) + case 1, 2: .init(width: 20, height: 16) + case 3: .init(width: 28, height: 16) + default: .init(width: 34, height: 16) } } ///Property to store the defined layout attributes. From 812fac5a597be52e41f13cbb71b797f317ece61b Mon Sep 17 00:00:00 2001 From: vasavk Date: Thu, 14 Mar 2024 12:15:36 +0530 Subject: [PATCH 13/31] Digital ACT-191 ONEAPP-6827 story: updating cell data --- .../Breadcrumbs/BreadcrumbCellItem.swift | 41 ++++++++++------ .../Breadcrumbs/BreadcrumbItem.swift | 36 +++++++------- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 48 ++++++++----------- 3 files changed, 64 insertions(+), 61 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 74e35961..c5175001 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -13,16 +13,28 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Identifier for the BreadcrumbCellItem static let identifier: String = String(describing: BreadcrumbCellItem.self) - + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + internal var crumbWidthConstraint: NSLayoutConstraint? + + var crumb : BreadcrumbItem? { + didSet { + guard let crumb = crumb else { return } + breadcrumb = crumb + crumbWidthConstraint?.constant = crumb.intrinsicContentSize.width + crumbWidthConstraint?.isActive = true + } + } + internal var stackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal $0.distribution = .fill $0.alignment = .top + $0.spacing = VDSLayout.Spacing.space1X.value } }() @@ -41,6 +53,12 @@ final class BreadcrumbCellItem: UICollectionViewCell { private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + private var crumbTextColorConfiguration = ControlColorConfiguration().with { + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) + $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) + } + //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -56,27 +74,22 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Configuring the cell with default setup private func setUp() { - //add stackview - //this is the horizontal stack that contains breadcrumb and separator + //add stackview - this is the horizontal stack that contains breadcrumb and separator stackView.addArrangedSubview(breadcrumb) + crumbWidthConstraint = breadcrumb.widthAnchor.constraint(greaterThanOrEqualToConstant: 0).activate() stackView.addArrangedSubview(separator) stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadcrumb) - stackView - .pinTop() - .pinLeading() - .pinTrailing(0, .defaultHigh) - .pinBottom(0, .defaultHigh) + stackView.pinToSuperView() contentView.addSubview(stackView) separator.backgroundColor = .clear - -// stackView.backgroundColor = .red -// breadcrumb.backgroundColor = .green -// separator.backgroundColor = .yellow } ///Updating UI based on selected index, current index along with surface - func update(_ selectedIndex: Int, currentIndex: Int, surface: Surface, showSlash: Bool) { + func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { + breadcrumb = breadCrumbItem + breadcrumb.text = breadCrumbItem.text separator.textColor = textColorConfiguration.getColor(surface) - separator.isHidden = showSlash + separator.isHidden = hideSlash + print("selected: \(breadcrumb.isSelected), hideSlash: \(hideSlash), text: \(String(describing: breadCrumbItem.text)))") } } diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index ac8951cb..a5972496 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -88,24 +88,24 @@ open class BreadcrumbItem: ButtonBase { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { //always call last so the label is rendered - if (text != nil) { - var newText: String = text ?? "" - if isSelected { - if newText.contains(separator) { - let result = newText.dropLast(2) - newText = String(result) - } - } else { - if !newText.contains(separator) { - newText = (text ?? "") + separator - } - } - print("newText:\(newText), isSelected: \(isSelected)") - text = newText - if let titleLabel { - titleLabel.text = text - } - } +// if (text != nil) { +// var newText: String = text ?? "" +// if isSelected { +// if newText.contains(separator) { +// let result = newText.dropLast(2) +// newText = String(result) +// } +// } else { +// if !newText.contains(separator) { +// newText = (text ?? "") + separator +// } +// } +// print("newText:\(newText), isSelected: \(isSelected)") +// text = newText +// if let titleLabel { +// titleLabel.text = text +// } +// } super.updateView() } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index cfef9936..d6325629 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -18,21 +18,11 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - ///Collectionview width anchor - private var collectionViewWidthAnchor: NSLayoutConstraint? - ///Selected page index - private var _selectedPageIndex: Int = 0 - ///A root view for the Breadcrumbs - private let containerView: View = View().with { - $0.translatesAutoresizingMaskIntoConstraints = false - } - let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() ///Collectionview to render Breadcrumbs indexes private lazy var collectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - layout.itemSize = CGSize(width: 50, height: 25) layout.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value collectionView.isScrollEnabled = false collectionView.translatesAutoresizingMaskIntoConstraints = false @@ -49,15 +39,15 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- -// /// Array of Breadcrumb Items Titles that are shown as Breadcrumbs. -// open var breadcrumbs: [String?] = [] { didSet { setNeedsUpdate() } } - /// Array of Breadcrumb Items that are shown in the group. open var breadcrumbItems: [ButtonBase] = [] { didSet { setNeedsUpdate() } } /// Whether this object is enabled or not - open var selected: Bool = false { didSet { setNeedsUpdate() } } - + override open var isEnabled: Bool { + didSet { + breadcrumbItems.forEach { $0.isEnabled = isEnabled } + } + } /// Current Surface and this is used to pass down to child objects that implement Surfacable override open var surface: Surface { didSet { @@ -76,13 +66,9 @@ open class Breadcrumbs: View { /// Executed on initialization for this View. open override func initialSetup() { super.initialSetup() - - addSubview(containerView) - containerView.pinToSuperView() - //for TEST - containerView.widthAnchor.constraint(greaterThanOrEqualToConstant: 288).activate() - containerView.heightAnchor.constraint(equalToConstant: 150).activate() - containerView.addSubview(collectionView) + addSubview(collectionView) + collectionView.pinToSuperView() + collectionView.heightAnchor.constraint(equalToConstant: 100).activate() } /// Resets to default settings. @@ -94,6 +80,7 @@ open class Breadcrumbs: View { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() + collectionView.reloadData() } } @@ -101,19 +88,22 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, UIC //-------------------------------------------------- // MARK: - UICollectionView Delegate & Datasource //-------------------------------------------------- - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { breadcrumbItems.count } + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { breadcrumbItems.count + } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } - - let showSlash = (indexPath.row == (breadcrumbItems.count - 1)) - cell.update(_selectedPageIndex, currentIndex: indexPath.row, surface: surface, showSlash: showSlash) + let breadcrumb : BreadcrumbItem = breadcrumbItems[indexPath.row] as! BreadcrumbItem + let hideSlash = (indexPath.row == (breadcrumbItems.count - 1)) + cell.crumb = breadcrumb + cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumb) return cell } + public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { + breadcrumbItems[indexPath.row].intrinsicContentSize + } + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { -// _selectedPageIndex = indexPath.row -// updateSelection() -// onPageDidSelect?(selectedPage) } } From a39e08871156b9bd853e00ad18f693884493d2c5 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Thu, 14 Mar 2024 13:02:32 +0530 Subject: [PATCH 14/31] Digital ACT-191 ONEAPP-6827 story: fixed layout issues --- .../Breadcrumbs/BreadcrumbCellItem.swift | 41 ++++++++++++------- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 18 ++++---- 2 files changed, 35 insertions(+), 24 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index c5175001..c9d66327 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -22,7 +22,7 @@ final class BreadcrumbCellItem: UICollectionViewCell { var crumb : BreadcrumbItem? { didSet { guard let crumb = crumb else { return } - breadcrumb = crumb + breadCrumbItem = crumb crumbWidthConstraint?.constant = crumb.intrinsicContentSize.width crumbWidthConstraint?.isActive = true } @@ -33,15 +33,12 @@ final class BreadcrumbCellItem: UICollectionViewCell { $0.translatesAutoresizingMaskIntoConstraints = false $0.axis = .horizontal $0.distribution = .fill - $0.alignment = .top + $0.alignment = .fill $0.spacing = VDSLayout.Spacing.space1X.value } }() - internal var breadcrumb = BreadcrumbItem().with { - $0.translatesAutoresizingMaskIntoConstraints = false - $0.titleLabel?.numberOfLines = 0 - } + internal var breadCrumbItem: BreadcrumbItem? ///separator label private var separator: Label = Label().with { @@ -74,22 +71,36 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Configuring the cell with default setup private func setUp() { - //add stackview - this is the horizontal stack that contains breadcrumb and separator - stackView.addArrangedSubview(breadcrumb) - crumbWidthConstraint = breadcrumb.widthAnchor.constraint(greaterThanOrEqualToConstant: 0).activate() - stackView.addArrangedSubview(separator) - stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadcrumb) - stackView.pinToSuperView() contentView.addSubview(stackView) + stackView.pinToSuperView() separator.backgroundColor = .clear } ///Updating UI based on selected index, current index along with surface func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { - breadcrumb = breadCrumbItem - breadcrumb.text = breadCrumbItem.text + stackView.removeAllArrangedSubviews() + stackView.addArrangedSubview(separator) + stackView.addArrangedSubview(breadCrumbItem) + stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadCrumbItem) separator.textColor = textColorConfiguration.getColor(surface) separator.isHidden = hideSlash - print("selected: \(breadcrumb.isSelected), hideSlash: \(hideSlash), text: \(String(describing: breadCrumbItem.text)))") + print("selected: \(breadCrumbItem.isSelected), hideSlash: \(hideSlash), text: \(String(describing: breadCrumbItem.text)))") + self.breadCrumbItem = breadCrumbItem + layoutIfNeeded() + } +} + +extension UIStackView { + + @discardableResult + func removeAllArrangedSubviews() -> [UIView] { + return arrangedSubviews.reduce([UIView]()) { $0 + [removeArrangedSubViewProperly($1)] } + } + + func removeArrangedSubViewProperly(_ view: UIView) -> UIView { + removeArrangedSubview(view) + NSLayoutConstraint.deactivate(view.constraints) + view.removeFromSuperview() + return view } } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index d6325629..cd48c012 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -18,12 +18,17 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout() + let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout().with { + $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + $0.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value + $0.minimumLineSpacing = VDSLayout.Spacing.space1X.value + $0.sectionInset = .zero + $0.scrollDirection = .vertical + } ///Collectionview to render Breadcrumbs indexes private lazy var collectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - layout.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value collectionView.isScrollEnabled = false collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.delegate = self @@ -84,7 +89,7 @@ open class Breadcrumbs: View { } } -extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { +extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { //-------------------------------------------------- // MARK: - UICollectionView Delegate & Datasource //-------------------------------------------------- @@ -94,16 +99,11 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource, UIC public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } let breadcrumb : BreadcrumbItem = breadcrumbItems[indexPath.row] as! BreadcrumbItem - let hideSlash = (indexPath.row == (breadcrumbItems.count - 1)) - cell.crumb = breadcrumb + let hideSlash = (indexPath.row == 0) cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumb) return cell } - public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { - breadcrumbItems[indexPath.row].intrinsicContentSize - } - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { } } From 2703112148b2631611e4eb2d7a9eecfb36a79847 Mon Sep 17 00:00:00 2001 From: vasavk Date: Thu, 14 Mar 2024 15:05:01 +0530 Subject: [PATCH 15/31] Digital ACT-191 ONEAPP-6827 story: removed unused and commented code --- .../Breadcrumbs/BreadcrumbCellItem.swift | 22 +--------- .../Breadcrumbs/BreadcrumbItem.swift | 20 --------- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 44 +++++++++---------- 3 files changed, 23 insertions(+), 63 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index c9d66327..84111e11 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -17,17 +17,6 @@ final class BreadcrumbCellItem: UICollectionViewCell { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - internal var crumbWidthConstraint: NSLayoutConstraint? - - var crumb : BreadcrumbItem? { - didSet { - guard let crumb = crumb else { return } - breadCrumbItem = crumb - crumbWidthConstraint?.constant = crumb.intrinsicContentSize.width - crumbWidthConstraint?.isActive = true - } - } - internal var stackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -50,12 +39,6 @@ final class BreadcrumbCellItem: UICollectionViewCell { private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) - private var crumbTextColorConfiguration = ControlColorConfiguration().with { - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) - $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) - $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) - } - //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -76,15 +59,14 @@ final class BreadcrumbCellItem: UICollectionViewCell { separator.backgroundColor = .clear } - ///Updating UI based on selected index, current index along with surface + ///Updating the breadCrumbItem and UI based on the selected flag along with the surface func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { stackView.removeAllArrangedSubviews() stackView.addArrangedSubview(separator) stackView.addArrangedSubview(breadCrumbItem) - stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadCrumbItem) + stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) separator.textColor = textColorConfiguration.getColor(surface) separator.isHidden = hideSlash - print("selected: \(breadCrumbItem.isSelected), hideSlash: \(hideSlash), text: \(String(describing: breadCrumbItem.text)))") self.breadCrumbItem = breadCrumbItem layoutIfNeeded() } diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index a5972496..856099b8 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -66,8 +66,6 @@ open class BreadcrumbItem: ButtonBase { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - var separator = " /" - private var textColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) @@ -88,24 +86,6 @@ open class BreadcrumbItem: ButtonBase { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { //always call last so the label is rendered -// if (text != nil) { -// var newText: String = text ?? "" -// if isSelected { -// if newText.contains(separator) { -// let result = newText.dropLast(2) -// newText = String(result) -// } -// } else { -// if !newText.contains(separator) { -// newText = (text ?? "") + separator -// } -// } -// print("newText:\(newText), isSelected: \(isSelected)") -// text = newText -// if let titleLabel { -// titleLabel.text = text -// } -// } super.updateView() } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index cd48c012..5a7e05d0 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -15,6 +15,25 @@ import Combine @objc(VDSBreadcrumbs) open class Breadcrumbs: View { + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + /// Array of Breadcrumb Items that are shown in the group. + open var breadcrumbItems: [BreadcrumbItem] = [] { didSet { setNeedsUpdate() } } + + /// Whether this object is enabled or not + override open var isEnabled: Bool { + didSet { + breadcrumbItems.forEach { $0.isEnabled = isEnabled } + } + } + /// Current Surface and this is used to pass down to child objects that implement Surfacable + override open var surface: Surface { + didSet { + breadcrumbItems.forEach { $0.surface = surface } + } + } + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -40,26 +59,6 @@ open class Breadcrumbs: View { return collectionView }() - - //-------------------------------------------------- - // MARK: - Public Properties - //-------------------------------------------------- - /// Array of Breadcrumb Items that are shown in the group. - open var breadcrumbItems: [ButtonBase] = [] { didSet { setNeedsUpdate() } } - - /// Whether this object is enabled or not - override open var isEnabled: Bool { - didSet { - breadcrumbItems.forEach { $0.isEnabled = isEnabled } - } - } - /// Current Surface and this is used to pass down to child objects that implement Surfacable - override open var surface: Surface { - didSet { - breadcrumbItems.forEach { $0.surface = surface } - } - } - //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- @@ -73,7 +72,7 @@ open class Breadcrumbs: View { super.initialSetup() addSubview(collectionView) collectionView.pinToSuperView() - collectionView.heightAnchor.constraint(equalToConstant: 100).activate() + collectionView.heightAnchor.constraint(equalToConstant: 80).activate() } /// Resets to default settings. @@ -98,9 +97,8 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } - let breadcrumb : BreadcrumbItem = breadcrumbItems[indexPath.row] as! BreadcrumbItem let hideSlash = (indexPath.row == 0) - cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumb) + cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumbItems[indexPath.row]) return cell } From 4c9c844b1d770b43aaac52bdf3167a3ec6d83f10 Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 19 Mar 2024 14:31:16 +0530 Subject: [PATCH 16/31] Digital ACT-191 ONEAPP-6827 story: alignment issue fix on surface change --- .../Breadcrumbs/BreadcrumbCellItem.swift | 37 ++++++++++++------- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 20 ++++++++-- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 84111e11..f8899577 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -33,7 +33,9 @@ final class BreadcrumbCellItem: UICollectionViewCell { private var separator: Label = Label().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.textAlignment = .left - $0.numberOfLines = 0 + $0.numberOfLines = 1 + $0.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal) + $0.setContentHuggingPriority(.defaultHigh, for: .horizontal) $0.text = "/" } @@ -54,6 +56,7 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Configuring the cell with default setup private func setUp() { + separator.textColorConfiguration = textColorConfiguration.eraseToAnyColorable() contentView.addSubview(stackView) stackView.pinToSuperView() separator.backgroundColor = .clear @@ -61,7 +64,8 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Updating the breadCrumbItem and UI based on the selected flag along with the surface func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { - stackView.removeAllArrangedSubviews() + separator.surface = surface + breadCrumbItem.surface = surface stackView.addArrangedSubview(separator) stackView.addArrangedSubview(breadCrumbItem) stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) @@ -72,17 +76,24 @@ final class BreadcrumbCellItem: UICollectionViewCell { } } -extension UIStackView { - - @discardableResult - func removeAllArrangedSubviews() -> [UIView] { - return arrangedSubviews.reduce([UIView]()) { $0 + [removeArrangedSubViewProperly($1)] } - } +class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout { - func removeArrangedSubViewProperly(_ view: UIView) -> UIView { - removeArrangedSubview(view) - NSLayoutConstraint.deactivate(view.constraints) - view.removeFromSuperview() - return view + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + let attributes = super.layoutAttributesForElements(in: rect) + + var leftMargin = sectionInset.left + var maxY: CGFloat = -1.0 + attributes?.forEach { layoutAttribute in + if layoutAttribute.frame.origin.y >= maxY { + leftMargin = sectionInset.left + } + + layoutAttribute.frame.origin.x = leftMargin + + leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing + maxY = max(layoutAttribute.frame.maxY , maxY) + } + + return attributes } } diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 5a7e05d0..b69e5ead 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -27,6 +27,7 @@ open class Breadcrumbs: View { breadcrumbItems.forEach { $0.isEnabled = isEnabled } } } + /// Current Surface and this is used to pass down to child objects that implement Surfacable override open var surface: Surface { didSet { @@ -37,7 +38,7 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout().with { + let layout: UICollectionViewFlowLayout = LeftAlignedCollectionViewFlowLayout().with { $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize $0.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value $0.minimumLineSpacing = VDSLayout.Spacing.space1X.value @@ -45,7 +46,7 @@ open class Breadcrumbs: View { $0.scrollDirection = .vertical } - ///Collectionview to render Breadcrumbs indexes + ///Collectionview to render Breadcrumb Items private lazy var collectionView: UICollectionView = { let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) collectionView.isScrollEnabled = false @@ -78,6 +79,9 @@ open class Breadcrumbs: View { /// Resets to default settings. open override func reset() { super.reset() + shouldUpdateView = false + breadcrumbItems.forEach { $0.reset() } + shouldUpdateView = true setNeedsUpdate() } @@ -86,6 +90,15 @@ open class Breadcrumbs: View { super.updateView() collectionView.reloadData() } + + open override func layoutSubviews() { + super.layoutSubviews() + // Accounts for any collection size changes + DispatchQueue.main.async { [weak self] in + guard let self else { return } + self.collectionView.collectionViewLayout.invalidateLayout() + } + } } extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { @@ -102,6 +115,7 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { return cell } - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { + breadcrumbItems[indexPath.row].intrinsicContentSize } } From 868c728f63a40b3a66eb38185b934154cefe9b88 Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 19 Mar 2024 17:33:19 +0530 Subject: [PATCH 17/31] Digital ACT-191 ONEAPP-6827 story: container size changes --- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index b69e5ead..94d6e6fe 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -38,6 +38,11 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- + // Sizes are from InVision design specs. + internal var containerSize: CGSize { CGSize(width: 45, height: 44) } + + internal var heightConstraint: NSLayoutConstraint? + let layout: UICollectionViewFlowLayout = LeftAlignedCollectionViewFlowLayout().with { $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize $0.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value @@ -60,12 +65,16 @@ open class Breadcrumbs: View { return collectionView }() - //-------------------------------------------------- + //------------------------------------------s-------- // MARK: - Overrides //-------------------------------------------------- /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. open override func setup() { super.setup() + //create the wrapping view + heightConstraint = self.heightAnchor.constraint(equalToConstant: containerSize.height) + heightConstraint?.priority = .defaultHigh + heightConstraint?.isActive = true } /// Executed on initialization for this View. @@ -73,7 +82,6 @@ open class Breadcrumbs: View { super.initialSetup() addSubview(collectionView) collectionView.pinToSuperView() - collectionView.heightAnchor.constraint(equalToConstant: 80).activate() } /// Resets to default settings. @@ -89,6 +97,8 @@ open class Breadcrumbs: View { open override func updateView() { super.updateView() collectionView.reloadData() + heightConstraint?.constant = collectionView.collectionViewLayout.collectionViewContentSize.height + heightConstraint?.isActive = true } open override func layoutSubviews() { From 86e91c3ac7398ff4ed92abecc6b04f7c9c18c865 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Wed, 20 Mar 2024 16:50:47 +0530 Subject: [PATCH 18/31] Added Center X & Y constraints and modified code based on constraints --- VDS/Components/Pagination/Pagination.swift | 38 +++-- .../Pagination/PaginationCellItem.swift | 2 +- VDS/Protocols/LayoutConstraintable.swift | 152 ++++++++++++++++++ 3 files changed, 174 insertions(+), 18 deletions(-) diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 7728d6dc..72cb3224 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -92,34 +92,38 @@ open class Pagination: View { open override func initialSetup() { super.initialSetup() - addSubview(containerView) - containerView - .pinTop() - .pinBottom() - containerView.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor).activate() - trailingAnchor.constraint(greaterThanOrEqualTo: containerView.trailingAnchor).activate() - containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() - containerView.widthAnchor.constraint(equalToConstant: maxWidth).activate() - containerView.heightAnchor.constraint(equalToConstant: 44).activate() + collectionContainerView.addSubview(collectionView) containerView.addSubview(previousButton) containerView.addSubview(collectionContainerView) containerView.addSubview(nextButton) - collectionContainerView.addSubview(collectionView) + addSubview(containerView) + + containerView + .pinTop() + .pinBottom() + .pinLeadingGreaterThanOrEqualTo() + .pinTrailingLessThanOrEqualTo() + .pinCenterX() + .width(maxWidth) + .height(44) + previousButton .pinTop() .pinBottom() .pinLeading() + .pinTrailingGreaterThanOrEqualTo(collectionContainerView.leadingAnchor) - previousButton.trailingAnchor.constraint(greaterThanOrEqualTo: collectionContainerView.leadingAnchor).activate() - collectionContainerView.trailingAnchor.constraint(greaterThanOrEqualTo: nextButton.leadingAnchor).activate() collectionContainerView + .pinTrailingGreaterThanOrEqualTo(nextButton.leadingAnchor) .pinTop() .pinBottom() - collectionView.heightAnchor.constraint(equalToConstant: VDSLayout.Spacing.space4X.value).activate() - collectionView.centerYAnchor.constraint(equalTo: centerYAnchor).activate() - collectionView.centerXAnchor.constraint(equalTo: collectionContainerView.centerXAnchor).activate() - collectionViewWidthAnchor = collectionView.widthAnchor.constraint(equalToConstant: 92) - collectionViewWidthAnchor?.activate() + + collectionView + .height(VDSLayout.Spacing.space4X.value) + .pinCenterY() + .pinCenterX() + + collectionViewWidthAnchor = collectionView.width(constant: 92) nextButton .pinTop() diff --git a/VDS/Components/Pagination/PaginationCellItem.swift b/VDS/Components/Pagination/PaginationCellItem.swift index 68f51142..24edc3a4 100644 --- a/VDS/Components/Pagination/PaginationCellItem.swift +++ b/VDS/Components/Pagination/PaginationCellItem.swift @@ -48,7 +48,7 @@ final class PaginationCellItem: UICollectionViewCell { contentView.addSubview(containerView) containerView.pinToSuperView() indexLabel.pinToSuperView() - indexLabel.widthAnchor.constraint(greaterThanOrEqualToConstant: VDSLayout.Spacing.space5X.value).activate() + indexLabel.widthGreaterThanEqualTo(VDSLayout.Spacing.space5X.value) contentView.backgroundColor = .clear containerView.backgroundColor = .clear indexLabel.backgroundColor = .clear diff --git a/VDS/Protocols/LayoutConstraintable.swift b/VDS/Protocols/LayoutConstraintable.swift index 3c05bbc7..457b5fa5 100644 --- a/VDS/Protocols/LayoutConstraintable.swift +++ b/VDS/Protocols/LayoutConstraintable.swift @@ -478,7 +478,159 @@ extension LayoutConstraintable { } } +//-------------------------------------------------- +// MARK: - Center X Constraints +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a centerXAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func pinCenterX(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinCenterX(nil, constant) + } + @discardableResult + /// Adds a centerXAnchor to a specific XAxisAnchor. + /// - Parameter anchor:The anchor in which to attach the centerXAnchor. + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinCenterX(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinCenterX(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a centerXAnchor to a specific XAxisAnchor passed in using a lessThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the centerXAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinCenterXLessThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinCenterXLessThanOrEqualTo(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a centerXAnchor to a specific XAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the centerXAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinCenterXGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + pinCenterXGreaterThanOrEqualTo(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a centerXAnchor for the constant passed into the method. + /// - Parameter anchor:The anchor in which to attach the centerXAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinCenterX(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.centerXAnchor + guard let found else { return nil } + return centerXAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a centerXAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the centerXAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinCenterXLessThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.centerXAnchor + guard let found else { return nil } + return centerXAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a centerXAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the centerXAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinCenterXGreaterThanOrEqualTo(anchor: NSLayoutXAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutXAxisAnchor? = anchor ?? superview?.centerXAnchor + guard let found else { return nil } + return centerXAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } +} + +//-------------------------------------------------- +// MARK: - Center Y Constraints +//-------------------------------------------------- +extension LayoutConstraintable { + + @discardableResult + /// Adds a centerYAnchor. + /// - Parameter constant: Constant size. + /// - Returns: Yourself. + public func pinCenterY(_ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinCenterY(nil, constant) + } + + @discardableResult + /// Adds a centerYAnchor to a specific YAxisAnchor. + /// - Parameter anchor:The anchor in which to attach the centerYAnchor. + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinCenterY(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinCenterY(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a centerYAnchor to a specific YAxisAnchor passed in using a lessThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the centerYAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinCenterYLessThanOrEqualTo(_ anchor: NSLayoutYAxisAnchor? = nil, _ constant: CGFloat = 0.0, _ priority: UILayoutPriority = .required) -> Self { + pinCenterYLessThanOrEqualTo(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a centerYAnchor to a specific YAxisAnchor passed in using a greaterThanOrEqualTo Constraint + /// - Parameter anchor:The anchor in which to attach the centerYAnchor + /// - constant: Constant size. + /// - Returns: Yourself. + public func pinCenterYGreaterThanOrEqualTo(_ anchor: NSLayoutXAxisAnchor? = nil, _ constant: CGFloat = 0.0) -> Self { + pinCenterXGreaterThanOrEqualTo(anchor: anchor, constant: constant) + return self + } + + @discardableResult + /// Adds a centerYAnchor for the constant passed into the method. + /// - Parameter anchor:The anchor in which to attach the centerYAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinCenterY(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.centerYAnchor + guard let found else { return nil } + return centerYAnchor.constraint(equalTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a centerYAnchor with the constant passed in using a lessThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the centerYAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinCenterYLessThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.centerYAnchor + guard let found else { return nil } + return centerYAnchor.constraint(lessThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } + + @discardableResult + /// Adds a centerYAnchor with the constant passed in using a greaterThanOrEqualTo Constraint. + /// - Parameter anchor:The anchor in which to attach the centerYAnchor + /// - constant: Constant size. + /// - Returns: The Constraint that was created. + public func pinCenterYGreaterThanOrEqualTo(anchor: NSLayoutYAxisAnchor?, constant: CGFloat = 0.0, priority: UILayoutPriority = .required) -> NSLayoutConstraint? { + let found: NSLayoutYAxisAnchor? = anchor ?? superview?.centerYAnchor + guard let found else { return nil } + return centerYAnchor.constraint(greaterThanOrEqualTo: found, constant: -constant).with { $0.priority = priority; $0.isActive = true } + } +} //-------------------------------------------------- // MARK: - Implementations //-------------------------------------------------- From e0d1fd844d19d2ce66d651a88776fabf150755c5 Mon Sep 17 00:00:00 2001 From: vasavk Date: Wed, 20 Mar 2024 17:20:58 +0530 Subject: [PATCH 19/31] Digital ACT-191 ONEAPP-6827 story: Updated code as per review feedback --- VDS.xcodeproj/project.pbxproj | 6 +- .../Breadcrumbs/BreadcrumbCellItem.swift | 4 +- .../Breadcrumbs/BreadcrumbItem.swift | 14 +---- .../Breadcrumbs/BreadcrumbItemModel.swift | 32 +++++++++++ VDS/Components/Breadcrumbs/Breadcrumbs.swift | 56 ++++++++++++++++--- 5 files changed, 88 insertions(+), 24 deletions(-) create mode 100644 VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 39250df1..5557e118 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -9,6 +9,7 @@ /* Begin PBXBuildFile section */ 1832AC572BA0791D008AE476 /* BreadcrumbCellItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */; }; 18450CF12BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */; }; + 1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */; }; 186B2A8A2B88DA7F001AB71F /* TextAreaChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */; }; 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; @@ -184,6 +185,7 @@ /* Begin PBXFileReference section */ 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbCellItem.swift; sourceTree = ""; }; 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = BreadcrumbsChangeLog.txt; sourceTree = ""; }; + 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbItemModel.swift; sourceTree = ""; }; 186B2A892B88DA7F001AB71F /* TextAreaChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TextAreaChangeLog.txt; sourceTree = ""; }; 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; 18A65A012B96E848006602CC /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; @@ -373,8 +375,9 @@ 18A65A002B96E7E1006602CC /* Breadcrumbs */ = { isa = PBXGroup; children = ( - 18A65A012B96E848006602CC /* Breadcrumbs.swift */, 18A65A032B96F050006602CC /* BreadcrumbItem.swift */, + 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */, + 18A65A012B96E848006602CC /* Breadcrumbs.swift */, 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */, 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */, ); @@ -1043,6 +1046,7 @@ EA0D1C452A6AD73000E5C127 /* RawRepresentable.swift in Sources */, EA985C23296E033A00F2FF2E /* TextArea.swift in Sources */, EAF7F0B3289B1ADC00B287F5 /* ActionLabelAttribute.swift in Sources */, + 1855EC662BAABF2A002ACAC2 /* BreadcrumbItemModel.swift in Sources */, EAC925832911B35400091998 /* TextLinkCaret.swift in Sources */, EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */, EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */, diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index f8899577..888ade37 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -66,9 +66,9 @@ final class BreadcrumbCellItem: UICollectionViewCell { func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { separator.surface = surface breadCrumbItem.surface = surface - stackView.addArrangedSubview(separator) stackView.addArrangedSubview(breadCrumbItem) - stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) + stackView.addArrangedSubview(separator) + stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadCrumbItem) separator.textColor = textColorConfiguration.getColor(surface) separator.isHidden = hideSlash self.breadCrumbItem = breadCrumbItem diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index 856099b8..7d936d65 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -40,18 +40,8 @@ open class BreadcrumbItem: ButtonBase { /// TextStyle used on the titleLabel. open override var textStyle: TextStyle { isSelected ? TextStyle.boldBodySmall : TextStyle.bodySmall } - /// If true, it will be rendered as selected. - open var selectable: Bool = false { - didSet { - //update selected state - if selectable{ - isSelected = true - } else { - isSelected = false - } - setNeedsUpdate() - } - } + /// Whether the Control is selected or not. + open override var isSelected: Bool { didSet { setNeedsUpdate() } } /// UIColor used on the titleLabel text. open override var textColor: UIColor { diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift b/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift new file mode 100644 index 00000000..f792df3f --- /dev/null +++ b/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift @@ -0,0 +1,32 @@ +// +// BreadcrumbItemModel.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 20/03/24. +// + +import Foundation + +extension Breadcrumbs { + public struct BreadcrumbItemModel { + + ///Text that goes in the breadcrumb item + public var text: String + + /// The Breadcrumb link to links to its respective page. + public var link: String + + /// The Breadcrumb link to links to its respective page. + public var isSelected: Bool? + + ///Click event when you click on a breadcrumb item + public var onClick: ((BreadcrumbItem) -> Void)? + + public init(text: String, link: String, isSelected: Bool? = false, onClick: ((BreadcrumbItem) -> Void)? = nil) { + self.text = text + self.isSelected = isSelected + self.onClick = onClick + self.link = link + } + } +} diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index 94d6e6fe..ca6afaa1 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -18,23 +18,32 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// Array of Breadcrumb Items that are shown in the group. - open var breadcrumbItems: [BreadcrumbItem] = [] { didSet { setNeedsUpdate() } } + /// Array of ``BreadcrumbItem`` views for the Breadcrumbs. + open var breadcrumbs: [BreadcrumbItem] = [] + + /// Array of ``BreadcurmbItemModel`` you are wanting to show. + open var breadcrumbModels: [BreadcrumbItemModel] = [] { didSet { updateBreadcrumbItems() } } /// Whether this object is enabled or not override open var isEnabled: Bool { didSet { - breadcrumbItems.forEach { $0.isEnabled = isEnabled } + breadcrumbs.forEach { $0.isEnabled = isEnabled } } } /// Current Surface and this is used to pass down to child objects that implement Surfacable override open var surface: Surface { didSet { - breadcrumbItems.forEach { $0.surface = surface } + breadcrumbs.forEach { $0.surface = surface } } } + /// A callback when the selected item changes. Passes parameters (crumb). + open var onBreadcrumbDidSelect: ((BreadcrumbItem) -> Void)? + + /// A callback when the Tab determine if a item should be selected. + open var onBreadcrumbShouldSelect:((BreadcrumbItem) -> Bool)? + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -65,6 +74,35 @@ open class Breadcrumbs: View { return collectionView }() + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + /// Removes all of the Breadcrumbs and creates new ones from the Breadcrumb Models property. + private func updateBreadcrumbItems() { + // Clear existing breadcrumbs + for breadcrumbItem in breadcrumbs { + breadcrumbItem.removeFromSuperview() + } + + breadcrumbs.removeAll() + // Create new breadcrumb items from the models + for model in breadcrumbModels { + let breadcrumbItem = BreadcrumbItem() + breadcrumbItem.text = model.text + breadcrumbItem.link = model.link + breadcrumbItem.isSelected = model.isSelected ?? false + breadcrumbs.append(breadcrumbItem) + breadcrumbItem.onClick = { [weak self] breadcrumb in + guard let self else { return } + if self.onBreadcrumbShouldSelect?(breadcrumb) ?? true { + model.onClick?(breadcrumb) + self.onBreadcrumbDidSelect?(breadcrumb) + } + } + } + setNeedsUpdate() + } + //------------------------------------------s-------- // MARK: - Overrides //-------------------------------------------------- @@ -88,7 +126,7 @@ open class Breadcrumbs: View { open override func reset() { super.reset() shouldUpdateView = false - breadcrumbItems.forEach { $0.reset() } + breadcrumbs.forEach { $0.reset() } shouldUpdateView = true setNeedsUpdate() } @@ -115,17 +153,17 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { //-------------------------------------------------- // MARK: - UICollectionView Delegate & Datasource //-------------------------------------------------- - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { breadcrumbItems.count + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { breadcrumbs.count } public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } - let hideSlash = (indexPath.row == 0) - cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumbItems[indexPath.row]) + let hideSlash = (indexPath.row == breadcrumbs.count - 1 || breadcrumbs.count == 1) + cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumbs[indexPath.row]) return cell } public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { - breadcrumbItems[indexPath.row].intrinsicContentSize + breadcrumbs[indexPath.row].intrinsicContentSize } } From d11ef82a4a48c0b1fdab9b58e6e216daf0162911 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:16:17 -0500 Subject: [PATCH 20/31] refactored out flowlayout into a class and renamed Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 6 +++- .../Breadcrumbs/BreadcrumbsFlowLayout.swift | 31 +++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 5557e118..1454090c 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -154,6 +154,7 @@ EAEEECAF2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = EAEEECAE2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt */; }; EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; }; EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; }; + EAF4A6A12BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */; }; EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* CheckboxItem.swift */; }; EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; }; EAF7F0A0289AB7EC00B287F5 /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09F289AB7EC00B287F5 /* View.swift */; }; @@ -332,6 +333,7 @@ EAEEECAE2B1FC2BA00531FC2 /* ToggleViewChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ToggleViewChangeLog.txt; sourceTree = ""; }; EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = ""; }; EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = ""; }; + EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsFlowLayout.swift; sourceTree = ""; }; EAF7F0932899861000B287F5 /* CheckboxItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckboxItem.swift; sourceTree = ""; }; EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = ""; }; EAF7F09F289AB7EC00B287F5 /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; @@ -375,9 +377,10 @@ 18A65A002B96E7E1006602CC /* Breadcrumbs */ = { isa = PBXGroup; children = ( + 18A65A012B96E848006602CC /* Breadcrumbs.swift */, + EAF4A6A02BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift */, 18A65A032B96F050006602CC /* BreadcrumbItem.swift */, 1855EC652BAABF2A002ACAC2 /* BreadcrumbItemModel.swift */, - 18A65A012B96E848006602CC /* Breadcrumbs.swift */, 1832AC562BA0791D008AE476 /* BreadcrumbCellItem.swift */, 18450CF02BA1B19C009FDF2A /* BreadcrumbsChangeLog.txt */, ); @@ -1085,6 +1088,7 @@ EAD068922A560B65002E3A2D /* LoaderViewController.swift in Sources */, EABFEB642A26473700C4C106 /* NSAttributedString.swift in Sources */, EAF7F13328A2A16500B287F5 /* AttachmentLabelAttributeModel.swift in Sources */, + EAF4A6A12BAC8B94006BCC2C /* BreadcrumbsFlowLayout.swift in Sources */, EA0FC2C62914222900DF80B4 /* ButtonGroup.swift in Sources */, EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */, EA8E40932A82889500934ED3 /* TooltipDialog.swift in Sources */, diff --git a/VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift b/VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift new file mode 100644 index 00000000..d6daf151 --- /dev/null +++ b/VDS/Components/Breadcrumbs/BreadcrumbsFlowLayout.swift @@ -0,0 +1,31 @@ +// +// BreadcrumsFlowLayout.swift +// VDS +// +// Created by Matt Bruce on 3/21/24. +// + +import Foundation +import UIKit + +class BreadcrumbsFlowLayout: UICollectionViewFlowLayout { + + override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { + let attributes = super.layoutAttributesForElements(in: rect) + + var leftMargin = sectionInset.left + var maxY: CGFloat = -1.0 + attributes?.forEach { layoutAttribute in + if layoutAttribute.frame.origin.y >= maxY { + leftMargin = sectionInset.left + } + + layoutAttribute.frame.origin.x = leftMargin + + leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing + maxY = max(layoutAttribute.frame.maxY , maxY) + } + + return attributes + } +} From 5ce775a8856f221e76b907ceb25a6393047399ca Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:16:31 -0500 Subject: [PATCH 21/31] added isSelected to buttonBase Signed-off-by: Matt Bruce --- VDS/Components/Buttons/ButtonBase.swift | 3 +++ 1 file changed, 3 insertions(+) diff --git a/VDS/Components/Buttons/ButtonBase.swift b/VDS/Components/Buttons/ButtonBase.swift index 46f72c55..a1cb39dc 100644 --- a/VDS/Components/Buttons/ButtonBase.swift +++ b/VDS/Components/Buttons/ButtonBase.swift @@ -97,6 +97,9 @@ open class ButtonBase: UIButton, ViewProtocol, UserInfoable, Clickable { /// Whether the Control is enabled or not. open override var isEnabled: Bool { didSet { setNeedsUpdate() } } + /// Whether the Control is selected or not. + open override var isSelected: Bool { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- From c23e7f700b29eca2d2b24fae75d48e62dd45ac17 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:16:43 -0500 Subject: [PATCH 22/31] refactored model to correct properties Signed-off-by: Matt Bruce --- .../Breadcrumbs/BreadcrumbItemModel.swift | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift b/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift index f792df3f..507212de 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift @@ -12,21 +12,20 @@ extension Breadcrumbs { ///Text that goes in the breadcrumb item public var text: String - - /// The Breadcrumb link to links to its respective page. - public var link: String + public var enabled: Bool + /// The Breadcrumb link to links to its respective page. - public var isSelected: Bool? + public var selected: Bool ///Click event when you click on a breadcrumb item public var onClick: ((BreadcrumbItem) -> Void)? - public init(text: String, link: String, isSelected: Bool? = false, onClick: ((BreadcrumbItem) -> Void)? = nil) { + public init(text: String, enabeled: Bool = true, selected: Bool = false, onClick: ((BreadcrumbItem) -> Void)? = nil) { self.text = text - self.isSelected = isSelected + self.enabled = enabeled + self.selected = selected self.onClick = onClick - self.link = link } } } From b9f17f2af4a1fe0706ee19da5f74f459a9a3b45b Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:17:18 -0500 Subject: [PATCH 23/31] added disabled state removed link Signed-off-by: Matt Bruce --- VDS/Components/Breadcrumbs/BreadcrumbItem.swift | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift index 7d936d65..3b279551 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItem.swift @@ -34,15 +34,9 @@ open class BreadcrumbItem: ButtonBase { //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- - /// The Breadcrumb link to links to its respective page. - open var link: String? { didSet { setNeedsUpdate() } } - /// TextStyle used on the titleLabel. open override var textStyle: TextStyle { isSelected ? TextStyle.boldBodySmall : TextStyle.bodySmall } - - /// Whether the Control is selected or not. - open override var isSelected: Bool { didSet { setNeedsUpdate() } } - + /// UIColor used on the titleLabel text. open override var textColor: UIColor { textColorConfiguration.getColor(self) @@ -58,6 +52,7 @@ open class BreadcrumbItem: ButtonBase { //-------------------------------------------------- private var textColorConfiguration = ControlColorConfiguration().with { $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .normal) + $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .disabled) $0.setSurfaceColors(VDSColor.interactiveActiveOnlight, VDSColor.interactiveActiveOndark, forState: .highlighted) $0.setSurfaceColors(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark, forState: .selected) } @@ -85,7 +80,6 @@ open class BreadcrumbItem: ButtonBase { super.reset() shouldUpdateView = false text = nil - link = nil accessibilityCustomActions = [] isAccessibilityElement = true accessibilityTraits = .button From e9bd1614ec60d77c2b02e9859fe765c122aade95 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:17:26 -0500 Subject: [PATCH 24/31] refactored cell Signed-off-by: Matt Bruce --- .../Breadcrumbs/BreadcrumbCellItem.swift | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 888ade37..7026c885 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -66,34 +66,12 @@ final class BreadcrumbCellItem: UICollectionViewCell { func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { separator.surface = surface breadCrumbItem.surface = surface - stackView.addArrangedSubview(breadCrumbItem) stackView.addArrangedSubview(separator) - stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: breadCrumbItem) + stackView.addArrangedSubview(breadCrumbItem) + stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) separator.textColor = textColorConfiguration.getColor(surface) separator.isHidden = hideSlash self.breadCrumbItem = breadCrumbItem layoutIfNeeded() } } - -class LeftAlignedCollectionViewFlowLayout: UICollectionViewFlowLayout { - - override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { - let attributes = super.layoutAttributesForElements(in: rect) - - var leftMargin = sectionInset.left - var maxY: CGFloat = -1.0 - attributes?.forEach { layoutAttribute in - if layoutAttribute.frame.origin.y >= maxY { - leftMargin = sectionInset.left - } - - layoutAttribute.frame.origin.x = leftMargin - - leftMargin += layoutAttribute.frame.width + minimumInteritemSpacing - maxY = max(layoutAttribute.frame.maxY , maxY) - } - - return attributes - } -} From 7a533944b81fce491d264a5766e21730d2fbd814 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:17:44 -0500 Subject: [PATCH 25/31] refactored breadcrumbs to use selfsizing cv Signed-off-by: Matt Bruce --- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 54 +++++++------------- 1 file changed, 18 insertions(+), 36 deletions(-) diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index ca6afaa1..ad2f20de 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -19,7 +19,7 @@ open class Breadcrumbs: View { // MARK: - Public Properties //-------------------------------------------------- /// Array of ``BreadcrumbItem`` views for the Breadcrumbs. - open var breadcrumbs: [BreadcrumbItem] = [] + open var breadcrumbs: [BreadcrumbItem] = [] { didSet { setNeedsUpdate() } } /// Array of ``BreadcurmbItemModel`` you are wanting to show. open var breadcrumbModels: [BreadcrumbItemModel] = [] { didSet { updateBreadcrumbItems() } } @@ -47,12 +47,7 @@ open class Breadcrumbs: View { //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- - // Sizes are from InVision design specs. - internal var containerSize: CGSize { CGSize(width: 45, height: 44) } - - internal var heightConstraint: NSLayoutConstraint? - - let layout: UICollectionViewFlowLayout = LeftAlignedCollectionViewFlowLayout().with { + let layout: UICollectionViewFlowLayout = BreadcrumbsFlowLayout().with { $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize $0.minimumInteritemSpacing = VDSLayout.Spacing.space1X.value $0.minimumLineSpacing = VDSLayout.Spacing.space1X.value @@ -61,8 +56,8 @@ open class Breadcrumbs: View { } ///Collectionview to render Breadcrumb Items - private lazy var collectionView: UICollectionView = { - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + private lazy var collectionView: SelfSizingCollectionView = { + let collectionView = SelfSizingCollectionView(frame: .zero, collectionViewLayout: layout) collectionView.isScrollEnabled = false collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.delegate = self @@ -84,37 +79,26 @@ open class Breadcrumbs: View { breadcrumbItem.removeFromSuperview() } - breadcrumbs.removeAll() // Create new breadcrumb items from the models - for model in breadcrumbModels { + breadcrumbs = breadcrumbModels.compactMap({ model in let breadcrumbItem = BreadcrumbItem() breadcrumbItem.text = model.text - breadcrumbItem.link = model.link - breadcrumbItem.isSelected = model.isSelected ?? false - breadcrumbs.append(breadcrumbItem) + breadcrumbItem.isEnabled = model.enabled + breadcrumbItem.isSelected = model.selected breadcrumbItem.onClick = { [weak self] breadcrumb in - guard let self else { return } + guard let self, breadcrumb.isEnabled else { return } if self.onBreadcrumbShouldSelect?(breadcrumb) ?? true { model.onClick?(breadcrumb) self.onBreadcrumbDidSelect?(breadcrumb) } } - } - setNeedsUpdate() + return breadcrumbItem + }) } //------------------------------------------s-------- // MARK: - Overrides //-------------------------------------------------- - /// Called once when a view is initialized and is used to Setup additional UI or other constants and configurations. - open override func setup() { - super.setup() - //create the wrapping view - heightConstraint = self.heightAnchor.constraint(equalToConstant: containerSize.height) - heightConstraint?.priority = .defaultHigh - heightConstraint?.isActive = true - } - /// Executed on initialization for this View. open override func initialSetup() { super.initialSetup() @@ -135,17 +119,17 @@ open class Breadcrumbs: View { open override func updateView() { super.updateView() collectionView.reloadData() - heightConstraint?.constant = collectionView.collectionViewLayout.collectionViewContentSize.height - heightConstraint?.isActive = true } open override func layoutSubviews() { - super.layoutSubviews() + //Don't call super since we don't want an infinite loop + //super.layoutSubviews() + // Accounts for any collection size changes DispatchQueue.main.async { [weak self] in guard let self else { return } self.collectionView.collectionViewLayout.invalidateLayout() - } + } } } @@ -153,17 +137,15 @@ extension Breadcrumbs: UICollectionViewDelegate, UICollectionViewDataSource { //-------------------------------------------------- // MARK: - UICollectionView Delegate & Datasource //-------------------------------------------------- - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { breadcrumbs.count + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + breadcrumbs.count } - + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: BreadcrumbCellItem.identifier, for: indexPath) as? BreadcrumbCellItem else { return UICollectionViewCell() } - let hideSlash = (indexPath.row == breadcrumbs.count - 1 || breadcrumbs.count == 1) + let hideSlash = indexPath.row == 0 cell.update(surface: surface, hideSlash: hideSlash, breadCrumbItem: breadcrumbs[indexPath.row]) return cell } - public func collectionView(_ collectionView: UICollectionView, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize { - breadcrumbs[indexPath.row].intrinsicContentSize - } } From f862c8bd1ce326aefdecf20fa7c54b6749331dff Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 11:20:11 -0500 Subject: [PATCH 26/31] fix bug, must find other solution later Signed-off-by: Matt Bruce --- VDS/Components/Breadcrumbs/Breadcrumbs.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/VDS/Components/Breadcrumbs/Breadcrumbs.swift b/VDS/Components/Breadcrumbs/Breadcrumbs.swift index ad2f20de..0ed7585d 100644 --- a/VDS/Components/Breadcrumbs/Breadcrumbs.swift +++ b/VDS/Components/Breadcrumbs/Breadcrumbs.swift @@ -122,14 +122,17 @@ open class Breadcrumbs: View { } open override func layoutSubviews() { - //Don't call super since we don't want an infinite loop - //super.layoutSubviews() - + //Turn off the ability to execute updateView() in the super + //since we don't want an infinite loop + shouldUpdateView = false + super.layoutSubviews() + shouldUpdateView = true + // Accounts for any collection size changes DispatchQueue.main.async { [weak self] in guard let self else { return } self.collectionView.collectionViewLayout.invalidateLayout() - } + } } } From e139a0a0b8ff32e51e3bad99f4a6ff3dd0ef9618 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 14:15:41 -0500 Subject: [PATCH 27/31] refactor cell some more Signed-off-by: Matt Bruce --- .../Breadcrumbs/BreadcrumbCellItem.swift | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift index 7026c885..9f0ea68b 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbCellItem.swift @@ -64,14 +64,31 @@ final class BreadcrumbCellItem: UICollectionViewCell { ///Updating the breadCrumbItem and UI based on the selected flag along with the surface func update(surface: Surface, hideSlash: Bool, breadCrumbItem: BreadcrumbItem) { + //remove views from stack + separator.removeFromSuperview() + self.breadCrumbItem?.removeFromSuperview() + + //update surface separator.surface = surface breadCrumbItem.surface = surface + + //add to stack stackView.addArrangedSubview(separator) stackView.addArrangedSubview(breadCrumbItem) stackView.setCustomSpacing(VDSLayout.Spacing.space1X.value, after: separator) + + //update separator separator.textColor = textColorConfiguration.getColor(surface) separator.isHidden = hideSlash + self.breadCrumbItem = breadCrumbItem layoutIfNeeded() } + + /// Remove views from StackView. + override func prepareForReuse() { + super.prepareForReuse() + separator.removeFromSuperview() + breadCrumbItem?.removeFromSuperview() + } } From 37d43fbb62b5e90581b11b4e149951c60caf8fce Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 14:15:48 -0500 Subject: [PATCH 28/31] added comments Signed-off-by: Matt Bruce --- VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift b/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift index 507212de..75c97c86 100644 --- a/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift +++ b/VDS/Components/Breadcrumbs/BreadcrumbItemModel.swift @@ -13,6 +13,7 @@ extension Breadcrumbs { ///Text that goes in the breadcrumb item public var text: String + /// Whether the Item can be clicked. public var enabled: Bool /// The Breadcrumb link to links to its respective page. From bbcdbebbb0b9290abb0addfef11bfbe0ac4f8051 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 14:31:57 -0500 Subject: [PATCH 29/31] refactored some naming to keep in line with others Signed-off-by: Matt Bruce --- VDS.xcodeproj/project.pbxproj | 8 ++++---- VDS/Components/Pagination/Pagination.swift | 2 +- VDS/Components/Pagination/PaginationButton.swift | 1 + ...ationContainerView.swift => PaginationContainer.swift} | 6 +++--- 4 files changed, 9 insertions(+), 8 deletions(-) rename VDS/Components/Pagination/{PaginationContainerView.swift => PaginationContainer.swift} (96%) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 0dca7215..419b82cd 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -16,7 +16,7 @@ 5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; }; 5FC35BE328D51405004EBEAC /* Button.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5FC35BE228D51405004EBEAC /* Button.swift */; }; 7115BD3C2B84C0C200E0A610 /* TileContainerChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */; }; - 71ACE89C2BA0451200FB6ADC /* PaginationContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationContainerView.swift */; }; + 71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */; }; 71B23C2D2B91FA690027F7D9 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71B23C2C2B91FA690027F7D9 /* Pagination.swift */; }; 71B5FCBB2B95A0CA00269BCC /* PaginationChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */; }; 71BFA70A2B7F70E6000DCE33 /* DropShadowable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */; }; @@ -194,7 +194,7 @@ 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = ""; }; 5FC35BE228D51405004EBEAC /* Button.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Button.swift; sourceTree = ""; }; 7115BD3B2B84C0C200E0A610 /* TileContainerChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = TileContainerChangeLog.txt; sourceTree = ""; }; - 71ACE89B2BA0451200FB6ADC /* PaginationContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainerView.swift; sourceTree = ""; }; + 71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationContainer.swift; sourceTree = ""; }; 71B23C2C2B91FA690027F7D9 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; 71B5FCBA2B95A0CA00269BCC /* PaginationChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = PaginationChangeLog.txt; sourceTree = ""; }; 71BFA7092B7F70E6000DCE33 /* DropShadowable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropShadowable.swift; sourceTree = ""; }; @@ -408,7 +408,7 @@ isa = PBXGroup; children = ( 71B23C2C2B91FA690027F7D9 /* Pagination.swift */, - 71ACE89B2BA0451200FB6ADC /* PaginationContainerView.swift */, + 71ACE89B2BA0451200FB6ADC /* PaginationContainer.swift */, 71FC86D92B96F44C00700965 /* PaginationButton.swift */, 71FC86DB2B96F4C800700965 /* PaginationCellItem.swift */, 71FC86E32B9841AC00700965 /* PaginationFlowLayout.swift */, @@ -1063,7 +1063,7 @@ EAE785312BA0A438009428EA /* UIImage+Helper.swift in Sources */, EAB5FEF5292D371F00998C17 /* ButtonBase.swift in Sources */, EA978EC5291D6AFE00ACC883 /* AnyLabelAttribute.swift in Sources */, - 71ACE89C2BA0451200FB6ADC /* PaginationContainerView.swift in Sources */, + 71ACE89C2BA0451200FB6ADC /* PaginationContainer.swift in Sources */, EAC71A1F2A2E173D00E47A9F /* RadioButton.swift in Sources */, EA33622C2891E73B0071C351 /* FontProtocol.swift in Sources */, EA596ABD2A16B4EC00300C4B /* Tab.swift in Sources */, diff --git a/VDS/Components/Pagination/Pagination.swift b/VDS/Components/Pagination/Pagination.swift index 72cb3224..b7adcab3 100644 --- a/VDS/Components/Pagination/Pagination.swift +++ b/VDS/Components/Pagination/Pagination.swift @@ -45,7 +45,7 @@ open class Pagination: View { return collectionView }() ///Container view to hold collectionview to render pagination indexes and to handler accessibility. - private let collectionContainerView = PaginationContainerView() + private let collectionContainerView = PaginationContainer() //-------------------------------------------------- // MARK: - Public Properties diff --git a/VDS/Components/Pagination/PaginationButton.swift b/VDS/Components/Pagination/PaginationButton.swift index 3805051d..4ed851b5 100644 --- a/VDS/Components/Pagination/PaginationButton.swift +++ b/VDS/Components/Pagination/PaginationButton.swift @@ -9,6 +9,7 @@ import UIKit import VDSColorTokens ///This is customised button for Pagination view +@objc(PaginationButton) open class PaginationButton: ButtonBase { //-------------------------------------------------- // MARK: - Private Properties diff --git a/VDS/Components/Pagination/PaginationContainerView.swift b/VDS/Components/Pagination/PaginationContainer.swift similarity index 96% rename from VDS/Components/Pagination/PaginationContainerView.swift rename to VDS/Components/Pagination/PaginationContainer.swift index b79a2fe2..2172e32a 100644 --- a/VDS/Components/Pagination/PaginationContainerView.swift +++ b/VDS/Components/Pagination/PaginationContainer.swift @@ -6,9 +6,9 @@ // import UIKit - + ///PaginationCollectionView is a container view that holds collectionview for displaying page indexes -final class PaginationContainerView: View { +final class PaginationContainer: View { //-------------------------------------------------- // MARK: - Internal Properties @@ -17,7 +17,7 @@ final class PaginationContainerView: View { var onAccessibilityIncrement: (() -> Void)? ///Notifies when accessibility decrement is happend when user swipes down var onAccessibilityDecrement: (() -> Void)? - + //-------------------------------------------------- // MARK: - Overrides //-------------------------------------------------- From 67e42b9730711884df56871d23e6579c1cdb48d5 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 14:32:04 -0500 Subject: [PATCH 30/31] removed dumb code Signed-off-by: Matt Bruce --- VDS/Components/Tabs/Tabs.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/VDS/Components/Tabs/Tabs.swift b/VDS/Components/Tabs/Tabs.swift index 0aa81bdf..647a74a2 100644 --- a/VDS/Components/Tabs/Tabs.swift +++ b/VDS/Components/Tabs/Tabs.swift @@ -264,7 +264,6 @@ open class Tabs: View { model.onClick?(tab.index) self.selectedIndex = tab.index self.onTabDidSelect?(tab.index) - let t = tabViews[tab.index] } } } From d1006f12664735048026fa331d3977e497617d65 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Thu, 21 Mar 2024 15:11:38 -0500 Subject: [PATCH 31/31] removed images that already existed added resizer and refactored code Signed-off-by: Matt Bruce --- VDS/Components/Icon/IconName.swift | 1 - VDS/Components/Pagination/PaginationButton.swift | 14 +++++++++----- VDS/Extensions/UIImage+Helper.swift | 13 +++++++++++++ .../pagination-arrow-left.imageset/Contents.json | 12 ------------ .../pagination-arrow-left.svg | 10 ---------- .../pagination-arrow-right.imageset/Contents.json | 12 ------------ .../pagination-arrow-right.svg | 3 --- 7 files changed, 22 insertions(+), 43 deletions(-) delete mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json delete mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg delete mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json delete mode 100644 VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg diff --git a/VDS/Components/Icon/IconName.swift b/VDS/Components/Icon/IconName.swift index c2d5076b..1234df63 100644 --- a/VDS/Components/Icon/IconName.swift +++ b/VDS/Components/Icon/IconName.swift @@ -48,7 +48,6 @@ extension Icon { internal static let paginationRightCaret = Name(name: "pagination-right-caret") internal static let verizonUp = Name(name: "verizon-up") internal static let warningBold = Name(name: "warning-bold") - public static let checkmark = Name(name: "checkmark") public static let checkmarkAlt = Name(name: "checkmark-alt") public static let close = Name(name: "close") diff --git a/VDS/Components/Pagination/PaginationButton.swift b/VDS/Components/Pagination/PaginationButton.swift index 4ed851b5..290bbef5 100644 --- a/VDS/Components/Pagination/PaginationButton.swift +++ b/VDS/Components/Pagination/PaginationButton.swift @@ -73,8 +73,9 @@ open class PaginationButton: ButtonBase { /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { text = type.title - setImage(type.image, for: .normal) - tintColor = buttonTintColorConfiguration.getColor(surface) + let color = buttonTintColorConfiguration.getColor(surface) + setImage(type.image(color), for: .normal) + tintColor = color super.updateView() } } @@ -94,13 +95,16 @@ extension PaginationButton { "Previous" } } + + private var imageSize: CGSize { Icon.Size.xsmall.dimensions } + ///Image for the configuration type - var image: UIImage? { + func image(_ color: UIColor) -> UIImage? { switch self { case .previous: - BundleManager.shared.image(for: "pagination-arrow-left")?.withRenderingMode(.alwaysTemplate) + UIImage.image(for: .paginationLeftArrow, color: color, renderingMode: .alwaysTemplate)?.resized(to: imageSize) case .next: - BundleManager.shared.image(for: "pagination-arrow-right")?.withRenderingMode(.alwaysTemplate) + UIImage.image(for: .paginationRightArrow, color: color, renderingMode: .alwaysTemplate)?.resized(to: imageSize) } } } diff --git a/VDS/Extensions/UIImage+Helper.swift b/VDS/Extensions/UIImage+Helper.swift index c8f103dc..41f25a42 100644 --- a/VDS/Extensions/UIImage+Helper.swift +++ b/VDS/Extensions/UIImage+Helper.swift @@ -23,4 +23,17 @@ extension UIImage { return image.withTintColor(color, renderingMode: renderingMode) } + + /// Resizes image to a specific Size + /// - Parameter size: Size to resize + /// - Returns: Image that is resized + public func resized(to size: CGSize) -> UIImage? { + UIGraphicsBeginImageContextWithOptions(size, false, 0.0) + + defer { UIGraphicsEndImageContext() } + draw(in: .init(origin: .zero, size: size)) + + return UIGraphicsGetImageFromCurrentImageContext() + } + } diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json deleted file mode 100644 index 6c37b40d..00000000 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "pagination-arrow-left.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg deleted file mode 100644 index a8c85c97..00000000 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-left.imageset/pagination-arrow-left.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json deleted file mode 100644 index d294d555..00000000 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "pagination-arrow-right.svg", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg b/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg deleted file mode 100644 index be02bedf..00000000 --- a/VDS/SupportingFiles/Icons.xcassets/Restricted/pagination-arrow-right.imageset/pagination-arrow-right.svg +++ /dev/null @@ -1,3 +0,0 @@ - - -