From 4b5c4a28b25cbf6b29b7004322d397164d29b735 Mon Sep 17 00:00:00 2001 From: vasavk Date: Thu, 9 May 2024 13:38:02 +0530 Subject: [PATCH] Digital ACT-191 ONEAPP-7958 story: handling days of month based on min, max date and active, inactive dates selected. --- VDS/Components/Calendar/Calendar.swift | 7 +- .../CalendarDateCollectionViewCell.swift | 128 +++++++++++++----- 2 files changed, 102 insertions(+), 33 deletions(-) diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index ce183fac..e2f101d4 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -39,7 +39,7 @@ open class CalendarBase: View { open var hideCurrentDateIndicator: Bool = false { didSet { setNeedsUpdate() } } /// Enable specific days. Pass an array of string value in date format e.g. ['07/21/2024', '07/24/2024', 07/28/2024']. - /// All other dates will be inactive + /// All other dates will be inactive. open var activeDates: [Date] = [] { didSet { setNeedsUpdate() } } /// Disable specific days. Pass an array of string value in date format e.g. ['07/21/2024', '07/24/2024', 07/28/2024']. @@ -112,12 +112,13 @@ open class CalendarBase: View { internal var backgroundColorConfiguration = SurfaceColorConfiguration(VDSFormControlsColor.backgroundOnlight, VDSFormControlsColor.backgroundOndark) //-------------------------------------------------- - // MARK: - Lifecycle + // MARK: - Overrides //-------------------------------------------------- open override func initialSetup() { super.initialSetup() } + /// 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 = false @@ -171,6 +172,7 @@ open class CalendarBase: View { super.layoutSubviews() } + /// Resets to default settings. open override func reset() { super.reset() } @@ -283,6 +285,7 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI onChangeSelectedDate?(selectedItem) selectedDate = self.dates[indexPath.row] + displayDate = selectedDate var reloadIndexPaths = [indexPath] // If an cell is already selected, then it needs to be deselected. diff --git a/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift b/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift index efc506d8..40ba8b82 100644 --- a/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift +++ b/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift @@ -68,6 +68,10 @@ final class CalendarDateCollectionViewCell: UICollectionViewCell { setUp() } + //-------------------------------------------------- + // MARK: - Private Methods + //-------------------------------------------------- + /// Configuring the cell with default setup private func setUp() { isAccessibilityElement = false @@ -95,37 +99,20 @@ final class CalendarDateCollectionViewCell: UICollectionViewCell { /// Updating UI based on selected date, modified indicators data along with surface /// Enable/disable cell based on min date, max date, active dates, inactive dates func update(with surface: Surface, indicators: [CalendarBase.CalendarIndicatorModel], text: String, indicatorCount: Int, selectedDate: Date, displayDate: Date, hideDate: Bool, minDate: Date, maxDate: Date, activeDates: [Date], inactiveDates: [Date]) { + + stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } numberLabel.surface = surface numberLabel.text = text - stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } - - // enable/disable cells based on min date, max date. - if let day:Int = Int(numberLabel.text), day < minDate.dayInt || day > maxDate.dayInt { - numberLabel.isEnabled = false - numberLabel.textColor = disabledTextColorConfiguration.getColor(surface) - layer.backgroundColor = disabledBackgroundColor.getColor(surface).cgColor - } else { - numberLabel.isEnabled = false - // handing active dates - if activeDates.count > 0 && inactiveDates.count == 0 { - for x in (0...(activeDates.count-1)) { - if let day:Int = Int(numberLabel.text), day == activeDates[x].dayInt { - numberLabel.isEnabled = true - } - } - } else { - numberLabel.isEnabled = true - } - } + + // enable/disable cells based on min date, max date and active/inactive dates + self.updateLabel(with:surface, displayDate: displayDate, minDate: minDate, maxDate: maxDate, activeDates: activeDates, inactiveDates: inactiveDates) // handling inactive dates if inactiveDates.count > 0 { for x in (0...(inactiveDates.count-1)) { - if (activeDates[x].monthInt == displayDate.monthInt) && (activeDates[x].yearInt == displayDate.yearInt) { + if (inactiveDates[x].monthInt == displayDate.monthInt) && (inactiveDates[x].yearInt == displayDate.yearInt) { if let day:Int = Int(numberLabel.text), day == inactiveDates[x].dayInt { - numberLabel.isEnabled = false - numberLabel.textColor = disabledTextColorConfiguration.getColor(surface) - layer.backgroundColor = disabledBackgroundColor.getColor(surface).cgColor + disableLabel(with: surface) } } } @@ -145,24 +132,103 @@ final class CalendarDateCollectionViewCell: UICollectionViewCell { // add indicators if indicatorCount > 0 { for x in (0...(indicators.count-1)) { - if (self.numberLabel.text == self.getDay(with: indicators[x].date)) { - let color = (numberLabel.text == self.getDay(with: selectedDate)) ? selectedCellIndicatorColorConfiguration.getColor(surface) : unselectedCellIndicatorColorConfiguration.getColor(surface) - addIndicator(with: color, surface: surface, clearFullCircle: (x == 1), drawSemiCircle: (x == 2)) + // irrespective of month and year, if it needs to show indicators on every month - comment below first if condition + if (indicators[x].date.monthInt == displayDate.monthInt) && (indicators[x].date.yearInt == displayDate.yearInt) { + if (self.numberLabel.text == self.getDay(with: indicators[x].date)) { + let color = (numberLabel.text == self.getDay(with: selectedDate)) ? selectedCellIndicatorColorConfiguration.getColor(surface) : unselectedCellIndicatorColorConfiguration.getColor(surface) + addIndicator(with: color, surface: surface, clearFullCircle: (x == 1), drawSemiCircle: (x == 2)) + } } } } // update text style for current date - if (numberLabel.text == self.getDay(with: currentDate)) && (currentDate.monthInt == displayDate.monthInt) { + if (numberLabel.text == self.getDay(with: currentDate)) && (currentDate.monthInt == displayDate.monthInt) && (currentDate.yearInt == displayDate.yearInt) { numberLabel.textStyle = hideDate ? .bodySmall : .boldBodySmall } else { numberLabel.textStyle = .bodySmall } } - //-------------------------------------------------- - // MARK: - Private Methods - //-------------------------------------------------- + func disableLabel(with surface: Surface) { + numberLabel.isEnabled = false + numberLabel.textColor = disabledTextColorConfiguration.getColor(surface) + layer.backgroundColor = disabledBackgroundColor.getColor(surface).cgColor + } + + func showActiveDates(with displayDate: Date, activeDates: [Date], inactiveDates: [Date]) { + for x in (0...(activeDates.count-1)) { + if (activeDates[x].monthInt == displayDate.monthInt) && (activeDates[x].yearInt == displayDate.yearInt ) { + if let day:Int = Int(numberLabel.text), day == activeDates[x].dayInt { + numberLabel.isEnabled = true + } + } + } + } + + // handing active dates if exist, else enable numberLabel to display day + func handleActiveDates(with displayDate: Date, activeDates: [Date], inactiveDates: [Date]) { + if activeDates.count > 0 && inactiveDates.count == 0 { + showActiveDates(with: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } else { + numberLabel.isEnabled = true + } + } + + // enable all days if no active dates, handing active dates if exist + func enableAllDaysAndCheckActiveDates(with surface:Surface, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) { + if activeDates.count > 0 && inactiveDates.count == 0 { + disableLabel(with: surface) + showActiveDates(with: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } else { + numberLabel.isEnabled = true + } + } + + // enable/disable cells based on min date, max date and active/inactive dates + func updateLabel(with surface: Surface, displayDate: Date, minDate: Date, maxDate: Date, activeDates: [Date], inactiveDates: [Date]) { + if (minDate.yearInt == displayDate.yearInt) || (maxDate.yearInt == displayDate.yearInt) { + if (minDate.monthInt == displayDate.monthInt) && (maxDate.monthInt == displayDate.monthInt) { + // validate days to enable/disable + if let day:Int = Int(numberLabel.text), day < minDate.dayInt || day > maxDate.dayInt { + disableLabel(with: surface) + } else { + numberLabel.isEnabled = false + handleActiveDates(with: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } + } else if (minDate.monthInt == displayDate.monthInt) || (maxDate.monthInt == displayDate.monthInt) { + if (minDate.monthInt == displayDate.monthInt) { + // validate days to enable/disable + if let day:Int = Int(numberLabel.text), day < minDate.dayInt { + disableLabel(with: surface) + } else { + numberLabel.isEnabled = false + handleActiveDates(with: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } + + } else if (maxDate.monthInt == displayDate.monthInt) { + // validate days to enable/disable + if let day:Int = Int(numberLabel.text), day > maxDate.dayInt { + disableLabel(with: surface) + } else { + numberLabel.isEnabled = false + handleActiveDates(with: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } + + } + } else if ((minDate.monthInt < displayDate.monthInt) || (displayDate.monthInt < maxDate.monthInt)) { + // enable all days if no active dates + // handing active dates + enableAllDaysAndCheckActiveDates(with: surface, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } + } else { + // enable all days if no active dates + // handing active dates + enableAllDaysAndCheckActiveDates(with: surface, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) + } + + } + func addIndicator(with color: UIColor, surface: Surface, clearFullCircle: Bool, drawSemiCircle: Bool) { // add indicator let indicatorView: View = View().with {