From a0ed2cc8a8f614dca385b2da1dfb3525dd8fe355 Mon Sep 17 00:00:00 2001 From: Dominic Go <18517029+dominicstop@users.noreply.github.com> Date: Mon, 19 Jun 2023 04:57:07 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=AB=20Update:=20Exp=20-=20`AdaptiveMod?= =?UTF-8?q?al`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Summary: Update experiment/test - `swift-programmatic-modal/AdaptiveModal`. --- .../AdaptiveModal/AdaptiveModalConfig.swift | 3 +- .../AdaptiveModal/AdaptiveModalManager.swift | 40 ++++-- .../RNILayout/RNILayoutValue.swift | 2 +- .../Test/AdaptiveModalConfigTestPresets.swift | 126 ++++++++++++++++++ ...eModalPresentationTestViewController.swift | 44 +++++- .../RNIComputable/RNIComputableOffset.swift | 9 +- 6 files changed, 209 insertions(+), 15 deletions(-) diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift index 0bbe115f..a807b72a 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalConfig.swift @@ -49,8 +49,9 @@ struct AdaptiveModalConfig { overshootSnapPoint: self.overshootSnapPoint ); }; + - var snapPointLastIndex: Int { + var overshootSnapPointIndex: Int { self.snapPoints.count - 1; }; diff --git a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift index fd096e60..a9ebb2ee 100644 --- a/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift +++ b/experiments/swift-programmatic-modal/AdaptiveModal/AdaptiveModalManager.swift @@ -20,8 +20,11 @@ class AdaptiveModalManager: NSObject { var enableSnapping = true; - var shouldSnapToOvershootSnapPoint = false; var shouldSnapToUnderShootSnapPoint = true; + var shouldSnapToOvershootSnapPoint = false; + + var shouldDismissModalOnSnapToUnderShootSnapPoint = true; + var shouldDismissModalOnSnapToOverShootSnapPoint = false; // MARK: - Properties - Layout-Related // ------------------------------------ @@ -1062,6 +1065,8 @@ class AdaptiveModalManager: NSObject { self.clearGestureValues(); self.clearAnimators(); self.cleanupViews(); + + self.currentInterpolationIndex = 0; }; // MARK: - Functions @@ -1293,6 +1298,7 @@ class AdaptiveModalManager: NSObject { + "\n - targetViewController: \(self.targetViewController?.debugDescription ?? "N/A")" + "\n - currentInterpolationIndex: \(self.currentInterpolationIndex)" + "\n - modalView gestureRecognizers: \(self.modalView?.gestureRecognizers.debugDescription ?? "N/A")" + + "\n - interpolationSteps.computedRect: \(self.interpolationSteps.map({ $0.computedRect }))" + "\n" ); }; @@ -1385,7 +1391,18 @@ class AdaptiveModalManager: NSObject { interpolationPoint: nextPoint ); - if nextIndex == 0 { + let shouldDismissOnSnapToUnderShootSnapPoint = + nextIndex == 0 && self.shouldDismissModalOnSnapToUnderShootSnapPoint; + + let shouldDismissOnSnapToOverShootSnapPoint = + nextIndex == self.modalConfig.overshootSnapPointIndex && + self.shouldDismissModalOnSnapToOverShootSnapPoint; + + let shouldDismiss = + shouldDismissOnSnapToUnderShootSnapPoint || + shouldDismissOnSnapToOverShootSnapPoint; + + if shouldDismiss { self.notifyOnModalWillHide(); }; }; @@ -1402,15 +1419,20 @@ class AdaptiveModalManager: NSObject { interpolationPoint: self.currentInterpolationStep ); - if self.currentInterpolationIndex == 0 { + let shouldDismissOnSnapToUnderShootSnapPoint = + self.currentInterpolationIndex == 0 && self.shouldDismissModalOnSnapToUnderShootSnapPoint; + + let shouldDismissOnSnapToOverShootSnapPoint = + self.currentInterpolationIndex == self.modalConfig.overshootSnapPointIndex && + self.shouldDismissModalOnSnapToOverShootSnapPoint; + + let shouldDismiss = + shouldDismissOnSnapToUnderShootSnapPoint || + shouldDismissOnSnapToOverShootSnapPoint; + + if shouldDismiss { self.notifyOnModalDidHide(); }; - - print( - "self.interpolationSteps.computedRect: \n -", - self.interpolationSteps.map({ $0.computedRect }), - "\n" - ); }; private func notifyOnModalWillHide(){ diff --git a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift index 0cd14f5f..9ea6d799 100644 --- a/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift +++ b/experiments/swift-programmatic-modal/RNILayout/RNILayoutValue.swift @@ -66,7 +66,7 @@ public struct RNILayoutValue { offsetOperation: self.offsetOperation ?? .add ); - return computableOffset.compute(withValue: value); + return computableOffset.compute(withValue: value, isValueOnRHS: true); }; public func clampValue( diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift index 2691d92a..ff2e85ec 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalConfigTestPresets.swift @@ -23,6 +23,8 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { case demo01; case demo02; case demo03; + case demo04; + case demo05; var config: AdaptiveModalConfig { switch self { @@ -693,6 +695,130 @@ enum AdaptiveModalConfigTestPresets: CaseIterable { layoutPreset: .edgeRight ) ); + + case .demo04: return AdaptiveModalConfig( + snapPoints: [ + // 1 + .init( + snapPoint: .init( + horizontalAlignment: .center, + verticalAlignment: .top, + width: .stretch, + height: .percent(percentValue: 0.2), + marginLeft: .constant(10), + marginRight: .constant(10), + marginTop: .multipleValues([ + .safeAreaInsets(insetKey: \.top), + .constant(10) + ]) + ), + animationKeyframe: .init( + modalScaleX: 1, + modalScaleY: 1, + modalShadowOpacity: 0.3, + modalShadowRadius: 10, + modalCornerRadius: 10 + ) + ), + + // 2 + .init( + snapPoint: .init( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .stretch, + height: .percent(percentValue: 0.5), + marginLeft: .constant(15), + marginRight: .constant(15) + ), + animationKeyframe: .init( + modalShadowOffset: .init(width: 2, height: 2), + modalShadowOpacity: 0.2, + modalShadowRadius: 5, + modalCornerRadius: 15, + backgroundOpacity: 0.25 + ) + ) + ], + snapDirection: .topToBottom, + undershootSnapPoint: .init( + layoutPreset: .offscreenTop, + animationKeyframe: .init( + modalScaleX: 0.75, + modalScaleY: 0.75 + ) + ), + overshootSnapPoint: .init( + layoutPreset: .offscreenBottom, + animationKeyframe: .init( + modalScaleX: 0.9, + modalScaleY: 0.9, + modalOpacity: 0.8, + backgroundOpacity: 0 + ) + ) + ); + + case .demo05: return AdaptiveModalConfig( + snapPoints: [ + // snap point - 1 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .left, + verticalAlignment: .center, + width: .percent(percentValue: 0.7), + height: .stretch + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 1, height: 0), + modalShadowOpacity: 0.3, + modalShadowRadius: 8, + modalBackgroundOpacity: 0.87, + modalBackgroundVisualEffect: UIBlurEffect(style: .regular), + modalBackgroundVisualEffectIntensity: 1, + backgroundVisualEffect: UIBlurEffect(style: .regular), + backgroundVisualEffectIntensity: 0.04 + ) + ), + // snap point - 2 + AdaptiveModalSnapPointConfig( + snapPoint: RNILayout( + horizontalAlignment: .center, + verticalAlignment: .center, + width: .stretch, + height: .stretch( + offsetValue: .multipleValues([ + .safeAreaInsets(insetKey: \.top), + .safeAreaInsets(insetKey: \.bottom), + .constant(40), + ]), + offsetOperation: .subtract + ), + marginLeft: .constant(20), + marginRight: .constant(20) + ), + animationKeyframe: AdaptiveModalAnimationConfig( + modalShadowOffset: .init(width: 2, height: 2), + modalShadowOpacity: 0.2, + modalShadowRadius: 15, + modalCornerRadius: 15, + modalBackgroundOpacity: 0.9, + modalBackgroundVisualEffectIntensity: 0.5, + backgroundVisualEffectIntensity: 0.5 + ) + ), + ], + snapDirection: .leftToRight, + undershootSnapPoint: .init( + layoutPreset: .offscreenLeft, + animationKeyframe: .init( + backgroundVisualEffectIntensity: 0 + ) + ), + overshootSnapPoint: AdaptiveModalSnapPointPreset( + layoutPreset: .edgeRight + ) + ); }; }; }; diff --git a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift index aa9c9520..125c51bb 100644 --- a/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift +++ b/experiments/swift-programmatic-modal/Test/AdaptiveModalPresentationTestViewController.swift @@ -94,7 +94,9 @@ class AdaptiveModalPresentationTestViewController : UIViewController { let modalConfigs: [AdaptiveModalConfigTestPresets] = [ .demo01, .demo02, - .demo03 + .demo03, + .demo04, + .demo05, ]; var currentModalConfigPresetCounter = 0; @@ -104,8 +106,43 @@ class AdaptiveModalPresentationTestViewController : UIViewController { }; var currentModalConfigPreset: AdaptiveModalConfigTestPresets { - //self.modalConfigs[self.currentModalConfigPresetIndex]; - AdaptiveModalConfigTestPresets.default; + self.modalConfigs[self.currentModalConfigPresetIndex]; + //AdaptiveModalConfigTestPresets.default; + }; + + var currentModalManagerAdjustmentBlock: () -> Void { + let defaultBlock = { + self.adaptiveModalManager.shouldSnapToUnderShootSnapPoint = true; + self.adaptiveModalManager.shouldSnapToOvershootSnapPoint = false; + + self.adaptiveModalManager.shouldDismissModalOnSnapToUnderShootSnapPoint = true; + self.adaptiveModalManager.shouldDismissModalOnSnapToOverShootSnapPoint = false; + }; + + 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(); + }; + + default: return defaultBlock; + }; }; var counterLabel: UILabel?; @@ -217,5 +254,6 @@ class AdaptiveModalPresentationTestViewController : UIViewController { self.counterLabel!.text = "\(self.currentModalConfigPresetIndex)"; self.adaptiveModalManager.modalConfig = self.currentModalConfigPreset.config; + self.currentModalManagerAdjustmentBlock(); }; }; diff --git a/ios/src_library/React Native/RNIComputable/RNIComputableOffset.swift b/ios/src_library/React Native/RNIComputable/RNIComputableOffset.swift index b8d5f9dc..04ab8f72 100644 --- a/ios/src_library/React Native/RNIComputable/RNIComputableOffset.swift +++ b/ios/src_library/React Native/RNIComputable/RNIComputableOffset.swift @@ -32,7 +32,14 @@ public struct RNIComputableOffset { public var offset: Double; public var offsetOperation: OffsetOperation; - public func compute(withValue value: Double) -> Double { + public func compute( + withValue value: Double, + isValueOnRHS: Bool = false + ) -> Double { + if isValueOnRHS { + return self.offsetOperation.compute(a: value, b: self.offset); + }; + return self.offsetOperation.compute(a: self.offset, b: value); }; };