refactored code
Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
parent
561b47610b
commit
49ec99e9be
@ -69,6 +69,7 @@ open class CalendarBase: View {
|
|||||||
// MARK: - Private Properties
|
// MARK: - Private Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
internal var containerSize: CGSize { CGSize(width: 328, height: 376) }
|
internal var containerSize: CGSize { CGSize(width: 328, height: 376) }
|
||||||
|
internal var calendar = Calendar.current
|
||||||
|
|
||||||
private let cellItemSize = CGSize(width: 40, height: 40)
|
private let cellItemSize = CGSize(width: 40, height: 40)
|
||||||
private let headerHeight = 88.0
|
private let headerHeight = 88.0
|
||||||
@ -96,10 +97,14 @@ open class CalendarBase: View {
|
|||||||
collectionView.showsHorizontalScrollIndicator = false
|
collectionView.showsHorizontalScrollIndicator = false
|
||||||
collectionView.showsVerticalScrollIndicator = false
|
collectionView.showsVerticalScrollIndicator = false
|
||||||
collectionView.backgroundColor = .clear
|
collectionView.backgroundColor = .clear
|
||||||
collectionView.register(CalendarDateViewCell.self, forCellWithReuseIdentifier: CalendarDateViewCell.identifier)
|
|
||||||
|
collectionView.register(CalendarDateViewCell.self,
|
||||||
|
forCellWithReuseIdentifier: CalendarDateViewCell.identifier)
|
||||||
|
|
||||||
collectionView.register(CalendarHeaderReusableView.self,
|
collectionView.register(CalendarHeaderReusableView.self,
|
||||||
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
|
forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader,
|
||||||
withReuseIdentifier: CalendarHeaderReusableView.identifier)
|
withReuseIdentifier: CalendarHeaderReusableView.identifier)
|
||||||
|
|
||||||
collectionView.register(CalendarFooterReusableView.self,
|
collectionView.register(CalendarFooterReusableView.self,
|
||||||
forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
|
forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter,
|
||||||
withReuseIdentifier: CalendarFooterReusableView.identifier)
|
withReuseIdentifier: CalendarFooterReusableView.identifier)
|
||||||
@ -138,6 +143,7 @@ open class CalendarBase: View {
|
|||||||
containerView.addSubview(collectionView)
|
containerView.addSubview(collectionView)
|
||||||
let calendarHeight = containerSize.height - (2 * VDSLayout.space4X)
|
let calendarHeight = containerSize.height - (2 * VDSLayout.space4X)
|
||||||
let spacing = (containerSize.width - calendarWidth) / 2
|
let spacing = (containerSize.width - calendarWidth) / 2
|
||||||
|
|
||||||
collectionView
|
collectionView
|
||||||
.pinTop(VDSLayout.space4X)
|
.pinTop(VDSLayout.space4X)
|
||||||
.pinBottom(VDSLayout.space4X)
|
.pinBottom(VDSLayout.space4X)
|
||||||
@ -145,7 +151,8 @@ open class CalendarBase: View {
|
|||||||
.pinTrailing(spacing)
|
.pinTrailing(spacing)
|
||||||
.width(calendarWidth)
|
.width(calendarWidth)
|
||||||
.heightGreaterThanEqualTo(calendarHeight)
|
.heightGreaterThanEqualTo(calendarHeight)
|
||||||
collectionView.centerXAnchor.constraint(equalTo: containerView.centerXAnchor).activate()
|
|
||||||
|
collectionView.pinCenterX(anchor: containerView.centerXAnchor)
|
||||||
}
|
}
|
||||||
|
|
||||||
open override func updateView() {
|
open override func updateView() {
|
||||||
@ -155,7 +162,7 @@ open class CalendarBase: View {
|
|||||||
// Check if current date falls between min & max dates.
|
// Check if current date falls between min & max dates.
|
||||||
let fallsBetween = displayDate.isBetweeen(date: minDate, andDate: maxDate)
|
let fallsBetween = displayDate.isBetweeen(date: minDate, andDate: maxDate)
|
||||||
displayDate = fallsBetween ? displayDate : minDate
|
displayDate = fallsBetween ? displayDate : minDate
|
||||||
self.fetchDates(with: displayDate)
|
fetchDates(with: displayDate)
|
||||||
}
|
}
|
||||||
|
|
||||||
layer.backgroundColor = backgroundColorConfiguration.getColor(self).cgColor
|
layer.backgroundColor = backgroundColorConfiguration.getColor(self).cgColor
|
||||||
@ -170,10 +177,6 @@ open class CalendarBase: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override open func layoutSubviews() {
|
|
||||||
super.layoutSubviews()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Resets to default settings.
|
/// Resets to default settings.
|
||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
@ -188,41 +191,31 @@ open class CalendarBase: View {
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Private Methods
|
// MARK: - Private Methods
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
func fetchDates(with aDate:Date) {
|
func fetchDates(with aDate: Date) {
|
||||||
heightConstraint?.isActive = false
|
heightConstraint?.isActive = false
|
||||||
containerHeightConstraint?.isActive = false
|
containerHeightConstraint?.isActive = false
|
||||||
days.removeAll()
|
days.removeAll()
|
||||||
self.dates = aDate.calendarDisplayDays
|
dates = aDate.calendarDisplayDays
|
||||||
|
|
||||||
for date in dates {
|
for date in dates {
|
||||||
// code to be executed
|
// code to be executed
|
||||||
if date.monthInt != aDate.monthInt {
|
if date.monthInt != aDate.monthInt {
|
||||||
days.append("")
|
days.append("")
|
||||||
} else {
|
} else {
|
||||||
days.append(getDay(with: date))
|
days.append(date.getDay())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.collectionView.reloadData()
|
|
||||||
var height = self.collectionView.collectionViewLayout.collectionViewContentSize.height
|
collectionView.reloadData()
|
||||||
height = (height > 0) ? height : containerSize.height
|
|
||||||
|
var height = collectionView.collectionViewLayout.collectionViewContentSize.height
|
||||||
|
height = height > 0 ? height : containerSize.height
|
||||||
heightConstraint = collectionView.heightAnchor.constraint(equalToConstant: 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
|
heightConstraint?.isActive = true
|
||||||
containerHeightConstraint?.isActive = true
|
containerHeightConstraint?.isActive = true
|
||||||
self.layoutIfNeeded()
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
|
||||||
@ -235,21 +228,41 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI
|
|||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
|
||||||
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalendarDateViewCell.identifier, for: indexPath) as? CalendarDateViewCell else { return UICollectionViewCell() }
|
guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CalendarDateViewCell.identifier, for: indexPath) as? CalendarDateViewCell else { return UICollectionViewCell() }
|
||||||
|
|
||||||
var indicatorCount = 0
|
var indicatorCount = 0
|
||||||
if self.indicators.count > 0 {
|
|
||||||
for x in (0...(self.indicators.count-1)) {
|
if indicators.count > 0 {
|
||||||
if (self.days[indexPath.row] == self.getDay(with: self.indicators[x].date)) {
|
for x in 0...indicators.count - 1 {
|
||||||
|
if days[indexPath.row] == indicators[x].date.getDay() {
|
||||||
indicatorCount += 1
|
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
|
return cell
|
||||||
}
|
}
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
public func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView {
|
||||||
if kind == UICollectionView.elementKindSectionHeader {
|
|
||||||
|
switch kind {
|
||||||
|
case UICollectionView.elementKindSectionHeader:
|
||||||
|
|
||||||
// Header
|
// Header
|
||||||
guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarHeaderReusableView.identifier, for: indexPath) as? CalendarHeaderReusableView else {
|
guard let header = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarHeaderReusableView.identifier, for: indexPath) as? CalendarHeaderReusableView else {
|
||||||
return UICollectionReusableView()
|
return UICollectionReusableView()
|
||||||
@ -258,42 +271,51 @@ extension CalendarBase: UICollectionViewDelegate, UICollectionViewDataSource, UI
|
|||||||
var prevEnabled = false
|
var prevEnabled = false
|
||||||
|
|
||||||
// check the interval between min date, max date.. set enable/disable flag for next / previous buttons.
|
// 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
|
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
|
prevEnabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
header.nextClicked = { [weak self] in
|
header.nextClicked = { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let aDate = Calendar.current.date(byAdding: .month, value: 1, to:self.displayDate)!
|
let date = calendar.date(byAdding: .month, value: 1, to:displayDate)!
|
||||||
if ((aDate.monthInt <= maxDate.monthInt) && (aDate.yearInt == maxDate.yearInt)) || (aDate.yearInt < maxDate.yearInt) {
|
if date.monthInt <= maxDate.monthInt && date.yearInt == maxDate.yearInt
|
||||||
displayDate = aDate
|
|| date.yearInt < maxDate.yearInt {
|
||||||
self.fetchDates(with: displayDate)
|
displayDate = date
|
||||||
|
fetchDates(with: displayDate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
header.previousClicked = { [weak self] in
|
header.previousClicked = { [weak self] in
|
||||||
guard let self = self else { return }
|
guard let self = self else { return }
|
||||||
let aDate = Calendar.current.date(byAdding: .month, value: -1, to:self.displayDate)!
|
let date = calendar.date(byAdding: .month, value: -1, to:displayDate)!
|
||||||
if ((minDate.monthInt <= aDate.monthInt) && (minDate.yearInt == aDate.yearInt)) || (minDate.yearInt < aDate.yearInt) {
|
if minDate.monthInt <= date.monthInt && minDate.yearInt == date.yearInt || (minDate.yearInt < date.yearInt) {
|
||||||
displayDate = aDate
|
displayDate = date
|
||||||
self.fetchDates(with: displayDate)
|
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
|
return header
|
||||||
} else {
|
|
||||||
// Footer
|
case UICollectionView.elementKindSectionFooter:
|
||||||
if kind == UICollectionView.elementKindSectionFooter {
|
|
||||||
guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else {
|
guard let footer = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: CalendarFooterReusableView.identifier, for: indexPath) as? CalendarFooterReusableView else {
|
||||||
return UICollectionReusableView()
|
return UICollectionReusableView()
|
||||||
}
|
}
|
||||||
footer.update(with: surface, indicators: indicators)
|
footer.update(with: surface, indicators: indicators)
|
||||||
|
|
||||||
return footer
|
return footer
|
||||||
}
|
|
||||||
}
|
default:
|
||||||
|
|
||||||
return UICollectionReusableView()
|
return UICollectionReusableView()
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
|
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 {
|
if let cell = collectionView.cellForItem(at: indexPath) as? CalendarDateViewCell {
|
||||||
let isEnabled: Bool = cell.isDateEnabled()
|
let isEnabled: Bool = cell.isDateEnabled()
|
||||||
if isEnabled {
|
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
|
displayDate = selectedDate
|
||||||
|
|
||||||
var reloadIndexPaths = [indexPath]
|
var reloadIndexPaths = [indexPath]
|
||||||
|
|
||||||
// If an cell is already selected, then it needs to be deselected.
|
// 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.
|
// Add its index path to the array of index paths to be reloaded.
|
||||||
if let deselectIndexPath = selectedIndexPath { reloadIndexPaths.append(deselectIndexPath) }
|
if let deselectIndexPath = selectedIndexPath {
|
||||||
self.collectionView.reloadItems(at: reloadIndexPaths)
|
reloadIndexPaths.append(deselectIndexPath)
|
||||||
|
}
|
||||||
|
|
||||||
|
collectionView.reloadItems(at: reloadIndexPaths)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -80,7 +80,7 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
.pinTrailingLessThanOrEqualTo()
|
.pinTrailingLessThanOrEqualTo()
|
||||||
.height(containerSize.height)
|
.height(containerSize.height)
|
||||||
.width(containerSize.width)
|
.width(containerSize.width)
|
||||||
containerView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
.pinCenterX()
|
||||||
|
|
||||||
// Number label
|
// Number label
|
||||||
containerView.addSubview(numberLabel)
|
containerView.addSubview(numberLabel)
|
||||||
@ -89,8 +89,12 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
// Indicators
|
// Indicators
|
||||||
containerView.addSubview(stackView)
|
containerView.addSubview(stackView)
|
||||||
let topPos = containerSize.height * 0.7
|
let topPos = containerSize.height * 0.7
|
||||||
stackView.pinTop(topPos).pinBottom().pinTopGreaterThanOrEqualTo().pinTrailingLessThanOrEqualTo()
|
stackView
|
||||||
stackView.centerXAnchor.constraint(equalTo: centerXAnchor).activate()
|
.pinTop(topPos)
|
||||||
|
.pinBottom()
|
||||||
|
.pinTopGreaterThanOrEqualTo()
|
||||||
|
.pinTrailingLessThanOrEqualTo()
|
||||||
|
.pinCenterX()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updating UI based on selected date, modified indicators data along with surface.
|
/// Updating UI based on selected date, modified indicators data along with surface.
|
||||||
@ -102,12 +106,12 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
numberLabel.text = text
|
numberLabel.text = text
|
||||||
|
|
||||||
// enable/disable cells based on min date, max date and active/inactive dates.
|
// 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.
|
// handling inactive dates.
|
||||||
if inactiveDates.count > 0 {
|
if inactiveDates.count > 0 {
|
||||||
for x in (0...(inactiveDates.count-1)) {
|
for x in 0...inactiveDates.count-1 {
|
||||||
if (inactiveDates[x].monthInt == displayDate.monthInt) && (inactiveDates[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 {
|
if let day:Int = Int(numberLabel.text), day == inactiveDates[x].dayInt {
|
||||||
disableLabel(with: surface)
|
disableLabel(with: surface)
|
||||||
}
|
}
|
||||||
@ -116,10 +120,15 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// update text color, bg color, corner radius.
|
// 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)
|
numberLabel.textColor = selectedTextColorConfiguration.getColor(surface)
|
||||||
layer.backgroundColor = selectedBackgroundColor.getColor(surface).cgColor
|
layer.backgroundColor = selectedBackgroundColor.getColor(surface).cgColor
|
||||||
layer.cornerRadius = VDSFormControls.borderRadius
|
layer.cornerRadius = VDSFormControls.borderRadius
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
numberLabel.textColor = unselectedTextColorConfiguration.getColor(surface)
|
numberLabel.textColor = unselectedTextColorConfiguration.getColor(surface)
|
||||||
layer.backgroundColor = nil
|
layer.backgroundColor = nil
|
||||||
@ -128,19 +137,18 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
|
|
||||||
// add indicators.
|
// add indicators.
|
||||||
if indicatorCount > 0 {
|
if indicatorCount > 0 {
|
||||||
for x in (0...(indicators.count-1)) {
|
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 numberLabel.text == indicators[x].date.getDay() {
|
||||||
// if (indicators[x].date.monthInt == displayDate.monthInt) && (indicators[x].date.yearInt == displayDate.yearInt) {
|
let color = numberLabel.text == selectedDate.getDay() ? selectedCellIndicatorColorConfiguration.getColor(surface) : unselectedCellIndicatorColorConfiguration.getColor(surface)
|
||||||
if (self.numberLabel.text == self.getDay(with: indicators[x].date)) {
|
addIndicator(with: color, surface: surface, clearFullCircle: x == 1, drawSemiCircle: x == 2)
|
||||||
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.
|
// 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
|
numberLabel.textStyle = hideDate ? .bodySmall : .boldBodySmall
|
||||||
} else {
|
} else {
|
||||||
numberLabel.textStyle = .bodySmall
|
numberLabel.textStyle = .bodySmall
|
||||||
@ -159,8 +167,8 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func showActiveDates(with displayDate: Date, activeDates: [Date], inactiveDates: [Date]) {
|
func showActiveDates(with displayDate: Date, activeDates: [Date], inactiveDates: [Date]) {
|
||||||
for x in (0...(activeDates.count-1)) {
|
for x in 0...activeDates.count-1 {
|
||||||
if (activeDates[x].monthInt == displayDate.monthInt) && (activeDates[x].yearInt == displayDate.yearInt ) {
|
if activeDates[x].monthInt == displayDate.monthInt && activeDates[x].yearInt == displayDate.yearInt {
|
||||||
if let day:Int = Int(numberLabel.text), day == activeDates[x].dayInt {
|
if let day:Int = Int(numberLabel.text), day == activeDates[x].dayInt {
|
||||||
numberLabel.isEnabled = true
|
numberLabel.isEnabled = true
|
||||||
}
|
}
|
||||||
@ -189,7 +197,7 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
|
|
||||||
func minDateValidation(with surface:Surface, minDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) {
|
func minDateValidation(with surface:Surface, minDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) {
|
||||||
// validate days to enable/disable with min date only.
|
// 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)
|
disableLabel(with: surface)
|
||||||
} else {
|
} else {
|
||||||
numberLabel.isEnabled = false
|
numberLabel.isEnabled = false
|
||||||
@ -199,7 +207,7 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
|
|
||||||
func maxDateValidation(with surface:Surface, maxDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) {
|
func maxDateValidation(with surface:Surface, maxDate: Date, displayDate: Date, activeDates: [Date], inactiveDates: [Date]) {
|
||||||
// validate days to enable/disable with max date only.
|
// 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)
|
disableLabel(with: surface)
|
||||||
} else {
|
} else {
|
||||||
numberLabel.isEnabled = false
|
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]) {
|
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.
|
// 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)
|
disableLabel(with: surface)
|
||||||
} else {
|
} else {
|
||||||
numberLabel.isEnabled = false
|
numberLabel.isEnabled = false
|
||||||
@ -220,33 +228,33 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
// enable/disable cells based on min date, max date and active/inactive dates.
|
// 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]) {
|
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.
|
// 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.
|
// 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)
|
minDateValidation(with: surface, minDate: minDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates)
|
||||||
} else {
|
} else {
|
||||||
// handing active dates - enable all days if no active dates.
|
// handing active dates - enable all days if no active dates.
|
||||||
enableAllDaysAndCheckActiveDates(with: surface, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates)
|
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.
|
// 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.
|
// 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)
|
maxDateValidation(with: surface, maxDate: maxDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates)
|
||||||
} else {
|
} else {
|
||||||
// handing active dates - enable all days if no active dates.
|
// handing active dates - enable all days if no active dates.
|
||||||
enableAllDaysAndCheckActiveDates(with: surface, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates)
|
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
|
// 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.
|
// 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)
|
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.
|
// 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.
|
// min year and max year same, and matched to min month.
|
||||||
minDateValidation(with: surface, minDate: minDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates)
|
minDateValidation(with: surface, minDate: minDate, displayDate: displayDate, activeDates: activeDates, inactiveDates: inactiveDates)
|
||||||
} else if (maxDate.monthInt == displayDate.monthInt) {
|
} else if (maxDate.monthInt == displayDate.monthInt) {
|
||||||
@ -272,14 +280,21 @@ final class CalendarDateViewCell: UICollectionViewCell {
|
|||||||
$0.backgroundColor = .clear
|
$0.backgroundColor = .clear
|
||||||
$0.layer.borderWidth = 1.0
|
$0.layer.borderWidth = 1.0
|
||||||
}
|
}
|
||||||
indicatorView.pinLeading().pinTrailing().width(8).height(8).pinCenterY()
|
|
||||||
|
indicatorView
|
||||||
|
.pinLeading()
|
||||||
|
.pinTrailing()
|
||||||
|
.width(8)
|
||||||
|
.height(8)
|
||||||
|
.pinCenterY()
|
||||||
|
|
||||||
stackView.addArrangedSubview(indicatorView)
|
stackView.addArrangedSubview(indicatorView)
|
||||||
|
|
||||||
// update indicator
|
// update indicator
|
||||||
indicatorView.backgroundColor = drawSemiCircle ? .clear : (clearFullCircle ? .clear : color)
|
indicatorView.backgroundColor = drawSemiCircle ? .clear : (clearFullCircle ? .clear : color)
|
||||||
indicatorView.layer.borderColor = color.cgColor
|
indicatorView.layer.borderColor = color.cgColor
|
||||||
|
|
||||||
self.layoutIfNeeded()
|
layoutIfNeeded()
|
||||||
|
|
||||||
indicatorView.layer.cornerRadius = indicatorView.frame.size.height / 2.0
|
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 }
|
guard indicatorView.layer.sublayers?.contains(shapeLayer) ?? true else { return }
|
||||||
indicatorView.layer.addSublayer(shapeLayer)
|
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,7 +65,6 @@ class CalendarFooterReusableView: UICollectionReusableView {
|
|||||||
|
|
||||||
addSubview(containerView)
|
addSubview(containerView)
|
||||||
containerView
|
containerView
|
||||||
// .pinTop(VDSLayout.space6X)
|
|
||||||
.pinTopLessThanOrEqualTo(topAnchor, VDSLayout.space6X, .defaultLow)
|
.pinTopLessThanOrEqualTo(topAnchor, VDSLayout.space6X, .defaultLow)
|
||||||
.pinBottom()
|
.pinBottom()
|
||||||
.pinLeadingGreaterThanOrEqualTo(leadingAnchor, VDSLayout.space3X, .defaultHigh)
|
.pinLeadingGreaterThanOrEqualTo(leadingAnchor, VDSLayout.space3X, .defaultHigh)
|
||||||
@ -99,7 +98,11 @@ extension CalendarFooterReusableView: UICollectionViewDelegate, UICollectionView
|
|||||||
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LegendCollectionViewCell.identifier, for: indexPath) as? LegendCollectionViewCell,
|
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: LegendCollectionViewCell.identifier, for: indexPath) as? LegendCollectionViewCell,
|
||||||
indexPath.row <= items.count else { return UICollectionViewCell() }
|
indexPath.row <= items.count else { return UICollectionViewCell() }
|
||||||
let text = items[indexPath.row].label
|
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
|
return cell
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -153,7 +153,7 @@ class CalendarHeaderReusableView: UICollectionReusableView {
|
|||||||
|
|
||||||
/// Updating UI based on next/previous clicks along with surface.
|
/// Updating UI based on next/previous clicks along with surface.
|
||||||
/// Updating UI to enable/disable the next & previous buttons, updating header title.
|
/// 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
|
self.surface = surface
|
||||||
headerTitle.surface = surface
|
headerTitle.surface = surface
|
||||||
previousButton.surface = surface
|
previousButton.surface = surface
|
||||||
@ -161,7 +161,7 @@ class CalendarHeaderReusableView: UICollectionReusableView {
|
|||||||
nextButton.isEnabled = nextEnabled
|
nextButton.isEnabled = nextEnabled
|
||||||
previousButton.isEnabled = previousEnabled
|
previousButton.isEnabled = previousEnabled
|
||||||
daysCollectionView.reloadData()
|
daysCollectionView.reloadData()
|
||||||
let labelText = aDate.getMonthName(date: aDate) + " \(aDate.yearInt)"
|
let labelText = date.getMonthName() + " \(date.yearInt)"
|
||||||
headerTitle.text = labelText
|
headerTitle.text = labelText
|
||||||
headerTitle.textColor = headerTitleTextColorConfiguration.getColor(surface)
|
headerTitle.textColor = headerTitleTextColorConfiguration.getColor(surface)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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 {
|
var startOfMonth: Date {
|
||||||
Calendar.current.dateInterval(of: .month, for: self)!.start
|
Calendar.current.dateInterval(of: .month, for: self)!.start
|
||||||
}
|
}
|
||||||
@ -45,7 +33,7 @@ public extension Date {
|
|||||||
|
|
||||||
/// Get the number of days of the month
|
/// Get the number of days of the month
|
||||||
var numberOfDaysInMonth: Int {
|
var numberOfDaysInMonth: Int {
|
||||||
Calendar.current.component(.day, from: endOfMonth)
|
Calendar.current.range(of: .day, in: .month, for: self)!.count
|
||||||
}
|
}
|
||||||
|
|
||||||
var firstWeekDayBeforeStart: Date {
|
var firstWeekDayBeforeStart: Date {
|
||||||
@ -98,9 +86,22 @@ public extension Date {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the month name of the given date
|
/// Returns the month name of the given date
|
||||||
func getMonthName(date: Date) -> String {
|
func getMonthName() -> String {
|
||||||
let names = Date.fullMonthNames
|
let dateFormatter = DateFormatter()
|
||||||
return names[date.monthInt - 1]
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user