testing not using popover viewcontroller

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2024-06-21 13:30:19 -05:00
parent ce6aad5540
commit aad70d2e40
2 changed files with 182 additions and 35 deletions

View File

@ -19,6 +19,10 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
/// Popover presentation controller of the popover /// Popover presentation controller of the popover
private var popOver: UIPopoverPresentationController! private var popOver: UIPopoverPresentationController!
open var maxWidth: CGFloat?
open var sourceRect: CGRect?
open var spacing: CGFloat = 0 open var spacing: CGFloat = 0
/** /**
A controller that manages the popover. A controller that manages the popover.
@ -35,6 +39,7 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
self.contentView = contentView self.contentView = contentView
self.spacing = spacing self.spacing = spacing
self.arrow = arrow self.arrow = arrow
self.sourceRect = sourceRect
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
setupPopover(sourceView, sourceRect, barButtonItem) setupPopover(sourceView, sourceRect, barButtonItem)
} }
@ -65,7 +70,6 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
popOver.popoverBackgroundViewClass = ClearPopoverBackgroundView.self popOver.popoverBackgroundViewClass = ClearPopoverBackgroundView.self
popOver.sourceView = sourceView popOver.sourceView = sourceView
popOver.popoverLayoutMargins = .zero popOver.popoverLayoutMargins = .zero
if let sourceRect = sourceRect { if let sourceRect = sourceRect {
popOver.sourceRect = sourceRect popOver.sourceRect = sourceRect
} }
@ -85,11 +89,8 @@ open class ClearPopoverViewController: UIViewController, UIPopoverPresentationCo
private func updatePopoverPosition() { private func updatePopoverPosition() {
guard let popoverPresentationController = popoverPresentationController else { return } guard let popoverPresentationController = popoverPresentationController else { return }
if let sourceView = popoverPresentationController.sourceView { if let sourceView = popoverPresentationController.sourceView, let sourceRect {
popoverPresentationController.sourceRect = .init(x: sourceView.bounds.origin.x, popoverPresentationController.sourceRect = sourceRect
y: sourceView.bounds.origin.y,
width: sourceView.bounds.width,
height: sourceView.bounds.height + spacing)
} }
} }

View File

@ -117,10 +117,11 @@ open class DatePicker: EntryFieldBase {
NotificationCenter.default NotificationCenter.default
.publisher(for: UIDevice.orientationDidChangeNotification).sink { [weak self] _ in .publisher(for: UIDevice.orientationDidChangeNotification).sink { [weak self] _ in
guard let self, let popoverController else { return } guard let self else { return }
popoverController.dismiss(animated: true){ [weak self] in popoverController?.dismiss(animated: true){ [weak self] in
guard let self else { return } guard let self else { return }
} }
hidePopoverView()
} }
.store(in: &subscribers) .store(in: &subscribers)
@ -163,7 +164,7 @@ open class DatePicker: EntryFieldBase {
selectedDateLabel.text = formatter.string(from: date) selectedDateLabel.text = formatter.string(from: date)
} }
internal var popoverController: UIViewController? internal var popoverController: ClearPopoverViewController?
func didSelect(_ date: Date) { func didSelect(_ date: Date) {
selectedDate = date selectedDate = date
@ -175,34 +176,179 @@ open class DatePicker: EntryFieldBase {
} }
} }
internal func togglePicker() { private var overlayView = UIView().with {
let calendar = CalendarBase() $0.backgroundColor = .clear;
calendar.activeDates = calendarModel.activeDates $0.isHidden = true
calendar.hideContainerBorder = calendarModel.hideContainerBorder }
calendar.hideCurrentDateIndicator = calendarModel.hideCurrentDateIndicator private var popoverView: UIView!
calendar.inactiveDates = calendarModel.inactiveDates private var popoverVisible = false
calendar.indicators = calendarModel.indicators private var outsideTapGesture: UITapGestureRecognizer?
calendar.maxDate = calendarModel.maxDate private var outsidePanGesture: UIPanGestureRecognizer?
calendar.minDate = calendarModel.minDate
calendar.surface = calendarModel.surface // internal func togglePicker() {
calendar.setNeedsLayout() // calendar.activeDates = calendarModel.activeDates
calendar.layoutIfNeeded() // calendar.hideContainerBorder = calendarModel.hideContainerBorder
calendar.onChange = { [weak self] control in // calendar.hideCurrentDateIndicator = calendarModel.hideCurrentDateIndicator
guard let self else { return } // calendar.inactiveDates = calendarModel.inactiveDates
didSelect(control.selectedDate) // calendar.indicators = calendarModel.indicators
} // calendar.maxDate = calendarModel.maxDate
// calendar.minDate = calendarModel.minDate
// calendar.surface = calendarModel.surface
// calendar.setNeedsLayout()
// calendar.layoutIfNeeded()
// calendar.onChange = { [weak self] control in
// guard let self else { return }
// didSelect(control.selectedDate)
// }
//
// popoverController = ClearPopoverViewController(contentView: calendar,
// arrow: .any,
// sourceView: containerView,
// sourceRect: .init(x: 0, y: 0, width: 320, height: 45),
// spacing: VDSLayout.space1X)
// popoverController?.maxWidth = 320
// if let viewController = UIApplication.topViewController(), let popoverController {
// viewController.present(popoverController,
// animated: true,
// completion: nil)
// }
// }
}
extension DatePicker {
private func togglePicker() {
guard let viewController = UIApplication.topViewController(), let parentView = viewController.view else { return }
if popoverVisible {
hidePopoverView()
} else {
let calendar = CalendarBase()
calendar.activeDates = calendarModel.activeDates
calendar.hideContainerBorder = calendarModel.hideContainerBorder
calendar.hideCurrentDateIndicator = calendarModel.hideCurrentDateIndicator
calendar.inactiveDates = calendarModel.inactiveDates
calendar.indicators = calendarModel.indicators
calendar.maxDate = calendarModel.maxDate
calendar.minDate = calendarModel.minDate
calendar.surface = calendarModel.surface
calendar.setNeedsLayout()
calendar.layoutIfNeeded()
calendar.onChange = { [weak self] control in
guard let self else { return }
selectedDate = control.selectedDate
sendActions(for: .valueChanged)
UIAccessibility.post(notification: .layoutChanged, argument: containerView)
hidePopoverView()
}
outsideTapGesture = UITapGestureRecognizer()
outsidePanGesture = UIPanGestureRecognizer()
overlayView.publisher(for: outsideTapGesture!).sink { [weak self] _ in
guard let self else { return }
hidePopoverView()
}.store(in: &subscribers)
parentView.publisher(for: outsidePanGesture!).sink { [weak self] _ in
guard let self else { return }
hidePopoverView()
}.store(in: &subscribers)
overlayView.frame = parentView.bounds
overlayView.isHidden = false
parentView.addSubview(overlayView)
popoverView = UIView()
popoverView.backgroundColor = .white
popoverView.layer.cornerRadius = 10
popoverView.layer.shadowColor = UIColor.black.cgColor
popoverView.layer.shadowOpacity = 0.2
popoverView.layer.shadowOffset = CGSize(width: 0, height: 5)
popoverView.layer.shadowRadius = 10
popoverView.isHidden = true
popoverView.addSubview(calendar)
calendar.pinToSuperView()
popoverView.translatesAutoresizingMaskIntoConstraints = false
parentView.addSubview(popoverView)
popoverView.width(calendar.frame.width)
popoverView.height(calendar.frame.height)
let spacing: CGFloat = 4
let (popoverX, popoverY) = calculatePopoverPosition(relativeTo: containerView, in: parentView, size: calendar.frame.size, with: spacing)
popoverView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: popoverX).isActive = true
popoverView.topAnchor.constraint(equalTo: parentView.topAnchor, constant: popoverY).isActive = true
parentView.layoutIfNeeded()
popoverView.alpha = 0
popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
popoverView.isHidden = false
popoverVisible = true
popoverController = ClearPopoverViewController(contentView: calendar, UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2, options: .curveEaseOut, animations: { [weak self] in
arrow: .up, guard let self else { return }
sourceView: containerView, popoverView.alpha = 1
sourceRect: containerView.bounds, popoverView.transform = CGAffineTransform.identity
spacing: VDSLayout.space1X) parentView.layoutIfNeeded()
})
if let viewController = UIApplication.topViewController(), let popoverController {
viewController.present(popoverController,
animated: true,
completion: nil)
} }
} }
private func hidePopoverView() {
overlayView.isHidden = true
overlayView.removeFromSuperview()
outsideTapGesture = nil
outsidePanGesture = nil
UIView.animate(withDuration: 0.2, animations: {
self.popoverView.alpha = 0
self.popoverView.transform = CGAffineTransform(scaleX: 0.9, y: 0.9)
}) { _ in
self.popoverView.isHidden = true
self.popoverView.removeFromSuperview()
self.popoverVisible = false
}
}
private func calculatePopoverPosition(relativeTo sourceView: UIView, in parentView: UIView, size: CGSize, with spacing: CGFloat) -> (CGFloat, CGFloat) {
let sourceFrameInParent = sourceView.convert(sourceView.bounds, to: parentView)
let parentBounds = parentView.bounds
let popoverWidth: CGFloat = size.width
let popoverHeight: CGFloat = size.height
var popoverX: CGFloat = 0
var popoverY: CGFloat = 0
// Calculate horizontal position
if sourceFrameInParent.width < popoverWidth {
if sourceFrameInParent.midX - popoverWidth / 2 < 0 {
// Align to left
popoverX = sourceFrameInParent.minX
} else if sourceFrameInParent.midX + popoverWidth / 2 > parentBounds.width {
// Align to right
popoverX = sourceFrameInParent.maxX - popoverWidth
} else {
// Center on source view
popoverX = sourceFrameInParent.midX - popoverWidth / 2
}
} else {
popoverX = sourceFrameInParent.midX - popoverWidth / 2
}
// Calculate vertical position
if sourceFrameInParent.origin.y > parentBounds.height / 2 {
// Show above
popoverY = sourceFrameInParent.minY - popoverHeight - spacing
} else {
// Show below
popoverY = sourceFrameInParent.maxY + spacing
}
// Ensure the popover is within the parent's bounds
popoverX = max(0, min(popoverX, parentBounds.width - popoverWidth))
return (popoverX, popoverY)
}
} }