From 28d8161d09aea73fb93093d5af428682073d9fa2 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Mon, 13 May 2024 13:12:07 -0500 Subject: [PATCH] refactored date picker a popover Signed-off-by: Matt Bruce --- VDS/Components/DatePicker/DatePicker.swift | 85 ++++++++++++++++------ 1 file changed, 64 insertions(+), 21 deletions(-) diff --git a/VDS/Components/DatePicker/DatePicker.swift b/VDS/Components/DatePicker/DatePicker.swift index a7dc3e29..cd4b3777 100644 --- a/VDS/Components/DatePicker/DatePicker.swift +++ b/VDS/Components/DatePicker/DatePicker.swift @@ -5,7 +5,7 @@ import Combine /// A dropdown select is an expandable menu of predefined options that allows a customer to make a single selection. @objc(VDSDatePicker) -open class DatePicker: EntryFieldBase { +open class DatePicker: EntryFieldBase, DatePickerPopoverViewControllerDelegate, UIPopoverPresentationControllerDelegate { //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- @@ -31,9 +31,7 @@ open class DatePicker: EntryFieldBase { // MARK: - Private Properties //-------------------------------------------------- internal var minWidthDefault = 186.0 - - internal let picker = UIDatePicker() - + internal var bottomStackView: UIStackView = { return UIStackView().with { $0.translatesAutoresizingMaskIntoConstraints = false @@ -103,10 +101,6 @@ open class DatePicker: EntryFieldBase { selectedDateLabel.textColorConfiguration = primaryColorConfiguration.eraseToAnyColorable() // setup the calendar - picker.datePickerMode = .date - picker.preferredDatePickerStyle = .inline - picker.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged) - picker.isHidden = true // tap gesture fieldStackView @@ -128,19 +122,12 @@ open class DatePicker: EntryFieldBase { controlStackView.addArrangedSubview(selectedDateLabel) return controlStackView } - - open override func getBottomContainer() -> UIView { - bottomStackView.addArrangedSubview(bottomContainerStackView) - bottomStackView.addArrangedSubview(picker) - return bottomStackView - } - + /// Used to make changes to the View based off a change events or from local properties. open override func updateView() { super.updateView() if let selectedDate { - picker.date = selectedDate formatDate(selectedDate) } @@ -162,13 +149,69 @@ open class DatePicker: EntryFieldBase { } internal func togglePicker() { - picker.isHidden = !picker.isHidden - bottomContainerStackView.isHidden = !bottomContainerStackView.isHidden + let calendarVC = DatePickerPopoverViewController(calendar: Calendar(identifier: .gregorian), delegate: self) + calendarVC.modalPresentationStyle = .popover + calendarVC.selectedDate = selectedDate ?? Date() + if let popoverController = calendarVC.popoverPresentationController { + popoverController.delegate = self + popoverController.sourceView = containerView + popoverController.sourceRect = containerView.bounds + popoverController.permittedArrowDirections = .any + } + if let viewController = UIApplication.topViewController() { + viewController.present(calendarVC, animated: true, completion: nil) + } } - @objc private func dateChanged(_ sender: UIDatePicker) { - selectedDate = sender.date + internal func didSelectDate(_ controller: DatePickerPopoverViewController, date: Date) { + selectedDate = date + controller.dismiss(animated: true) sendActions(for: .valueChanged) - togglePicker() + } + + public func adaptivePresentationStyle(for controller: UIPresentationController) -> UIModalPresentationStyle { + return .none + } +} + +protocol DatePickerPopoverViewControllerDelegate: NSObject { + func didSelectDate(_ controller: DatePickerPopoverViewController, date: Date) +} + +class DatePickerPopoverViewController: UIViewController { + + private let picker = UIDatePicker() + weak var delegate: DatePickerPopoverViewControllerDelegate? + + init(calendar: Calendar, delegate: DatePickerPopoverViewControllerDelegate?) { + self.delegate = delegate + super.init(nibName: nil, bundle: nil) + picker.datePickerMode = .date + picker.preferredDatePickerStyle = .inline + picker.addTarget(self, action: #selector(dateChanged(_:)), for: .valueChanged) + } + + var selectedDate: Date = Date() { + didSet { + picker.date = selectedDate + } + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func loadView() { + view = picker + view.backgroundColor = .white + } + + override func viewDidLoad() { + super.viewDidLoad() + preferredContentSize = CGSize(width: 300, height: 400) // Adjust as needed + } + + @objc private func dateChanged(_ sender: UIDatePicker) { + delegate?.didSelectDate(self, date: sender.date) } }