diff --git a/VDS/Components/Calendar/Calendar.swift b/VDS/Components/Calendar/Calendar.swift index 41890756..cfd2c11d 100644 --- a/VDS/Components/Calendar/Calendar.swift +++ b/VDS/Components/Calendar/Calendar.swift @@ -54,15 +54,10 @@ open class CalendarBase: View { /// If provided, this is the date that will show as selected by the Calendar. /// If no value is provided, the current date will be used. If null is provided, no date will be selected. - open var selectedDate: Date? { + open var selectedDate: Date { get { return _selectedDate } set { - if let newValue { - _selectedDate = newValue - } else { - _selectedDate = Date() - } - //update views what needed + _selectedDate = newValue setNeedsUpdate() } } @@ -75,22 +70,25 @@ open class CalendarBase: View { // /// Array of indicators for the legend. // open var indicatorData: [CalendarIndicatorModel] = [] { didSet { setNeedsUpdate() } } - - /// A callback when the selected date changes.. - open var onChangeSelectedDate: ((Date) -> String)? + + /// A callback when the date changes. Passes parameters (selectedDate). + public var onChangeSelectedDate: ((Date) -> Void)? //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- internal var _selectedDate: Date = Date() - private var dates: [Date] = [] - private var days: [String] = [] internal var containerSize: CGSize { CGSize(width: 328, height: 376) } //width:320/328 + private let cellItemSize = CGSize(width: 40, height: 40) private let headerHeight = 88.0 private let footerHeight = 40.0 private let items = 35 + private var selectedIndexPath : IndexPath? + private var dates: [Date] = [] + private var days: [String] = [] + internal var containerView = View().with { $0.clipsToBounds = true } @@ -163,7 +161,7 @@ open class CalendarBase: View { open override func updateView() { super.updateView() - self.fetchDates(with: selectedDate ?? Date()) + self.fetchDates(with: selectedDate) collectionView.reloadData() if hideContainerBorder { layer.borderColor = nil @@ -189,15 +187,13 @@ open class CalendarBase: View { //-------------------------------------------------- func fetchDates(with date:Date) { days.removeAll() - if let dates = selectedDate?.calendarDisplayDays { - self.dates = dates - for date in dates { - // code to be executed - if date.monthInt != selectedDate?.monthInt { - days.append("") - } else { - days.append(getDay(with: date)) - } + self.dates = selectedDate.calendarDisplayDays + for date in dates { + // code to be executed + if date.monthInt != selectedDate.monthInt { + days.append("") + } else { + days.append(getDay(with: date)) } } } @@ -234,7 +230,8 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI } } } - cell.configure(with: surface, indicators: indicators, text: days[indexPath.row], indicatorCount: indicatorCount) + cell.configure(with: surface, indicators: indicators, text: days[indexPath.row], indicatorCount: indicatorCount, selectedDate: selectedDate) + if (self.days[indexPath.row] == self.getDay(with: selectedDate)) { selectedIndexPath = indexPath } return cell } @@ -260,8 +257,16 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI } public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { -// let selectedDate = Calendar.current.date(byAdding: .day, value: 1, to: self.dates[indexPath.row])! -// print("selected day: \(days[indexPath.row]), date: \(selectedDate)") + let selectedItem = Calendar.current.date(byAdding: .day, value: 1, to: self.dates[indexPath.row])! + onChangeSelectedDate?(selectedItem) + + selectedDate = self.dates[indexPath.row] + 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) } public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { diff --git a/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift b/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift index 68917069..eb66cde7 100644 --- a/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift +++ b/VDS/Components/Calendar/CalendarDateCollectionViewCell.swift @@ -9,15 +9,20 @@ import Foundation import UIKit import VDSTokens -/// Calendar collection view cell +/// Calendar collection view for Date view final class CalendarDateCollectionViewCell: UICollectionViewCell { ///Identifier for the Calendar Date Cell static let identifier: String = String(describing: CalendarDateCollectionViewCell.self) - + //-------------------------------------------------- + // MARK: - Private Properties + //-------------------------------------------------- private lazy var dateView = DateView() + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- override init(frame: CGRect) { super.init(frame: frame) } @@ -26,17 +31,15 @@ final class CalendarDateCollectionViewCell: UICollectionViewCell { fatalError("init(coder:) has not been implemented") } - func configure(with surface: Surface, indicators: [CalendarBase.CalendarIndicatorModel], text: String, indicatorCount: Int) { + func configure(with surface: Surface, indicators: [CalendarBase.CalendarIndicatorModel], text: String, indicatorCount: Int, selectedDate: Date) { addSubview(dateView) dateView.surface = surface dateView.numberLabel.text = text dateView.indicatorCount = indicatorCount dateView.dateIndicators = indicators + dateView.selectedDate = selectedDate } - override func layoutSubviews() { - super.layoutSubviews() - } } /// Date view to show Date number and indicator if applies @@ -67,9 +70,11 @@ private class DateView : View { open var numberLabel = Label().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.textAlignment = .center - $0.textStyle = .bodySmall //isCurrentDate: .boldBodySmall + $0.textStyle = .bodySmall } + open var selectedDate: Date = Date() //? { didSet { setNeedsUpdate() } } + //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- @@ -93,8 +98,15 @@ private class DateView : View { private lazy var shapeLayer = CAShapeLayer() - private let indicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) + private let selectedTextColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryInverseOnlight, VDSColor.elementsPrimaryInverseOndark) + private let selectedBackgroundColor = SurfaceColorConfiguration(VDSColor.backgroundPrimaryInverseLight, VDSColor.backgroundPrimaryInverseDark) + private let selectedCellIndicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.paletteGray65, VDSColor.paletteGray44) + + private let unselectedTextColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsPrimaryOnlight, VDSColor.elementsPrimaryOndark) + private let unselectedCellIndicatorColorConfiguration = SurfaceColorConfiguration(VDSColor.elementsSecondaryOnlight, VDSColor.elementsSecondaryOndark) + private let currentDate = Date() + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- @@ -130,17 +142,42 @@ private class DateView : View { super.updateView() numberLabel.surface = surface numberLabel.isEnabled = isEnabled - stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } + + // update text color, bg color, corner radius + if numberLabel.text == self.getDay(with: selectedDate) { + numberLabel.textColor = selectedTextColorConfiguration.getColor(self) + layer.backgroundColor = selectedBackgroundColor.getColor(self).cgColor + layer.cornerRadius = VDSFormControls.borderRadius + } else { + numberLabel.textColor = unselectedTextColorConfiguration.getColor(self) + layer.backgroundColor = nil + layer.cornerRadius = 0 + } + + // add indicators if indicatorCount > 0 { let width = (indicatorCount * 8) + (Int(VDSLayout.space1X) * (indicatorCount - 1)) stackView.widthAnchor.constraint(equalToConstant: CGFloat(width)).activate() for x in (0...(dateIndicators.count-1)) { if (self.numberLabel.text == self.getDay(with: dateIndicators[x].date)) { - addIndicator(with: VDSColor.elementsSecondaryOnlight, surface: surface, clearFullCircle: (x == 1), drawSemiCircle: (x == 2)) + if numberLabel.text == self.getDay(with: selectedDate) { + addIndicator(with: selectedCellIndicatorColorConfiguration.getColor(self), surface: surface, clearFullCircle: (x == 1), drawSemiCircle: (x == 2)) + } else { + addIndicator(with: unselectedCellIndicatorColorConfiguration.getColor(self), surface: surface, clearFullCircle: (x == 1), drawSemiCircle: (x == 2)) + } } } } + + // update text style for current date + if numberLabel.text == self.getDay(with: currentDate) { + numberLabel.textStyle = .boldBodySmall + } else { + numberLabel.textStyle = .bodySmall + } + + } override open func layoutSubviews() { @@ -167,7 +204,7 @@ private class DateView : View { // update indicator indicatorView.backgroundColor = drawSemiCircle ? .clear : (clearFullCircle ? .clear : color) - indicatorView.layer.borderColor = indicatorColorConfiguration.getColor(surface).cgColor + indicatorView.layer.borderColor = color.cgColor self.layoutIfNeeded()