From 7438d65fe53d2a46959c26be258eab2945cbf346 Mon Sep 17 00:00:00 2001 From: vasavk Date: Tue, 30 Apr 2024 11:17:14 +0530 Subject: [PATCH] Digital ACT-191 ONEAPP-7016 story: updating footer with indicators data --- VDS.xcodeproj/project.pbxproj | 12 +- VDS/Components/Calendar/Calendar.swift | 13 +- .../Calendar/CalendarIndicatorModel.swift | 4 +- .../Calendar/CalendarLegendView.swift | 204 ++++++++++++++++++ ...eView.swift => CalendarReusableView.swift} | 13 +- 5 files changed, 230 insertions(+), 16 deletions(-) create mode 100644 VDS/Components/Calendar/CalendarLegendView.swift rename VDS/Components/Calendar/{CalendarHeaderReusableView.swift => CalendarReusableView.swift} (83%) diff --git a/VDS.xcodeproj/project.pbxproj b/VDS.xcodeproj/project.pbxproj index 1890cb34..354969af 100644 --- a/VDS.xcodeproj/project.pbxproj +++ b/VDS.xcodeproj/project.pbxproj @@ -18,12 +18,13 @@ 18792A902B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */; }; 18A3F12A2BD9298900498E4A /* Calendar.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1292BD9298900498E4A /* Calendar.swift */; }; 18A3F1322BD944E800498E4A /* CalendarDateCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */; }; - 18A3F1382BDA693000498E4A /* CalendarHeaderReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */; }; 18A65A022B96E848006602CC /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A012B96E848006602CC /* Breadcrumbs.swift */; }; 18A65A042B96F050006602CC /* BreadcrumbItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18A65A032B96F050006602CC /* BreadcrumbItem.swift */; }; 18B463A42BBD3C46005C4528 /* DropdownOptionModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */; }; 18BDEE822B75316E00452358 /* ButtonIconChangeLog.txt in Resources */ = {isa = PBXBuildFile; fileRef = 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */; }; 18FEA1AD2BDD137500A56439 /* CalendarIndicatorModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */; }; + 18FEA1B12BE0B69300A56439 /* CalendarLegendView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */; }; + 18FEA1B32BE0BC8700A56439 /* CalendarReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */; }; 445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; }; 44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; }; 44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; }; @@ -211,12 +212,13 @@ 18792A8F2B7431F2008C0D29 /* ButtonIconBadgeIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonIconBadgeIndicatorModel.swift; sourceTree = ""; }; 18A3F1292BD9298900498E4A /* Calendar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Calendar.swift; sourceTree = ""; }; 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarDateCollectionViewCell.swift; sourceTree = ""; }; - 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarHeaderReusableView.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 = ""; }; 18B463A32BBD3C46005C4528 /* DropdownOptionModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropdownOptionModel.swift; sourceTree = ""; }; 18BDEE812B75316E00452358 /* ButtonIconChangeLog.txt */ = {isa = PBXFileReference; lastKnownFileType = text; path = ButtonIconChangeLog.txt; sourceTree = ""; }; 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarIndicatorModel.swift; sourceTree = ""; }; + 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarLegendView.swift; sourceTree = ""; }; + 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarReusableView.swift; sourceTree = ""; }; 445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = ""; }; 44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; @@ -428,8 +430,9 @@ children = ( 18A3F1292BD9298900498E4A /* Calendar.swift */, 18A3F1312BD944E800498E4A /* CalendarDateCollectionViewCell.swift */, - 18A3F1372BDA693000498E4A /* CalendarHeaderReusableView.swift */, 18FEA1AC2BDD137500A56439 /* CalendarIndicatorModel.swift */, + 18FEA1B02BE0B69300A56439 /* CalendarLegendView.swift */, + 18FEA1B22BE0BC8700A56439 /* CalendarReusableView.swift */, ); path = Calendar; sourceTree = ""; @@ -1163,7 +1166,6 @@ 71FC86DC2B96F4C800700965 /* PaginationCellItem.swift in Sources */, EAC846F3294B95CE00F685BA /* ButtonGroupCollectionViewCell.swift in Sources */, EAF7F0952899861000B287F5 /* CheckboxItem.swift in Sources */, - 18A3F1382BDA693000498E4A /* CalendarHeaderReusableView.swift in Sources */, EA985BE82968951C00F2FF2E /* TileletTitleModel.swift in Sources */, 71FC86DE2B9738B900700965 /* SurfaceConfigurationValue.swift in Sources */, EA297A5529FB07760031ED56 /* TooltipLabelAttribute.swift in Sources */, @@ -1216,7 +1218,9 @@ EA0B180A2AA78F9000F2D0CD /* UIEdgeInsets.swift in Sources */, EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */, EA0B18052A9E2D2D00F2D0CD /* SelectorBase.swift in Sources */, + 18FEA1B12BE0B69300A56439 /* CalendarLegendView.swift in Sources */, EAC71A1D2A2E155A00E47A9F /* Checkbox.swift in Sources */, + 18FEA1B32BE0BC8700A56439 /* CalendarReusableView.swift in Sources */, EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */, EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */, EA81410B2A0E8E3C004F60D2 /* ButtonIcon.swift in Sources */, diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index cb938dde..c9312c4e 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -62,8 +62,8 @@ open class CalendarBase: View { /// Array of ``CalendarIndicatorModel`` you are wanting to show on legend. open var indicators: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } - /// Array of indicators for the legend. - open var indicatorData: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } +// /// Array of indicators for the legend. +// open var indicatorData: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } /// A callback when the selected date changes.. open var onChangeSelectedDate: ((Date) -> String)? @@ -76,7 +76,7 @@ open class CalendarBase: View { private let headerHeight = 104.0 private let footerHeight = 56.0 private let items = 35 - + internal var containerView = View().with { $0.clipsToBounds = true } @@ -127,6 +127,11 @@ open class CalendarBase: View { collectionView.pinToSuperView() } + open override func updateView() { + super.updateView() + collectionView.reloadData() + } + override open func layoutSubviews() { super.layoutSubviews() } @@ -163,7 +168,7 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else { return UICollectionReusableView() } - footer.configure(with: true) + footer.configure(with: indicators) return footer } } diff --git a/VDS/Components/Calendar/CalendarIndicatorModel.swift b/VDS/Components/Calendar/CalendarIndicatorModel.swift index 04ad9714..911afe36 100644 --- a/VDS/Components/Calendar/CalendarIndicatorModel.swift +++ b/VDS/Components/Calendar/CalendarIndicatorModel.swift @@ -8,7 +8,7 @@ import Foundation /// Custom data type for indicators prop -extension CalendarBase { +//extension CalendarBase { public struct CalendarIndicatorModel { /// Text that shown to an indicator for legend @@ -22,4 +22,4 @@ extension CalendarBase { self.date = date } } -} +//} diff --git a/VDS/Components/Calendar/CalendarLegendView.swift b/VDS/Components/Calendar/CalendarLegendView.swift new file mode 100644 index 00000000..df1bbdf6 --- /dev/null +++ b/VDS/Components/Calendar/CalendarLegendView.swift @@ -0,0 +1,204 @@ +// +// CalendarLegendView.swift +// VDS +// +// Created by Kanamarlapudi, Vasavi on 29/04/24. +// + +import Foundation +import UIKit +import VDSTokens +import Combine + +/// Legend view to show array of indicators as calendar footer view. +open class CalendarLegendView: View { + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + required public init() { + super.init(frame: .zero) + } + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + } + + //-------------------------------------------------- + // MARK: - Public Properties + //-------------------------------------------------- + open var items: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } + + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- + internal var containerSize: CGSize { CGSize(width: 320, height: 56) } //width:320/328 + + internal var containerView = View().with { + $0.clipsToBounds = true + } + + private let flowLayout = UICollectionViewFlowLayout().with { + $0.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + $0.minimumLineSpacing = VDSLayout.space1X + $0.minimumInteritemSpacing = VDSLayout.space4X + $0.scrollDirection = .vertical + } + open lazy var legendCollectionView = UICollectionView(frame: .zero, collectionViewLayout: flowLayout).with { + $0.isScrollEnabled = false + $0.translatesAutoresizingMaskIntoConstraints = false + $0.showsVerticalScrollIndicator = false + $0.showsHorizontalScrollIndicator = false + $0.isAccessibilityElement = true + $0.backgroundColor = .clear + $0.delegate = self + $0.dataSource = self + $0.register(LegendCollectionViewCell.self, forCellWithReuseIdentifier: LegendCollectionViewCell.identifier) + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func initialSetup() { + super.initialSetup() + } + + open override func setup() { + super.setup() + isAccessibilityElement = false + + addSubview(containerView) + containerView + .pinTop(VDSLayout.space6X) + .pinBottom(VDSLayout.space4X) + .pinLeadingGreaterThanOrEqualTo(leadingAnchor, VDSLayout.space5X, .defaultLow) + .pinTrailingLessThanOrEqualTo(trailingAnchor, VDSLayout.space5X, .defaultHigh) + .height(containerSize.height) + .width(containerSize.width) + + containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + + // legend Collection View + containerView.addSubview(legendCollectionView) + legendCollectionView.pinToSuperView() + + } + + open override func updateView() { + super.updateView() + legendCollectionView.reloadData() + } + + override open func layoutSubviews() { + super.layoutSubviews() + } + + open override func reset() { + super.reset() + } +} + +extension CalendarLegendView: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return items.count + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard collectionView == legendCollectionView, + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LegendCollectionViewCell.identifier, for: indexPath) as? LegendCollectionViewCell, + indexPath.row <= items.count else { return UICollectionViewCell() } + let text = items[indexPath.row].label + cell.updateTitle(text: text, color: VDSColor.elementsSecondaryOnlight, surface: surface, clearFullcircle: indexPath.row == 1, drawSemiCircle: indexPath.row == 2) + return cell + } +} + +private class LegendCollectionViewCell: UICollectionViewCell { + + static let identifier: String = String(describing: LegendCollectionViewCell.self) + + private let textColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + + private let indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) + + private var title = Label().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.textAlignment = .left + $0.numberOfLines = 1 + $0.textStyle = .bodySmall + $0.backgroundColor = .clear + $0.isAccessibilityElement = false + } + private var legendIndicatorWrapper: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.backgroundColor = .clear + } + private var legendIndicator: View = View().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.backgroundColor = .clear + $0.layer.borderWidth = 1.0 + } + + private lazy var stackView = UIStackView().with { + $0.translatesAutoresizingMaskIntoConstraints = false + $0.distribution = .equalSpacing + $0.spacing = VDSLayout.space2X + $0.axis = .horizontal + $0.backgroundColor = .clear + } + + private lazy var shapeLayer = CAShapeLayer() + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + override init(frame: CGRect) { + super.init(frame: frame) + setupCell() + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + setupCell() + } + + func setupCell() { + addSubview(stackView) + stackView.pinToSuperView() + + legendIndicatorWrapper.addSubview(legendIndicator) + legendIndicator.pinLeading().pinTrailing().width(8).height(8).pinCenterY() + + stackView.addArrangedSubview(legendIndicatorWrapper) + stackView.addArrangedSubview(title) + } + + func updateTitle(text: String, color: UIColor, surface: Surface, clearFullcircle: Bool, drawSemiCircle: Bool) { + title.text = text + title.textColor = textColorConfiguration.getColor(surface) + + legendIndicator.backgroundColor = drawSemiCircle ? .clear : (clearFullcircle ? .clear : color) + legendIndicator.layer.borderColor = indicatorColorConfiguration.getColor(surface).cgColor + + self.layoutIfNeeded() + + legendIndicator.layer.cornerRadius = legendIndicator.frame.size.height / 2.0 + + guard drawSemiCircle else { return } + + let center = CGPoint(x: legendIndicator.frame.size.width/2, y: legendIndicator.frame.size.height/2) + let path = UIBezierPath() + path.move(to: center) + path.addArc(withCenter: center, radius: center.x, startAngle: 2 * .pi, endAngle: .pi, clockwise: true) + path.close() + shapeLayer.path = path.cgPath + shapeLayer.fillColor = color.cgColor + + guard legendIndicator.layer.sublayers?.contains(shapeLayer) ?? true else { return } + legendIndicator.layer.addSublayer(shapeLayer) + } +} diff --git a/VDS/Components/Calendar/CalendarHeaderReusableView.swift b/VDS/Components/Calendar/CalendarReusableView.swift similarity index 83% rename from VDS/Components/Calendar/CalendarHeaderReusableView.swift rename to VDS/Components/Calendar/CalendarReusableView.swift index 3f139a10..8131ce33 100644 --- a/VDS/Components/Calendar/CalendarHeaderReusableView.swift +++ b/VDS/Components/Calendar/CalendarReusableView.swift @@ -1,11 +1,12 @@ // -// CalendarHeaderReusableView.swift +// CalendarReusableView.swift // VDS // // Created by Kanamarlapudi, Vasavi on 24/04/24. // import UIKit +import VDSTokens /// Custom header view class CalendarHeaderReusableView: UICollectionReusableView { @@ -23,7 +24,6 @@ class CalendarHeaderReusableView: UICollectionReusableView { func configure(with color: Bool) { // Make a view and make in generic and dynamic - self.backgroundColor = .orange } override func layoutSubviews() { @@ -37,6 +37,8 @@ class CalendarFooterReusableView: UICollectionReusableView { ///Identifier for the Calendar Footer Reusable View static let identifier: String = String(describing: CalendarFooterReusableView.self) + private lazy var footerView = CalendarLegendView() + override init(frame: CGRect) { super.init(frame: frame) } @@ -45,13 +47,12 @@ class CalendarFooterReusableView: UICollectionReusableView { fatalError("init(coder:) has not been implemented") } - func configure(with color: Bool) { - // Make a view and make in generic and dynamic - self.backgroundColor = .green + func configure(with indicators: [CalendarIndicatorModel]) { + footerView.items = indicators + addSubview(footerView) } override func layoutSubviews() { super.layoutSubviews() } } -