// // DatePickerViewController.swift // VDSSample // // Created by Matt Bruce on 4/11/24. // import Foundation import VDS import UIKit class DatePickerViewController: BaseViewController { // Datepicker var label = Label() var disabledSwitch = Toggle() var requiredSwitch = Toggle() var labelTextField = TextField() var errorTextField = TextField() var helperTextField = TextField() var inlineLabelSwitch = Toggle() var readonlySwitch = Toggle() var transparentBgSwitch = Toggle() var errorSwitch = Toggle() var widthTextField = NumericField() var tooltipTitleTextField = TextField() var tooltipContentTextField = TextField() lazy var dateFormatPickerSelectorView = { PickerSelectorView(title: "shortNumeric", picker: self.picker, items: DatePicker.DateFormat.allCases ) }() // Calendar //props var indicators: [CalendarBase.CalendarIndicatorModel] = [] var activeDates: [Date] = [] var inactiveDates: [Date] = [] var minDate: Date = Date().startOfMonth var maxDate: Date = Date().endOfMonth //form var containerBorderSwitch = Toggle() var hideCurrentDateIndicatorSwitch = Toggle() var indicatorOneSwitch = Toggle() var indicatorTwoSwitch = Toggle() var indicatorThreeSwitch = Toggle() var clearActiveDatesSwitch = Toggle() var clearInactiveDatesSwitch = Toggle() var activeDatesField = TextField() var inactiveDatesField = TextField() var legendOneField = TextField() var legendTwoField = TextField() var legendThreeField = TextField() private var minDatePicker: UIDatePicker = UIDatePicker() private var maxDatePicker: UIDatePicker = UIDatePicker() private var indicatorOnePicker: UIDatePicker = UIDatePicker() private var indicatorTwoPicker: UIDatePicker = UIDatePicker() private var indicatorThreePicker: UIDatePicker = UIDatePicker() private var activeDatePicker: UIDatePicker = UIDatePicker().with { $0.datePickerMode = .date } private var inactiveDatePicker: UIDatePicker = UIDatePicker().with { $0.datePickerMode = .date } let indicatorOnePickerTag = 1 let indicatorTwoPickerTag = 2 let indicatorThreePickerTag = 3 let minDatePickerTag = 4 let maxDatePickerTag = 5 let activeDatePickerTag = 6 let inactiveDatePickerTag = 7 override func viewDidLoad() { super.viewDidLoad() addContentTopView(view: component) setupModel() setupPicker() setupCalendar() } override func setupForm(){ addFormRow(label: "onChange", view: label) addFormRow(label: "Surface", view: surfacePickerSelectorView) addFormRow(label: "Disabled", view: disabledSwitch) addFormRow(label: "Readonly", view: readonlySwitch) addFormRow(label: "Required", view: requiredSwitch) addFormRow(label: "Date Format", view: dateFormatPickerSelectorView) addFormRow(label: "Label Text", view: labelTextField) addFormRow(label: "Helper Text", view: helperTextField) addFormRow(label: "Transparent Background", view: transparentBgSwitch) addFormRow(label: "Error", view: .makeWrapper(for: errorSwitch)) addFormRow(label: "Error Text", view: errorTextField) addFormRow(label: "Width", view: widthTextField) addFormRow(label: "ToolTip Title", view: tooltipTitleTextField) addFormRow(label: "ToolTip Content", view: tooltipContentTextField) append(section: getCalendarSection()) disabledSwitch.onChange = { [weak self] sender in self?.component.isEnabled = !sender.isOn } requiredSwitch.onChange = { [weak self] sender in self?.component.isRequired = sender.isOn } readonlySwitch.onChange = { [weak self] sender in self?.component.isReadOnly = sender.isOn } transparentBgSwitch.onChange = { [weak self] sender in self?.component.transparentBackground = sender.isOn } errorSwitch .publisher(for: .valueChanged) .sink { [weak self] sender in guard let self else { return } component.showError = sender.isOn if component.showError != sender.isOn { self.errorSwitch.isOn = self.component.showError } }.store(in: &subscribers) labelTextField .textPublisher .sink { [weak self] text in self?.component.labelText = text }.store(in: &subscribers) helperTextField .textPublisher .sink { [weak self] text in self?.component.helperText = text }.store(in: &subscribers) errorTextField .textPublisher .sink { [weak self] text in self?.component.errorText = text }.store(in: &subscribers) widthTextField .numberPublisher .sink { [weak self] number in self?.component.width = number?.cgFloatValue }.store(in: &subscribers) tooltipTitleTextField .textPublisher .sink { [weak self] text in self?.updateTooltip() }.store(in: &subscribers) tooltipContentTextField .textPublisher .sink { [weak self] text in self?.updateTooltip() }.store(in: &subscribers) } func setupModel() { component.selectedDate = Calendar.current.date(byAdding: .day, value: -5, to: Date()) component.labelText = "Date" component.helperText = "Pick a date for your needs." component.errorText = "Enter a date." component.tooltipModel = .init(title: "Check your date.", content:"Here is the content for your date component") component.onChange = { [weak self] control in self?.label.text = DateFormatter.localizedString(from: control.selectedDate!, dateStyle: .short, timeStyle: .none) } //setup UI disabledSwitch.isOn = !component.isEnabled requiredSwitch.isOn = component.isRequired surfacePickerSelectorView.text = component.surface.rawValue labelTextField.text = component.labelText helperTextField.text = component.helperText readonlySwitch.isOn = false transparentBgSwitch.isOn = false errorSwitch.isOn = component.showError errorTextField.text = component.errorText tooltipTitleTextField.text = component.tooltipModel?.title tooltipContentTextField.text = component.tooltipModel?.content } func setupPicker() { surfacePickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.surface = item self?.contentTopView.backgroundColor = item.color } dateFormatPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.dateFormat = item } } func updateTooltip() { let title = tooltipTitleTextField.text ?? "" let content = tooltipContentTextField.text ?? "" component.tooltipModel = !title.isEmpty || !content.isEmpty ? .init(title: title, content: content) : nil } } extension DatePickerViewController { func getCalendarSection() -> FormSection { let section = FormSection() section.title = "Calendar Options" section.addFormRow(label: "Hide Container Border", view: containerBorderSwitch) section.addFormRow(label: "Hide Current Date Indicator", view: hideCurrentDateIndicatorSwitch) section.addFormRow(label: "Min Date", view: minDatePicker) section.addFormRow(label: "Max Date", view: maxDatePicker) section.addFormRow(label: "Active Dates", view: activeDatesField) section.addFormRow(label: "Select ActiveDate", view: activeDatePicker) section.addFormRow(label: "Clear Active Dates", view: clearActiveDatesSwitch) section.addFormRow(label: "Inactive Dates", view: inactiveDatesField) section.addFormRow(label: "Select InActiveDate", view: inactiveDatePicker) section.addFormRow(label: "Clear Inactive Dates", view: clearInactiveDatesSwitch) section.addFormRow(label: "Indicator One", view: indicatorOneSwitch) section.addFormRow(label: "Indicator Two", view: indicatorTwoSwitch) section.addFormRow(label: "Indicator Three", view: indicatorThreeSwitch) section.addFormRow(label: "Legend One", view: legendOneField) section.addFormRow(label: "Legend Two", view: legendTwoField) section.addFormRow(label: "Legend Three", view: legendThreeField) section.addFormRow(label: "Indicator One Date", view: indicatorOnePicker) section.addFormRow(label: "Indicator Two Date", view: indicatorTwoPicker) section.addFormRow(label: "Indicator Three Date", view: indicatorThreePicker) containerBorderSwitch.onChange = { [weak self] sender in self?.updateCalendarModel() } hideCurrentDateIndicatorSwitch.onChange = { [weak self] sender in self?.updateCalendarModel() } clearActiveDatesSwitch.onChange = { [weak self] sender in self?.updateCalendarModel() } clearInactiveDatesSwitch.onChange = { [weak self] sender in self?.updateCalendarModel() } legendOneField .textPublisher .sink { [weak self] text in self?.updateIndicatorData(label: text, date: self?.indicatorOnePicker.date, index: 0) }.store(in: &subscribers) legendTwoField .textPublisher .sink { [weak self] text in self?.updateIndicatorData(label: text, date: self?.indicatorTwoPicker.date, index: 1) }.store(in: &subscribers) legendThreeField .textPublisher .sink { [weak self] text in self?.updateIndicatorData(label: text, date: self?.indicatorThreePicker.date, index: 2) }.store(in: &subscribers) indicatorOneSwitch.onChange = { [weak self] sender in guard let self else { return } if !sender.isOn { self.indicators.removeAll() } else { self.setIndicatorsData() } self.updateCalendarModel() } indicatorTwoSwitch.onChange = { [weak self] sender in guard let self else { return } if !sender.isOn { if self.indicators.count > 2 { self.indicators.removeLast() self.indicators.removeLast() } else if self.indicators.count == 2 { self.indicators.removeLast() } } else { self.setIndicatorsData() } self.updateCalendarModel() } indicatorThreeSwitch.onChange = { [weak self] sender in guard let self else { return } if !sender.isOn { if self.indicators.count > 2 { self.indicators.removeLast() } } else { self.setIndicatorsData() } self.updateCalendarModel() } return section } func updateCalendarModel() { component.calendarModel = .init(surface: component.surface, hideContainerBorder: containerBorderSwitch.isOn, hideCurrentDateIndicator: hideCurrentDateIndicatorSwitch.isOn, activeDates: activeDates, inactiveDates: inactiveDates, minDate: minDate, maxDate: maxDate, indicators: indicators) } func setupCalendar() { configurePicker(indicatorOnePicker) indicatorOnePicker.tag = indicatorOnePickerTag configurePicker(indicatorTwoPicker) indicatorTwoPicker.tag = indicatorTwoPickerTag configurePicker(indicatorThreePicker) indicatorThreePicker.tag = indicatorThreePickerTag configurePicker(minDatePicker) minDatePicker.tag = minDatePickerTag configurePicker(maxDatePicker) maxDatePicker.tag = maxDatePickerTag configurePicker(activeDatePicker) activeDatePicker.tag = activeDatePickerTag configurePicker(inactiveDatePicker) inactiveDatePicker.tag = inactiveDatePickerTag indicators = [ .init(label: "Due Date", date: indicatorOnePicker.date), .init(label: "Auto Pay", date: indicatorTwoPicker.date), .init(label: "Scheduled", date: indicatorThreePicker.date) ] let calendar = Calendar.current let indicatorDate = calendar.startOfDay(for: calendar.date(byAdding: .day, value: 1, to: Date())!) legendOneField.text = "Due Date" legendTwoField.text = "Auto Pay" legendThreeField.text = "Scheduled" indicatorOneSwitch.isOn = true indicatorTwoSwitch.isOn = true indicatorThreeSwitch.isOn = true hideCurrentDateIndicatorSwitch.isOn = false indicatorOnePicker.date = indicatorDate indicatorTwoPicker.date = indicatorDate indicatorThreePicker.date = indicatorDate updateIndicatorData(label: legendOneField.text ?? "", date: indicatorOnePicker.date, index: 0) updateIndicatorData(label: legendTwoField.text ?? "", date: indicatorTwoPicker.date, index: 1) updateIndicatorData(label: legendThreeField.text ?? "", date: indicatorThreePicker.date, index: 2) activeDatesField.isUserInteractionEnabled = false inactiveDatesField.isUserInteractionEnabled = false activeDatesField.isEnabled = false inactiveDatesField.isEnabled = false minDatePicker.date = minDate maxDatePicker.date = maxDate updateCalendarModel() } func updateIndicatorData(label: String = "", date: Date?, index:Int) { indicators[index].label = label indicators[index].date = date ?? Date() updateCalendarModel() } func setIndicatorsData() { if indicatorOneSwitch.isOn && indicatorTwoSwitch.isOn && indicatorThreeSwitch.isOn { indicators = [ .init(label: self.legendOneField.text ?? "", date: indicatorOnePicker.date), .init(label: self.legendTwoField.text ?? "", date: indicatorTwoPicker.date), .init(label: self.legendThreeField.text ?? "", date: indicatorThreePicker.date) ] } else if indicatorOneSwitch.isOn && indicatorTwoSwitch.isOn && !indicatorThreeSwitch.isOn { indicators = [ .init(label: self.legendOneField.text ?? "", date: indicatorOnePicker.date), .init(label: self.legendTwoField.text ?? "", date: indicatorTwoPicker.date), ] } else if indicatorOneSwitch.isOn && !indicatorTwoSwitch.isOn { indicators = [ .init(label: self.legendOneField.text ?? "", date: indicatorOnePicker.date), ] } } func configurePicker(_ sender:UIDatePicker) { // Set some of UIDatePicker properties sender.timeZone = NSTimeZone.local sender.backgroundColor = UIColor.white // Add an event to call onDidChangeDate function when value is changed. sender.addTarget(self, action: #selector(self.datePickerValueChanged(_:)), for: .valueChanged) } @objc func datePickerValueChanged(_ sender: UIDatePicker){ switch sender.tag { case indicatorOnePickerTag: updateIndicatorData(label: legendOneField.text ?? "", date: sender.date, index: 0) case indicatorTwoPickerTag: updateIndicatorData(label: legendTwoField.text ?? "", date: sender.date, index: 1) case indicatorThreePickerTag: updateIndicatorData(label: legendThreeField.text ?? "", date: sender.date, index: 2) case minDatePickerTag: minDate = sender.date updateCalendarModel() case maxDatePickerTag: maxDate = sender.date updateCalendarModel() case activeDatePickerTag: activeDates.append(sender.date) var text = activeDatesField.text if let textEmpty = text?.isEmpty, textEmpty == true { text?.append("") } else { text?.append(", ") } text?.append("\(self.getSelectedDate(with: sender.date))") clearActiveDatesSwitch.isOn = false activeDatesField.text = text updateCalendarModel() case inactiveDatePickerTag: inactiveDates.append(sender.date) var text = inactiveDatesField.text if let textEmpty = text?.isEmpty, textEmpty == true { text?.append("") } else { text?.append(", ") } text?.append("\(self.getSelectedDate(with: sender.date))") clearInactiveDatesSwitch.isOn = false inactiveDatesField.text = text updateCalendarModel() default: break } } func getSelectedDate(with date:Date) -> String { let dateFormatter: DateFormatter = DateFormatter() dateFormatter.dateFormat = "MM/dd/yyyy" let day: String = dateFormatter.string(from: date) return day } }