Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Future date is not getting disabled in a single selection as well as in range selection #1401

Open
dimpy-iroid opened this issue Jun 11, 2024 · 3 comments

Comments

@dimpy-iroid
Copy link

(Required) Version Number: 8.0.5
Screenshot 2024-06-11 at 5 02 50 PM

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.

Simulator.Screen.Recording.-.iPhone.15.-.2024-06-11.at.17.41.17.mp4
Simulator.Screen.Recording.-.iPhone.15.-.2024-06-11.at.17.41.55.mp4

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:
image

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!

@patchthecode
Copy link
Owner

Its difficult to read this.
Is your project sharable?

@patchthecode
Copy link
Owner

Also have you checked this out?
#1319

@dimpy-iroid
Copy link
Author

dimpy-iroid commented Jun 12, 2024

Hello!
Thank you for your response, yes I have checked almost all the issues in the last 2 days. But I'm not able to fix the issue. Future dates are getting selected in some cases.
Could you please see attached zip file of my project?
CalendarApp.zip

Thank you!
Kindly see Expected Behaviour mentioned above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants