1 // Copyright (c) 2018, Applidium. All rights reserved 2 // OverlayContainerViewControllerDelegateWrapper.swift 3 // OverlayContainer 4 // 5 // Created by Gaétan Zanella on 20/11/2018. 6 // 7 8 import UIKit 9 10 class OverlayContainerConfigurationImplementation: OverlayContainerConfigurationInvalidating { 11 12 private weak var overlayContainerViewController: OverlayContainerViewController? 13 14 weak var delegate: OverlayContainerViewControllerDelegate? 15 16 private(set) var notchHeightByIndex: [Int: CGFloat] = [:] 17 18 private var needsMetricUpdate = false 19 20 // MARK: - Life Cycle 21 22 init(overlayContainerViewController: OverlayContainerViewController) { 23 self.overlayContainerViewController = overlayContainerViewController 24 } 25 26 // MARK: - OverlayContainerConfigurationInvalidating 27 invalidateOverlayMetricsnull28 func invalidateOverlayMetrics() { 29 needsMetricUpdate = true 30 } 31 requestOverlayMetricsIfNeedednull32 func requestOverlayMetricsIfNeeded() { 33 guard needsMetricUpdate else { return } 34 needsMetricUpdate = false 35 let numberOfNotches = requestNumberOfNotches() 36 assert(numberOfNotches >= 0, "The number of notches must be positive.") 37 let heights = (0..<numberOfNotches).map { requestHeightForNotch(at: $0) } 38 assert(heights.sorted() == heights, "The notches should be sorted by height. The notch at the first index must be the smaller one. \(heights)") 39 let values = heights.enumerated().map { ($0, $1) } 40 notchHeightByIndex = Dictionary(uniqueKeysWithValues: values) 41 } 42 43 // MARK: - OverlayContainerViewControllerConfiguration 44 numberOfNotchesnull45 func numberOfNotches() -> Int { 46 return notchHeightByIndex.count 47 } 48 heightForNotchnull49 func heightForNotch(at index: Int) -> CGFloat { 50 return notchHeightByIndex[index] ?? 0 51 } 52 animationControllernull53 func animationController(forOverlay overlay: UIViewController) -> OverlayAnimatedTransitioning { 54 guard let controller = overlayContainerViewController else { 55 return SpringOverlayTranslationAnimationController() 56 } 57 let transitioningDelegate = delegate?.overlayContainerViewController( 58 controller, 59 transitioningDelegateForOverlay: overlay 60 ) 61 let defaultController = SpringOverlayTranslationAnimationController(style: controller.style) 62 return transitioningDelegate?.animationController(for: overlay) ?? defaultController 63 } 64 overlayTargetNotchPolicynull65 func overlayTargetNotchPolicy(forOverlay overlay: UIViewController) -> OverlayTranslationTargetNotchPolicy { 66 guard let controller = overlayContainerViewController else { 67 return RushingForwardTargetNotchPolicy() 68 } 69 let transitioningDelegate = delegate?.overlayContainerViewController( 70 controller, 71 transitioningDelegateForOverlay: overlay 72 ) 73 return transitioningDelegate?.overlayTargetNotchPolicy(for: overlay) ?? RushingForwardTargetNotchPolicy() 74 } 75 scrollViewnull76 func scrollView(drivingOverlay controller: UIViewController) -> UIScrollView? { 77 guard let containerController = overlayContainerViewController else { return nil } 78 return delegate?.overlayContainerViewController(containerController, scrollViewDrivingOverlay: controller) 79 } 80 81 func shouldStartDraggingOverlay(_ viewController: UIViewController, 82 at point: CGPoint, 83 in coordinateSpace: UICoordinateSpace) -> Bool { 84 guard let containerController = overlayContainerViewController else { return false } 85 return delegate?.overlayContainerViewController( 86 containerController, 87 shouldStartDraggingOverlay: viewController, 88 at: point, 89 in: coordinateSpace 90 ) ?? true 91 } 92 93 func overlayTranslationFunction(using context: OverlayTranslationParameters, 94 for overlayViewController: UIViewController) -> OverlayTranslationFunction { 95 guard let containerController = overlayContainerViewController else { 96 return RubberBandOverlayTranslationFunction() 97 } 98 return delegate?.overlayContainerViewController( 99 containerController, 100 overlayTranslationFunctionForOverlay: overlayViewController 101 ) ?? RubberBandOverlayTranslationFunction() 102 } 103 canReachNotchnull104 func canReachNotch(at index: Int, for overlayViewController: UIViewController) -> Bool { 105 guard let containerController = overlayContainerViewController else { 106 return true 107 } 108 return delegate?.overlayContainerViewController( 109 containerController, 110 canReachNotchAt: index, 111 forOverlay: overlayViewController 112 ) ?? true 113 } 114 115 // MARK: - Private 116 requestHeightForNotchnull117 private func requestHeightForNotch(at index: Int) -> CGFloat { 118 guard let controller = overlayContainerViewController else { return 0 } 119 return delegate?.overlayContainerViewController( 120 controller, 121 heightForNotchAt: index, 122 availableSpace: controller.availableSpace 123 ) ?? 0 124 } 125 requestNumberOfNotchesnull126 private func requestNumberOfNotches() -> Int { 127 guard let controller = overlayContainerViewController else { return 0 } 128 return delegate?.numberOfNotches(in: controller) ?? 0 129 } 130 } 131