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

View File

@ -117,10 +117,11 @@ open class DatePicker: EntryFieldBase {
NotificationCenter.default
.publisher(for: UIDevice.orientationDidChangeNotification).sink { [weak self] _ in
guard let self, let popoverController else { return }
popoverController.dismiss(animated: true){ [weak self] in
guard let self else { return }
popoverController?.dismiss(animated: true){ [weak self] in
guard let self else { return }
}
hidePopoverView()
}
.store(in: &subscribers)
@ -163,7 +164,7 @@ open class DatePicker: EntryFieldBase {
selectedDateLabel.text = formatter.string(from: date)
}
internal var popoverController: UIViewController?
internal var popoverController: ClearPopoverViewController?
func didSelect(_ date: Date) {
selectedDate = date
@ -175,34 +176,179 @@ open class DatePicker: EntryFieldBase {
}
}
internal func togglePicker() {
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 }
didSelect(control.selectedDate)
}
private var overlayView = UIView().with {
$0.backgroundColor = .clear;
$0.isHidden = true
}
private var popoverView: UIView!
private var popoverVisible = false
private var outsideTapGesture: UITapGestureRecognizer?
private var outsidePanGesture: UIPanGestureRecognizer?
// internal func togglePicker() {
// 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 }
// 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,
arrow: .up,
sourceView: containerView,
sourceRect: containerView.bounds,
spacing: VDSLayout.space1X)
if let viewController = UIApplication.topViewController(), let popoverController {
viewController.present(popoverController,
animated: true,
completion: nil)
UIView.animate(withDuration: 0.3, delay: 0, usingSpringWithDamping: 0.8, initialSpringVelocity: 0.2, options: .curveEaseOut, animations: { [weak self] in
guard let self else { return }
popoverView.alpha = 1
popoverView.transform = CGAffineTransform.identity
parentView.layoutIfNeeded()
})
}
}
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)
}
}