diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift index a807b72a..6ec44e6e 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift @@ -28,8 +28,6 @@ struct AdaptiveModalConfig { let snapPercentStrategy: SnapPercentStrategy; - // let snapPointInitial: - let snapAnimationConfig: AdaptiveModalSnapAnimationConfig; let interpolationClampingConfig: AdaptiveModalClampingConfig; @@ -49,7 +47,6 @@ struct AdaptiveModalConfig { overshootSnapPoint: self.overshootSnapPoint ); }; - var overshootSnapPointIndex: Int { self.snapPoints.count - 1; @@ -112,7 +109,7 @@ struct AdaptiveModalConfig { self.initialSnapPointIndex = initialSnapPointIndex; self.undershootSnapPoint = undershootSnapPoint - ?? .getDefaultInitialSnapPoint(forDirection: snapDirection); + ?? .getDefaultUnderShootSnapPoint(forDirection: snapDirection); self.overshootSnapPoint = overshootSnapPoint ?? .getDefaultOvershootSnapPoint(forDirection: snapDirection); diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index b758975e..a2bb08be 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -19,6 +19,7 @@ class AdaptiveModalManager: NSObject { var modalConfig: AdaptiveModalConfig; var enableSnapping = true; + var enableOverShooting = true; var shouldSnapToUnderShootSnapPoint = true; var shouldSnapToOvershootSnapPoint = false; @@ -282,7 +283,7 @@ class AdaptiveModalManager: NSObject { func setupViewControllers() { guard let modalVC = self.modalViewController else { return }; - modalVC.modalPresentationStyle = .custom; + modalVC.modalPresentationStyle = .overCurrentContext; modalVC.transitioningDelegate = self; }; @@ -979,10 +980,19 @@ class AdaptiveModalManager: NSObject { let percent = inputValue / interpolationRangeMaxInput; - let percentAdj = shouldInvertPercent - ? AdaptiveModalUtilities.invertPercent(percent) - : percent; + let percentClamped: CGFloat = { + guard !self.enableOverShooting else { return percent }; + + let secondToLastIndex = self.modalConfig.overshootSnapPointIndex - 1; + let maxPercent = self.interpolationRangeInput[secondToLastIndex]; + + return percent.clamped(max: maxPercent); + }(); + let percentAdj = shouldInvertPercent + ? AdaptiveModalUtilities.invertPercent(percentClamped) + : percentClamped; + self.applyInterpolationToModal(forInputPercentValue: percentAdj); }; @@ -1112,21 +1122,6 @@ class AdaptiveModalManager: NSObject { let interpolationPoint = interpolationSteps[closestInterpolationIndex]; let snapPointIndex = interpolationPoint.snapPointIndex; - let coords = self.interpolationSteps.map { - $0.computedRect[keyPath: self.modalConfig.inputValueKeyForRect]; - }; - - print( - "getClosestSnapPoint" - + "\n - inputRect: \(inputRect)" - + "\n - inputCoordAdj: \(inputCoordAdj)" - + "\n - coords: \(coords)" - + "\n - delta: \(delta)" - + "\n - deltaSorted: \(deltaSorted)" - + "\n - closestInterpolationIndex: \(closestInterpolationIndex)" - + "\n" - ); - return ( interpolationIndex: closestInterpolationIndex, snapPointConfig: self.modalConfig.snapPoints[snapPointIndex], @@ -1291,15 +1286,6 @@ class AdaptiveModalManager: NSObject { let gestureFinalPoint = self.applyGestureOffsets(forGesturePoint: gestureFinalPointRaw); - print( - "onDragPanGesture" - + "\n - gesturePoint: \(gesturePoint)" - + "\n - gestureVelocity: \(gestureVelocity)" - + "\n - gestureFinalPointRaw: \(gestureFinalPointRaw)" - + "\n - gestureFinalPoint: \(gestureFinalPoint)" - + "\n" - ); - self.snapToClosestSnapPoint(forPoint: gestureFinalPoint) { self.notifyOnModalDidSnap(); }; @@ -1430,9 +1416,14 @@ class AdaptiveModalManager: NSObject { let shouldDismiss = shouldDismissOnSnapToUnderShootSnapPoint || shouldDismissOnSnapToOverShootSnapPoint; - + + let isPresenting = self.currentInterpolationIndex == 0 && nextIndex == 1; + if shouldDismiss { self.notifyOnModalWillHide(); + + } else if isPresenting { + self.notifyOnModalWillShow(); }; }; @@ -1458,16 +1449,34 @@ class AdaptiveModalManager: NSObject { let shouldDismiss = shouldDismissOnSnapToUnderShootSnapPoint || shouldDismissOnSnapToOverShootSnapPoint; + + let wasPresented = + self.currentInterpolationIndex == 1 && self.prevInterpolationIndex == 0; if shouldDismiss { self.notifyOnModalDidHide(); + + } else if wasPresented { + self.notifyOnModalDidShow(); }; - - self.debug(); + }; + + private func notifyOnModalWillShow(){ + // wip + }; + + private func notifyOnModalDidShow(){ + // wip + //UIView.animate(withDuration: 1){ + // self.targetViewController?.view.transform = .init(scaleX: 0.5, y: 0.5); + //}; }; private func notifyOnModalWillHide(){ // wip + //UIView.animate(withDuration: 1){ + // self.targetViewController?.view.transform = .identity; + //}; }; private func notifyOnModalDidHide(){ @@ -1558,16 +1567,6 @@ class AdaptiveModalManager: NSObject { let coord = point[keyPath: self.modalConfig.inputValueKeyForPoint]; let closestSnapPoint = self.getClosestSnapPoint(forCoord: coord); - print( - "snapToClosestSnapPoint" - + "\n - coord: \(coord)" - + "\n - closestSnapPoint.interpolationIndex: \(closestSnapPoint.interpolationIndex)" - + "\n - closestSnapPoint.snapDistance: \(closestSnapPoint.snapDistance)" - + "\n - closestSnapPoint.interpolationPoint: \(closestSnapPoint.interpolationPoint)" - + "\n - closestSnapPoint.snapPointConfig: \(closestSnapPoint.snapPointConfig)" - + "\n" - ); - let nextInterpolationIndex = self.adjustInterpolationIndex(for: closestSnapPoint.interpolationIndex); diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift index d07db2a0..35ec57f2 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalPresentationController.swift @@ -29,4 +29,10 @@ class AdaptiveModalPresentationController: UIPresentationController { override func presentationTransitionDidEnd(_ completed: Bool) { }; + + override func viewWillTransition( + to size: CGSize, + with coordinator: UIViewControllerTransitionCoordinator + ) { + } }; diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPointPreset.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPointPreset.swift index eee8389d..55e773e8 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPointPreset.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalSnapPointPreset.swift @@ -38,7 +38,7 @@ extension AdaptiveModalSnapPointPreset { return self.init(layoutPreset: layoutPreset); }; - static func getDefaultInitialSnapPoint( + static func getDefaultUnderShootSnapPoint( forDirection direction: AdaptiveModalConfig.Direction ) -> Self { diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalUtilities.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalUtilities.swift index f3f9f0b4..9b37bbe5 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalUtilities.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalUtilities.swift @@ -176,8 +176,16 @@ class AdaptiveModalUtilities { }; static func invertPercent(_ percent: CGFloat) -> CGFloat { - let offset = percent > 1 ? abs(percent - 1) : 0; - return 1 - percent + offset; + if percent >= 0 && percent <= 1 { + return 1 - percent; + }; + + if percent < 0 { + return abs(percent) + 1; + }; + + // percent > 1 + return -(percent - 1); }; static func unwrapAndSetProperty( diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift index 2c60563d..c9a5a879 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift @@ -27,6 +27,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { case demo05; case demo06; case demo07; + case demo08; var config: AdaptiveModalConfig { switch self { @@ -890,7 +891,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { modalCornerRadius: 15, modalBackgroundOpacity: 0.85, modalBackgroundVisualEffectIntensity: 0.9, - backgroundColor: .black, + backgroundColor: .white, backgroundOpacity: 0.15, backgroundVisualEffectIntensity: 0.05 ) @@ -901,8 +902,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { snapPoint: RNILayout( horizontalAlignment: .center, verticalAlignment: .center, - width: .percent(percentValue: 0.9), - height: .percent(percentValue: 0.85) + width: .stretch, + height: .stretch ), animationKeyframe: AdaptiveModalAnimationConfig( modalShadowOffset: .zero, @@ -912,7 +913,7 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { modalBackgroundVisualEffectOpacity: 0, modalBackgroundVisualEffectIntensity: 0, backgroundColor: .white, - backgroundOpacity: 0.5, + backgroundOpacity: 0.75, backgroundVisualEffectIntensity: 1 ) ), @@ -932,7 +933,38 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { ) ), overshootSnapPoint: AdaptiveModalSnapPointPreset( - layoutPreset: .edgeRight + layoutPreset: .offscreenRight + ) + ); + + case .demo08: return AdaptiveModalConfig( + snapPoints: [ + // Snap Point 1 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .bottom, + width: .stretch, + height: .percent(percentValue: 0.3) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 0, height: -2), + modalShadowOpacity: 0.2, + modalShadowRadius: 7, + modalCornerRadius: 25, + modalMaskedCorners: [ + .layerMinXMinYCorner, + .layerMaxXMinYCorner + ], + modalBackgroundOpacity: 0.9, + modalBackgroundVisualEffect: UIBlurEffect(style: .systemUltraThinMaterial), + modalBackgroundVisualEffectIntensity: 1 + ) + ) + ], + snapDirection: .bottomToTop, + overshootSnapPoint: AdaptiveModalSnapPointPreset( + layoutPreset: .fitScreen ) ); }; diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift index 77a144dd..0fa014e7 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift @@ -114,6 +114,8 @@ class AdaptiveModalPresentationTestViewController : UIViewController { var currentModalManagerAdjustmentBlock: () -> Void { let defaultBlock = { + self.adaptiveModalManager.enableOverShooting = true; + self.adaptiveModalManager.shouldSnapToUnderShootSnapPoint = true; self.adaptiveModalManager.shouldSnapToOvershootSnapPoint = false; @@ -122,25 +124,13 @@ class AdaptiveModalPresentationTestViewController : UIViewController { }; switch self.currentModalConfigPreset { - case .demo01: return { - defaultBlock(); - }; - - case .demo02: return { - defaultBlock(); - }; - - case .demo03: return { - defaultBlock(); - }; - case .demo04: return { self.adaptiveModalManager.shouldSnapToOvershootSnapPoint = true; self.adaptiveModalManager.shouldDismissModalOnSnapToOverShootSnapPoint = true; }; - case .demo05: return { - defaultBlock(); + case .demo07: return { + self.adaptiveModalManager.enableOverShooting = false; }; default: return defaultBlock;