JTAppleCalendar
JTAppleCalendar copied to clipboard
Future date is not getting disabled in a single selection as well as in range selection
(Required) Version Number: 8.0.5
Description
I have to disable the future dates in two calendars in which dailyCalendarView has single selection and weeklyCalendarView has range selection.
but the issue is sometimes future dates are not getting disabled. Also, how do I allow users to select only 7 dates in weeklyCalendarView? @IBAction func onClear(_ sender: UIButton) { self.dailyCalendarView.deselectAllDates() self.weeklyCalendarView.deselectAllDates() } this code is also not working.
https://github.com/patchthecode/JTAppleCalendar/assets/130362429/7c1fae36-6f3e-49d2-a916-498fd6b637f6
https://github.com/patchthecode/JTAppleCalendar/assets/130362429/76f04525-7415-40eb-827b-ba6a835a1c47
Steps To Reproduce
` import UIKit import JTAppleCalendar
class InsightsFilterScreen: BottomPopupViewController { // MARK: - Outlets //UIButton @IBOutlet weak var dailyMonthButton: UIButton! @IBOutlet weak var dailyYearButton: UIButton! @IBOutlet weak var weeklyMonthButton: UIButton! @IBOutlet weak var weeklyYearButton: UIButton!
//UIView
@IBOutlet weak var contentView: UIView!
@IBOutlet weak var dailyView: UIView!
@IBOutlet weak var weeklyView: UIView!
@IBOutlet weak var monthlyView: UIView!
//JTACMonthView
@IBOutlet weak var dailyCalendarView: JTACMonthView!
@IBOutlet weak var weeklyCalendarView: JTACMonthView!
//UISegmentedControl
@IBOutlet weak var insightsSegmentedControl: UISegmentedControl!
//UILabel
@IBOutlet weak var yearLabel: UILabel!
//UICollectionView
@IBOutlet weak var yearCollectionView: UICollectionView!
// MARK: BottomPopupAttributesDelegate Variables
//Bottom Popup Alert configurations
var height: CGFloat?
var topCornerRadius: CGFloat?
var presentDuration: Double?
var dismissDuration: Double?
var shouldDismissInteractivelty: Bool?
var dimmingViewDefaultAlphaValue: CGFloat?
override var popupHeight: CGFloat { height ?? SCREEN_HEIGHT }
override var popupTopCornerRadius: CGFloat { topCornerRadius ?? 0.0 } //10.0
override var popupPresentDuration: Double { presentDuration ?? 0.4 }
override var popupDismissDuration: Double { dismissDuration ?? 0.4 } // 1.0
override var popupShouldDismissInteractivelty: Bool { shouldDismissInteractivelty ?? false }
override var popupDimmingViewAlpha: CGFloat { dimmingViewDefaultAlphaValue ?? 0.30 }
// MARK: - Variables
var hasStrictBoundaries = true
var generateInDates: InDateCellGeneration = .forAllMonths
var generateOutDates: OutDateCellGeneration = .off
var allScrollModes: [ScrollingMode] = [
.none,
.nonStopTo(customInterval: 374, withResistance: 0.5),
.nonStopToCell(withResistance: 0.5),
.nonStopToSection(withResistance: 0.5),
.stopAtEach(customInterval: 374),
.stopAtEachCalendarFrame,
.stopAtEachSection
]
// MARK: - Daily
var dailyCalendar = Calendar.current
var dailyCurrentScrollModeIndex = 0
var dailyStartSelectedNSDate = Date()
var dailySelectedDatesArray:[String] = []
var dailyStartSelectedDate = "2020 01 01"
let dailyFormatter = DateFormatter()
// MARK: - Week
var weekCalendar = Calendar.current
var weekCurrentScrollModeIndex = 0
var weekStartSelectedNSDate = Date()
var weekSelectedDatesArray:[String] = []
var weekStartSelectedDate = "2020 01 01"
let weekFormatter = DateFormatter()
// MARK: - Methods
override func viewDidLoad() {
super.viewDidLoad()
self.initialDetails()
}
// MARK: - Functions
// MARK: - Initial Details
func initialDetails() {
self.contentView.roundCorners([.topLeft, .topRight], radius: 20.0)
self.setUpSegmentControl()
self.setUpWeeklyCalendar()
self.setUpDailyCalendar()
}
// MARK: - Set Up Daily Calendar
func setUpDailyCalendar() {
self.dailyCalendarView.calendarDelegate = self
self.dailyCalendarView.calendarDataSource = self
self.dailyCalendarView.scrollDirection = .horizontal
self.dailyCalendarView.allowsMultipleSelection = false
self.dailyCalendarView.scrollToDate(Date(),animateScroll: false)
// self.calendarCollection.selectDates([Date()])
self.dailyCalendarView.visibleDates {[unowned self] (visibleDates: DateSegmentInfo) in
self.setupViewsOfDailyCalendar(from: visibleDates)
}
self.setupScrollModeForDailyCalendar()
}
// MARK: - Set Up Views of Daily Calendar
func setupViewsOfDailyCalendar(from visibleDates: DateSegmentInfo) {
guard let startDate = visibleDates.monthDates.first?.date else {
return
}
let month = self.dailyCalendar.dateComponents([.month], from: startDate).month!
// let monthName = DateFormatter().monthSymbols[(month-1) % 12]
let monthName = self.dailyCalendar.monthSymbols[month - 1]
// 0 indexed array
let year = self.dailyCalendar.component(.year, from: startDate)
self.dailyMonthButton.setTitle(monthName, for: .normal)
self.dailyYearButton.setTitle(String(year), for: .normal)
}
// MARK: - Set Up Scroll Mode for Daily Calendar
func setupScrollModeForDailyCalendar() {
self.dailyCurrentScrollModeIndex = 6
self.dailyCalendarView.scrollingMode = self.allScrollModes[self.dailyCurrentScrollModeIndex]
}
// MARK: - Set Up Weekly Calendar
func setUpWeeklyCalendar() {
self.weeklyCalendarView.calendarDelegate = self
self.weeklyCalendarView.calendarDataSource = self
self.weeklyCalendarView.scrollDirection = .horizontal
self.weeklyCalendarView.allowsMultipleSelection = true
self.weeklyCalendarView.allowsRangedSelection = true
self.weeklyCalendarView.rangeSelectionMode = .continuous
self.weeklyCalendarView.scrollToDate(Date(),animateScroll: false)
// self.calendarCollection.selectDates([Date()])
self.weeklyCalendarView.visibleDates {[unowned self] (visibleDates: DateSegmentInfo) in
self.setupViewsOfWeeklyCalendar(from: visibleDates)
}
self.setupScrollModeForWeeklyCalendar()
}
// MARK: - Set Up Views of Weekly Calendar
func setupViewsOfWeeklyCalendar(from visibleDates: DateSegmentInfo) {
guard let startDate = visibleDates.monthDates.first?.date else {
return
}
let month = self.weekCalendar.dateComponents([.month], from: startDate).month!
// let monthName = DateFormatter().monthSymbols[(month-1) % 12]
let monthName = self.weekCalendar.monthSymbols[month - 1]
// 0 indexed array
let year = self.weekCalendar.component(.year, from: startDate)
self.weeklyMonthButton.setTitle(monthName, for: .normal)
self.weeklyYearButton.setTitle(String(year), for: .normal)
}
// MARK: - Set Up Scroll Mode for Weekly Calendar
func setupScrollModeForWeeklyCalendar() {
self.weekCurrentScrollModeIndex = 6
self.weeklyCalendarView.scrollingMode = self.allScrollModes[self.weekCurrentScrollModeIndex]
}
// MARK: - Set up Segment Control
func setUpSegmentControl() {
self.insightsSegmentedControl.selectedSegmentIndex = 1
//set color
UISegmentedControl.appearance().setTitleTextAttributes(
[.foregroundColor: UIColor { tc in
switch tc.userInterfaceStyle {
case .dark:
return UtilityMethodsCommon.hexStringToUIColor(hex: "#FCF4F4")
default:
return UtilityMethodsCommon.hexStringToUIColor(hex: "#141414")
}
}
], for: .normal)
UISegmentedControl.appearance().setTitleTextAttributes(
[.foregroundColor: UIColor { tc in
switch tc.userInterfaceStyle {
case .dark:
return UtilityMethodsCommon.hexStringToUIColor(hex: "#212121")
default:
return UIColor.white
}
}
], for: .selected)
//set font
UISegmentedControl.appearance().setTitleTextAttributes([.font: UIFont(name: "Poppins-Regular", size: 15) ?? UIFont()], for: .normal)
}
// MARK: - IBActions
@IBAction func onBack(_ sender: UIButton) {
self.dismiss(animated: true)
}
@IBAction func onClear(_ sender: UIButton) {
self.dailyCalendarView.deselectAllDates()
self.weeklyCalendarView.deselectAllDates()
}
@IBAction func onSegment(_ sender: UISegmentedControl) {
self.onSegmentControl()
}
@IBAction func onDailyMonth(_ sender: UIButton) {
}
@IBAction func onDailyYear(_ sender: UIButton) {
}
@IBAction func onWeeklyMonth(_ sender: UIButton) {
}
@IBAction func onWeeklyYear(_ sender: UIButton) {
}
//Daily
@IBAction func onDailySave(_ sender: UIButton) {
}
//Monthly
@IBAction func onMonthlySave(_ sender: UIButton) {
}
@IBAction func onPrevious(_ sender: UIButton) {
}
@IBAction func onNext(_ sender: UIButton) {
}
@IBAction func onYearlySave(_ sender: UIButton) {
}
// MARK: - Segment Control Action
func onSegmentControl() {
let views = [self.dailyView, self.weeklyView, self.monthlyView]
let selectedIndex = self.insightsSegmentedControl.selectedSegmentIndex
for (index, view) in views.enumerated() {
view?.isHidden = index != selectedIndex
}
}
}
// MARK: - JTACMonthView DataSource extension InsightsFilterScreen: JTACMonthViewDataSource { func configureCalendar(_ calendar: JTACMonthView) -> ConfigurationParameters {
switch calendar {
case self.dailyCalendarView:
self.dailyFormatter.dateFormat = "yyyy-MM-dd"
self.dailyFormatter.timeZone = self.dailyCalendar.timeZone
self.dailyFormatter.locale = self.dailyCalendar.locale
let startDate = self.dailyFormatter.date(from: "2023-01-01")!
let endDate = Date()
let parameters = ConfigurationParameters(startDate: startDate,
endDate: endDate,
numberOfRows: 6,
calendar: self.dailyCalendar,
generateInDates: generateInDates,
generateOutDates: generateOutDates,
firstDayOfWeek: .sunday,
hasStrictBoundaries: true)
return parameters
case self.weeklyCalendarView:
self.weekFormatter.dateFormat = "yyyy-MM-dd"
self.weekFormatter.timeZone = self.weekCalendar.timeZone
self.weekFormatter.locale = self.weekCalendar.locale
let startDate = self.weekFormatter.date(from: "2023-01-01")!
let endDate = Date()
let parameters = ConfigurationParameters(startDate: startDate,
endDate: endDate,
numberOfRows: 6,
calendar: self.weekCalendar,
generateInDates: generateInDates,
generateOutDates: generateOutDates,
firstDayOfWeek: .sunday,
hasStrictBoundaries: true)
return parameters
default:
break
}
return ConfigurationParameters(startDate: Date(), endDate: Date())
}
}
// MARK: - JTACMonthView Delegate extension InsightsFilterScreen: JTACMonthViewDelegate { func calendar(_ calendar: JTACMonthView, cellForItemAt date: Date, cellState: CellState, indexPath: IndexPath) -> JTACDayCell {
switch calendar {
case self.dailyCalendarView:
if let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "DailyDateCell", for: indexPath) as? DailyDateCell {
cell.cellView.clipsToBounds = true
cell.cellView.layer.cornerRadius = cell.cellView.frame.height/2
cell.dateLabel.text = cellState.text
if self.dailyFormatter.string(from: Date()) < self.dailyFormatter.string(from: date) {
cell.dateLabel.textColor = .black.withAlphaComponent(0.5)
} else {
cell.dateLabel.textColor = .black
}
self.calendar(calendar, willDisplay: cell, forItemAt: date, cellState: cellState, indexPath: indexPath)
return cell
}
return JTACDayCell()
case self.weeklyCalendarView:
if let cell = calendar.dequeueReusableJTAppleCell(withReuseIdentifier: "WeeklyDateCell", for: indexPath) as? WeeklyDateCell {
cell.cellView.clipsToBounds = true
cell.cellView.layer.cornerRadius = cell.cellView.frame.height/2
cell.dateLabel.text = cellState.text
if self.weekFormatter.string(from: Date()) < self.weekFormatter.string(from: date) {
cell.dateLabel.textColor = .black.withAlphaComponent(0.5)
} else {
cell.dateLabel.textColor = .black
}
self.calendar(calendar, willDisplay: cell, forItemAt: date, cellState: cellState, indexPath: indexPath)
return cell
}
return JTACDayCell()
default:
break
}
return JTACDayCell()
}
func calendar(_ calendar: JTACMonthView, willDisplay cell: JTACDayCell, forItemAt date: Date, cellState: CellState, indexPath: IndexPath) {
switch calendar {
case self.dailyCalendarView:
let myCustomCell = cell as! DailyDateCell
self.configureVisibleDailyCell(myCustomCell: myCustomCell, cellState: cellState, date: date, indexPath: indexPath)
if cellState.dateBelongsTo == .thisMonth {
myCustomCell.isHidden = false
} else {
myCustomCell.isHidden = true
}
case self.weeklyCalendarView:
let myCustomCell = cell as! WeeklyDateCell
self.configureVisibleWeeklyCell(myCustomCell: myCustomCell, cellState: cellState, date: date, indexPath: indexPath)
if cellState.dateBelongsTo == .thisMonth {
myCustomCell.isHidden = false
} else {
myCustomCell.isHidden = true
}
default:
break
}
}
func calendar(_ calendar: JTACMonthView, willScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
switch calendar {
case self.dailyCalendarView:
self.setupViewsOfDailyCalendar(from: visibleDates)
case self.weeklyCalendarView:
self.setupViewsOfWeeklyCalendar(from: visibleDates)
default:
break
}
}
func calendar(_ calendar: JTACMonthView, didScrollToDateSegmentWith visibleDates: DateSegmentInfo) {
switch calendar {
case self.dailyCalendarView:
self.setupViewsOfDailyCalendar(from: visibleDates)
case self.weeklyCalendarView:
self.setupViewsOfWeeklyCalendar(from: visibleDates)
default:
break
}
}
func calendar(_ calendar: JTACMonthView, shouldSelectDate date: Date, cell: JTACDayCell?, cellState: CellState) -> Bool {
return date < Date()
}
func calendar(_ calendar: JTACMonthView, didSelectDate date: Date, cell: JTACDayCell?, cellState: CellState) {
switch calendar {
case self.dailyCalendarView:
self.handleCellSelectionForDaily(view: cell, cellState: cellState)
case self.weeklyCalendarView:
self.handleCellSelectionForWeekly(view: cell, cellState: cellState)
default:
break
}
}
func calendar(_ calendar: JTACMonthView, didDeselectDate date: Date, cell: JTACDayCell?, cellState: CellState) {
switch calendar {
case self.dailyCalendarView:
self.handleCellSelectionForDaily(view: cell, cellState: cellState)
case self.weeklyCalendarView:
self.handleCellSelectionForWeekly(view: cell, cellState: cellState)
default:
break
}
}
func calendar(_ calendar: JTACMonthView, didDeselectDate date: Date, cell: JTACDayCell?, cellState: CellState, indexPath: IndexPath) {
if self.dailyView.isHidden == false {
if self.dailyFormatter.string(from: Date()) < self.dailyFormatter.string(from: date) {
return
}
} else if self.weeklyView.isHidden == false {
if self.weekFormatter.string(from: Date()) < self.weekFormatter.string(from: date) {
return
}
}
switch calendar {
case self.dailyCalendarView:
self.addOrRemove(value: self.dailyFormatter.string(from: date), in: &dailySelectedDatesArray)
self.dailyCalendarView.reloadData()
self.handleCellSelectionForDaily(view: cell, cellState: cellState)
case self.weeklyCalendarView:
self.addOrRemove(value: self.weekFormatter.string(from: date), in: &weekSelectedDatesArray)
self.weeklyCalendarView.reloadData()
self.handleCellSelectionForWeekly(view: cell, cellState: cellState)
default:
break
}
}
func calendar(_ calendar: JTACMonthView, didSelectDate date: Date, cell: JTACDayCell?, cellState: CellState, indexPath: IndexPath) {
if self.dailyView.isHidden == false {
if self.dailyFormatter.string(from: Date()) < self.dailyFormatter.string(from: date) {
return
}
} else if self.weeklyView.isHidden == false {
if self.weekFormatter.string(from: Date()) < self.weekFormatter.string(from: date) {
return
}
}
switch calendar {
case self.dailyCalendarView:
self.dailyStartSelectedNSDate = date
self.dailyStartSelectedDate = self.dailyFormatter.string(from: date)
self.addOrRemove(value: self.dailyFormatter.string(from: date), in: &dailySelectedDatesArray)
self.dailyCalendarView.reloadData()
self.handleCellSelectionForDaily(view: cell, cellState: cellState)
#if DEBUG print("dailyFormatter --> (self.dailyFormatter.string(from: date))") #endif case self.weeklyCalendarView: self.weekStartSelectedNSDate = date self.weekStartSelectedDate = self.weekFormatter.string(from: date) self.addOrRemove(value: self.weekFormatter.string(from: date), in: &weekSelectedDatesArray)
self.weeklyCalendarView.reloadData()
self.handleCellSelectionForWeekly(view: cell, cellState: cellState)
#if DEBUG print("weekFormatter --> (self.weekFormatter.string(from: date))") #endif default: break } }
func handleCellSelectionForWeekly(view: JTACDayCell?, cellState: CellState) {
guard let cell = view as? WeeklyDateCell else {
return
}
cell.cellView.isHidden = !cellState.isSelected
switch cellState.selectedPosition() {
case .left:
cell.cellView.layer.cornerRadius = cell.cellView.frame.height/2
cell.cellView.layer.maskedCorners = [.layerMinXMaxYCorner, .layerMinXMinYCorner]
case .middle:
cell.cellView.layer.cornerRadius = 0
cell.cellView.layer.maskedCorners = []
case .right:
cell.cellView.layer.cornerRadius = cell.cellView.frame.height/2
cell.cellView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner]
case .full:
cell.cellView.layer.cornerRadius = cell.cellView.frame.height/2
cell.cellView.layer.maskedCorners = [.layerMaxXMaxYCorner, .layerMaxXMinYCorner, .layerMinXMaxYCorner, .layerMinXMinYCorner]
default: break
}
}
func handleCellSelectionForDaily(view: JTACDayCell?, cellState: CellState) {
guard let myCustomCell = view as? DailyDateCell else {
return
}
if cellState.isSelected {
myCustomCell.cellView.backgroundColor = #colorLiteral(red: 0.2901960784, green: 0.3098039216, blue: 0.968627451, alpha: 1)
} else {
myCustomCell.cellView.backgroundColor = .clear
}
myCustomCell.isHidden = cellState.dateBelongsTo != .thisMonth
}
func configureVisibleDailyCell(myCustomCell: DailyDateCell, cellState: CellState, date: Date, indexPath: IndexPath) {
handleCellSelectionForDaily(view: myCustomCell, cellState: cellState)
}
func configureVisibleWeeklyCell(myCustomCell: WeeklyDateCell, cellState: CellState, date: Date, indexPath: IndexPath) {
handleCellSelectionForWeekly(view: myCustomCell, cellState: cellState)
}
func addOrRemove<T: Equatable>(value: T, in array: inout [T]) {
if let index = array.firstIndex(of: value) {
array.remove(at: index)
} else {
array.append(value)
}
}
} `
Expected Behavior
I want to disable future dates. I want to allow users to select only 7 dates in weeklyCalendarView. I want to have a start date and end date in range selection like this:
on clear button all the selected dates should get deselected at one time.
Additional Context
I am constantly trying from the last two days to resolve this issue, Also there is no documentation here on how to create your custom calendar. If anyone could guide me I would be really grateful.
Thank you!