diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index 9ec8e6fc..18465c47 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -69,7 +69,8 @@ open class CalendarBase: View { // MARK: - Private Properties //-------------------------------------------------- internal var containerSize: CGSize { CGSize(width: 328, height: 376) } - + internal var calendar = Calendar.current + private let cellItemSize = CGSize(width: 40, height: 40) private let headerHeight = 88.0 private let footerHeight = 40.0 @@ -96,10 +97,14 @@ open class CalendarBase: View { collectionView.showsHorizontalScrollIndicator = false collectionView.showsVerticalScrollIndicator = false collectionView.backgroundColor = .clear - collectionView.register(CalendarDateViewCell.self, forCellWithReuseIdentifier: CalendarDateViewCell.identifier) + + collectionView.register(CalendarDateViewCell.self, + forCellWithReuseIdentifier: CalendarDateViewCell.identifier) + collectionView.register(CalendarHeaderReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: CalendarHeaderReusableView.identifier) + collectionView.register(CalendarFooterReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: CalendarFooterReusableView.identifier) @@ -138,6 +143,7 @@ open class CalendarBase: View { containerView.addSubview(collectionView) let calendarHeight = containerSize.height - (2 * VDSLayout.space4X) let spacing = (containerSize.width - calendarWidth) / 2 + collectionView .pinTop(VDSLayout.space4X) .pinBottom(VDSLayout.space4X) @@ -145,7 +151,8 @@ open class CalendarBase: View { .pinTrailing(spacing) .width(calendarWidth) .heightGreaterThanEqualTo(calendarHeight) - collectionView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).activate() + + collectionView.pinCenterX(anchor: containerView.centerXAnchor) } open override func updateView() { @@ -155,7 +162,7 @@ open class CalendarBase: View { // Check if current date falls between min & max dates. let fallsBetween = displayDate.isBetweeen(date: minDate, andDate: maxDate) displayDate = fallsBetween ? displayDate : minDate - self.fetchDates(with: displayDate) + fetchDates(with: displayDate) } layer.backgroundColor = backgroundColorConfiguration.getColor(self).cgColor @@ -169,11 +176,7 @@ open class CalendarBase: View { layer.cornerRadius = VDSFormControls.borderRadius } } - - override open func layoutSubviews() { - super.layoutSubviews() - } - + /// Resets to default settings. open override func reset() { super.reset() @@ -188,41 +191,31 @@ open class CalendarBase: View { //-------------------------------------------------- // MARK: - Private Methods //-------------------------------------------------- - func fetchDates(with aDate:Date) { + func fetchDates(with aDate: Date) { heightConstraint?.isActive = false containerHeightConstraint?.isActive = false days.removeAll() - self.dates = aDate.calendarDisplayDays + dates = aDate.calendarDisplayDays + for date in dates { // code to be executed if date.monthInt != aDate.monthInt { days.append("") } else { - days.append(getDay(with: date)) + days.append(date.getDay()) } } - self.collectionView.reloadData() - var height = self.collectionView.collectionViewLayout.collectionViewContentSize.height - height = (height > 0) ? height : containerSize.height + + collectionView.reloadData() + + var height = collectionView.collectionViewLayout.collectionViewContentSize.height + height = height > 0 ? height : containerSize.height heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: height) - containerHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: (height + (2 * VDSLayout.space4X))) + containerHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: height + (2 * VDSLayout.space4X)) heightConstraint?.isActive = true containerHeightConstraint?.isActive = true - self.layoutIfNeeded() - } - - func getDay(with date:Date) -> String { - if #available(iOS 15.0, *) { - return date.formatted(.dateTime.day()) - } else { - // Fallback on earlier versions - let dateFormatter: DateFormatter = DateFormatter() - dateFormatter.dateFormat = "d" - let day: String = dateFormatter.string(from: date) - return day - } - } - + layoutIfNeeded() + } } extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout { @@ -235,21 +228,41 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalendarDateViewCell.identifier, for: indexPath) as? CalendarDateViewCell else { return UICollectionViewCell() } + var indicatorCount = 0 - if self.indicators.count > 0 { - for x in (0...(self.indicators.count-1)) { - if (self.days[indexPath.row] == self.getDay(with: self.indicators[x].date)) { + + if indicators.count > 0 { + for x in 0...indicators.count - 1 { + if days[indexPath.row] == indicators[x].date.getDay() { indicatorCount += 1 } } } - cell.update(with: surface, indicators: indicators, text: days[indexPath.row], indicatorCount: indicatorCount, selectedDate: selectedDate, displayDate: displayDate, hideDate: hideCurrentDateIndicator, minDate: minDate, maxDate: maxDate, activeDates: activeDates, inactiveDates: inactiveDates) - if (self.days[indexPath.row] == self.getDay(with: selectedDate)) { selectedIndexPath = indexPath } + + cell.update(with: surface, + indicators: indicators, + text: days[indexPath.row], + indicatorCount: indicatorCount, + selectedDate: selectedDate, + displayDate: displayDate, + hideDate: hideCurrentDateIndicator, + minDate: minDate, + maxDate: maxDate, + activeDates: activeDates, + inactiveDates: inactiveDates) + + if days[indexPath.row] == selectedDate.getDay() { + selectedIndexPath = indexPath + } + return cell } public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - if kind == UICollectionView.elementKindSectionHeader { + + switch kind { + case UICollectionView.elementKindSectionHeader: + // Header guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarHeaderReusableView.identifier, for: indexPath) as? CalendarHeaderReusableView else { return UICollectionReusableView() @@ -258,42 +271,51 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI var prevEnabled = false // check the interval between min date, max date.. set enable/disable flag for next / previous buttons. - if ((displayDate.monthInt < maxDate.monthInt) && (displayDate.yearInt == maxDate.yearInt)) || (displayDate.yearInt < maxDate.yearInt) { + if displayDate.monthInt < maxDate.monthInt && displayDate.yearInt == maxDate.yearInt + || displayDate.yearInt < maxDate.yearInt { nextEnabled = true } - if ((minDate.monthInt < displayDate.monthInt) && (minDate.yearInt == displayDate.yearInt)) || (minDate.yearInt < displayDate.yearInt) { + if minDate.monthInt < displayDate.monthInt && minDate.yearInt == displayDate.yearInt + || minDate.yearInt < displayDate.yearInt { prevEnabled = true } header.nextClicked = { [weak self] in guard let self = self else { return } - let aDate = Calendar.current.date(byAdding: .month, value: 1, to:self.displayDate)! - if ((aDate.monthInt <= maxDate.monthInt) && (aDate.yearInt == maxDate.yearInt)) || (aDate.yearInt < maxDate.yearInt) { - displayDate = aDate - self.fetchDates(with: displayDate) + let date = calendar.date(byAdding: .month, value: 1, to:displayDate)! + if date.monthInt <= maxDate.monthInt && date.yearInt == maxDate.yearInt + || date.yearInt < maxDate.yearInt { + displayDate = date + fetchDates(with: displayDate) } } + header.previousClicked = { [weak self] in guard let self = self else { return } - let aDate = Calendar.current.date(byAdding: .month, value: -1, to:self.displayDate)! - if ((minDate.monthInt <= aDate.monthInt) && (minDate.yearInt == aDate.yearInt)) || (minDate.yearInt < aDate.yearInt) { - displayDate = aDate - self.fetchDates(with: displayDate) + let date = calendar.date(byAdding: .month, value: -1, to:displayDate)! + if minDate.monthInt <= date.monthInt && minDate.yearInt == date.yearInt || (minDate.yearInt < date.yearInt) { + displayDate = date + fetchDates(with: displayDate) } } - header.update(with: surface, aDate: displayDate, nextEnabled: nextEnabled, previousEnabled: prevEnabled) + header.update(with: surface, date: displayDate, nextEnabled: nextEnabled, previousEnabled: prevEnabled) + return header - } else { - // Footer - if kind == UICollectionView.elementKindSectionFooter { - guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else { - return UICollectionReusableView() - } - footer.update(with: surface, indicators: indicators) - return footer + + case UICollectionView.elementKindSectionFooter: + + guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else { + return UICollectionReusableView() } + footer.update(with: surface, indicators: indicators) + + return footer + + default: + + return UICollectionReusableView() + } - return UICollectionReusableView() } public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { @@ -301,18 +323,21 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI if let cell = collectionView.cellForItem(at: indexPath) as? CalendarDateViewCell { let isEnabled: Bool = cell.isDateEnabled() if isEnabled { - // Callback to pass selected date if it is enabled only. - let selectedItem = Calendar.current.date(byAdding: .day, value: 1, to: self.dates[indexPath.row])! - onChangeSelectedDate?(selectedItem) - selectedDate = self.dates[indexPath.row] + // Callback to pass selected date if it is enabled only. + selectedDate = dates[indexPath.row] + onChangeSelectedDate?(selectedDate) displayDate = selectedDate + var reloadIndexPaths = [indexPath] // If an cell is already selected, then it needs to be deselected. // Add its index path to the array of index paths to be reloaded. - if let deselectIndexPath = selectedIndexPath { reloadIndexPaths.append(deselectIndexPath) } - self.collectionView.reloadItems(at: reloadIndexPaths) + if let deselectIndexPath = selectedIndexPath { + reloadIndexPaths.append(deselectIndexPath) + } + + collectionView.reloadItems(at: reloadIndexPaths) } } } diff --git a/VDS/Components/Calendar/CalendarDateViewCell.swift b/VDS/Components/Calendar/CalendarDateViewCell.swift index 26886d0a..b9f7359b 100644 --- a/VDS/Components/Calendar/CalendarDateViewCell.swift +++ b/VDS/Components/Calendar/CalendarDateViewCell.swift @@ -80,7 +80,7 @@ final class CalendarDateViewCell: UICollectionViewCell { .pinTrailingLessThanOrEqualTo() .height(containerSize.height) .width(containerSize.width) - containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + .pinCenterX() // Number label containerView.addSubview(numberLabel) @@ -89,8 +89,12 @@ final class CalendarDateViewCell: UICollectionViewCell { // Indicators containerView.addSubview(stackView) let topPos = containerSize.height * 0.7 - stackView.pinTop(topPos).pinBottom().pinTopGreaterThanOrEqualTo().pinTrailingLessThanOrEqualTo() - stackView.centerXAnchor.constraint(equalTo: centerXAnchor).activate() + stackView + .pinTop(topPos) + .pinBottom() + .pinTopGreaterThanOrEqualTo() + .pinTrailingLessThanOrEqualTo() + .pinCenterX() } /// Updating UI based on selected date, modified indicators data along with surface. @@ -102,12 +106,12 @@ final class CalendarDateViewCell: UICollectionViewCell { numberLabel.text = text // 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) + 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 (inactiveDates[x].monthInt == displayDate.monthInt) && (inactiveDates[x].yearInt == displayDate.yearInt) { + for x in 0...inactiveDates.count-1 { + if inactiveDates[x].monthInt == displayDate.monthInt && inactiveDates[x].yearInt == displayDate.yearInt { if let day:Int = Int(numberLabel.text), day == inactiveDates[x].dayInt { disableLabel(with: surface) } @@ -116,10 +120,15 @@ final class CalendarDateViewCell: UICollectionViewCell { } // update text color, bg color, corner radius. - if (numberLabel.text == self.getDay(with: selectedDate)) && (selectedDate.monthInt == displayDate.monthInt) && (selectedDate.yearInt == displayDate.yearInt) && numberLabel.isEnabled { + if numberLabel.text == selectedDate.getDay() + && selectedDate.monthInt == displayDate.monthInt + && selectedDate.yearInt == displayDate.yearInt + && numberLabel.isEnabled { + numberLabel.textColor = selectedTextColorConfiguration.getColor(surface) layer.backgroundColor = selectedBackgroundColor.getColor(surface).cgColor layer.cornerRadius = VDSFormControls.borderRadius + } else { numberLabel.textColor = unselectedTextColorConfiguration.getColor(surface) layer.backgroundColor = nil @@ -128,19 +137,18 @@ final class CalendarDateViewCell: UICollectionViewCell { // add indicators. if indicatorCount > 0 { - for x in (0...(indicators.count-1)) { - // irrespective of month and year, if it needs to show indicators on every month - comment below first if condition, else uncomment it. - // 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)) - } - // } + for x in 0...indicators.count-1 { + if numberLabel.text == indicators[x].date.getDay() { + let color = numberLabel.text == selectedDate.getDay() ? 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) && (currentDate.yearInt == displayDate.yearInt) { + if numberLabel.text == currentDate.getDay() + && currentDate.monthInt == displayDate.monthInt + && currentDate.yearInt == displayDate.yearInt { numberLabel.textStyle = hideDate ? .bodySmall : .boldBodySmall } else { numberLabel.textStyle = .bodySmall @@ -159,8 +167,8 @@ final class CalendarDateViewCell: UICollectionViewCell { } 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 ) { + 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 } @@ -189,7 +197,7 @@ final class CalendarDateViewCell: UICollectionViewCell { func minDateValidation(with surface:Surface, minDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) { // validate days to enable/disable with min date only. - if let day:Int = Int(numberLabel.text), day < minDate.dayInt { + if let day = Int(numberLabel.text), day < minDate.dayInt { disableLabel(with: surface) } else { numberLabel.isEnabled = false @@ -199,7 +207,7 @@ final class CalendarDateViewCell: UICollectionViewCell { func maxDateValidation(with surface:Surface, maxDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) { // validate days to enable/disable with max date only. - if let day:Int = Int(numberLabel.text), day > maxDate.dayInt { + if let day = Int(numberLabel.text), day > maxDate.dayInt { disableLabel(with: surface) } else { numberLabel.isEnabled = false @@ -209,7 +217,7 @@ final class CalendarDateViewCell: UICollectionViewCell { func minAndMaxDateValidation(with surface:Surface, minDate: Date, maxDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) { // validate days to enable/disable with min and max date. - if let day:Int = Int(numberLabel.text), day < minDate.dayInt || day > maxDate.dayInt { + if let day = Int(numberLabel.text), day < minDate.dayInt || day > maxDate.dayInt { disableLabel(with: surface) } else { numberLabel.isEnabled = false @@ -220,33 +228,33 @@ final class CalendarDateViewCell: UICollectionViewCell { // 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.yearInt == displayDate.yearInt && !(maxDate.yearInt == displayDate.yearInt) { // min year and max year are different, and matched to min year. - if (minDate.monthInt == displayDate.monthInt) { + if minDate.monthInt == displayDate.monthInt { // min year and max year are different, and matched to min year and min month. minDateValidation(with: surface, minDate: minDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) } else { // handing active dates - enable all days if no active dates. enableAllDaysAndCheckActiveDates(with: surface, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) } - } else if (maxDate.yearInt == displayDate.yearInt) && !((minDate.yearInt == displayDate.yearInt)) { + } else if maxDate.yearInt == displayDate.yearInt && !(minDate.yearInt == displayDate.yearInt) { // min year and max year are different, and matched to max year. - if (maxDate.monthInt == displayDate.monthInt) { + if maxDate.monthInt == displayDate.monthInt { // min year and max year are different, and matched to max year and max month. maxDateValidation(with: surface, maxDate: maxDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) } else { // handing active dates - enable all days if no active dates. enableAllDaysAndCheckActiveDates(with: surface, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) } - } else if (minDate.yearInt == displayDate.yearInt) && (maxDate.yearInt == displayDate.yearInt) { + } else if minDate.yearInt == displayDate.yearInt && maxDate.yearInt == displayDate.yearInt { // min year and max year same - if (minDate.monthInt == displayDate.monthInt) && (maxDate.monthInt == displayDate.monthInt) { + if minDate.monthInt == displayDate.monthInt && maxDate.monthInt == displayDate.monthInt { // min year and max year same, when choose dates in same month. minAndMaxDateValidation(with: surface, minDate: minDate, maxDate: maxDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) - } else if (minDate.monthInt == displayDate.monthInt) || (maxDate.monthInt == displayDate.monthInt) { + } else if minDate.monthInt == displayDate.monthInt || maxDate.monthInt == displayDate.monthInt { // min year and max year same, and choose dates in different months. - if (minDate.monthInt == displayDate.monthInt) { + if minDate.monthInt == displayDate.monthInt { // min year and max year same, and matched to min month. minDateValidation(with: surface, minDate: minDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates) } else if (maxDate.monthInt == displayDate.monthInt) { @@ -272,14 +280,21 @@ final class CalendarDateViewCell: UICollectionViewCell { $0.backgroundColor = .clear $0.layer.borderWidth = 1.0 } - indicatorView.pinLeading().pinTrailing().width(8).height(8).pinCenterY() + + indicatorView + .pinLeading() + .pinTrailing() + .width(8) + .height(8) + .pinCenterY() + stackView.addArrangedSubview(indicatorView) // update indicator indicatorView.backgroundColor = drawSemiCircle ? .clear : (clearFullCircle ? .clear : color) indicatorView.layer.borderColor = color.cgColor - self.layoutIfNeeded() + layoutIfNeeded() indicatorView.layer.cornerRadius = indicatorView.frame.size.height / 2.0 @@ -296,16 +311,4 @@ final class CalendarDateViewCell: UICollectionViewCell { guard indicatorView.layer.sublayers?.contains(shapeLayer) ?? true else { return } indicatorView.layer.addSublayer(shapeLayer) } - - func getDay(with date: Date) -> String { - if #available(iOS 15.0, *) { - return date.formatted(.dateTime.day()) - } else { - // Fallback on earlier versions - let dateFormatter: DateFormatter = DateFormatter() - dateFormatter.dateFormat = "d" - let day: String = dateFormatter.string(from: date) - return day - } - } } diff --git a/VDS/Components/Calendar/CalendarFooterReusableView.swift b/VDS/Components/Calendar/CalendarFooterReusableView.swift index 3e85a6ec..f8432bda 100644 --- a/VDS/Components/Calendar/CalendarFooterReusableView.swift +++ b/VDS/Components/Calendar/CalendarFooterReusableView.swift @@ -65,7 +65,6 @@ class CalendarFooterReusableView: UICollectionReusableView { addSubview(containerView) containerView -// .pinTop(VDSLayout.space6X) .pinTopLessThanOrEqualTo(topAnchor, VDSLayout.space6X, .defaultLow) .pinBottom() .pinLeadingGreaterThanOrEqualTo(leadingAnchor, VDSLayout.space3X, .defaultHigh) @@ -99,7 +98,11 @@ extension CalendarFooterReusableView: UICollectionViewDelegate, UICollectionView 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: self.surface, clearFullcircle: indexPath.row == 1, drawSemiCircle: indexPath.row == 2) + cell.updateTitle(text: text, + color: VDSColor.elementsSecondaryOnlight, + surface: self.surface, + clearFullcircle: indexPath.row == 1, + drawSemiCircle: indexPath.row == 2) return cell } } diff --git a/VDS/Components/Calendar/CalendarHeaderReusableView.swift b/VDS/Components/Calendar/CalendarHeaderReusableView.swift index b1d18810..d0f7f247 100644 --- a/VDS/Components/Calendar/CalendarHeaderReusableView.swift +++ b/VDS/Components/Calendar/CalendarHeaderReusableView.swift @@ -153,7 +153,7 @@ class CalendarHeaderReusableView: UICollectionReusableView { /// Updating UI based on next/previous clicks along with surface. /// Updating UI to enable/disable the next & previous buttons, updating header title. - func update(with surface: Surface, aDate: Date, nextEnabled: Bool, previousEnabled: Bool) { + func update(with surface: Surface, date: Date, nextEnabled: Bool, previousEnabled: Bool) { self.surface = surface headerTitle.surface = surface previousButton.surface = surface @@ -161,7 +161,7 @@ class CalendarHeaderReusableView: UICollectionReusableView { nextButton.isEnabled = nextEnabled previousButton.isEnabled = previousEnabled daysCollectionView.reloadData() - let labelText = aDate.getMonthName(date: aDate) + " \(aDate.yearInt)" + let labelText = date.getMonthName() + " \(date.yearInt)" headerTitle.text = labelText headerTitle.textColor = headerTitleTextColorConfiguration.getColor(surface) } diff --git a/VDS/Components/Calendar/Date+Extension.swift b/VDS/Components/Calendar/Date+Extension.swift index ca4f5a3b..25d8c9de 100644 --- a/VDS/Components/Calendar/Date+Extension.swift +++ b/VDS/Components/Calendar/Date+Extension.swift @@ -22,18 +22,6 @@ public extension Date { } } - /// Returns all month names - static var fullMonthNames: [String] { - let dateFormatter = DateFormatter() - dateFormatter.locale = Locale.current - - return (1...12).compactMap { month in - dateFormatter.setLocalizedDateFormatFromTemplate("MMMM") - let date = Calendar.current.date(from: DateComponents(year: 2000, month: month, day: 1)) - return date.map { dateFormatter.string(from: $0) } - } - } - var startOfMonth: Date { Calendar.current.dateInterval(of: .month, for: self)!.start } @@ -45,7 +33,7 @@ public extension Date { /// Get the number of days of the month var numberOfDaysInMonth: Int { - Calendar.current.component(.day, from: endOfMonth) + Calendar.current.range(of: .day, in: .month, for: self)!.count } var firstWeekDayBeforeStart: Date { @@ -98,9 +86,22 @@ public extension Date { } /// Returns the month name of the given date - func getMonthName(date: Date) -> String { - let names = Date.fullMonthNames - return names[date.monthInt - 1] + func getMonthName() -> String { + let dateFormatter = DateFormatter() + dateFormatter.locale = Locale.current + dateFormatter.setLocalizedDateFormatFromTemplate("MMMM") + return dateFormatter.string(from: self) + } + + func getDay() -> String { + if #available(iOS 15.0, *) { + return formatted(.dateTime.day()) + } else { + // Fallback on earlier versions + let dateFormatter: DateFormatter = DateFormatter() + dateFormatter.dateFormat = "d" + let day: String = dateFormatter.string(from: self) + return day + } } - }