11import { logger } from '@sentry/core' ;
22import * as React from 'react' ;
3- import { Animated , KeyboardAvoidingView , Modal , PanResponder , Platform } from 'react-native' ;
3+ import { Animated , Dimensions , Easing , KeyboardAvoidingView , Modal , PanResponder , Platform } from 'react-native' ;
44
55import { FeedbackWidget } from './FeedbackWidget' ;
66import { modalBackground , modalSheetContainer , modalWrapper } from './FeedbackWidget.styles' ;
@@ -10,6 +10,8 @@ import { isModalSupported } from './utils';
1010
1111const PULL_DOWN_CLOSE_THREESHOLD = 200 ;
1212const PULL_DOWN_ANDROID_ACTIVATION_HEIGHT = 150 ;
13+ const SLIDE_ANIMATION_DURATION = 200 ;
14+ const BACKGROUND_ANIMATION_DURATION = 200 ;
1315
1416class FeedbackWidgetManager {
1517 private static _isVisible = false ;
@@ -53,7 +55,7 @@ class FeedbackWidgetProvider extends React.Component<FeedbackWidgetProviderProps
5355 public state : FeedbackWidgetProviderState = {
5456 isVisible : false ,
5557 backgroundOpacity : new Animated . Value ( 0 ) ,
56- panY : new Animated . Value ( 0 ) ,
58+ panY : new Animated . Value ( Dimensions . get ( 'screen' ) . height ) ,
5759 } ;
5860
5961 private _panResponder = PanResponder . create ( {
@@ -72,8 +74,8 @@ class FeedbackWidgetProvider extends React.Component<FeedbackWidgetProviderProps
7274 onPanResponderRelease : ( _ , gestureState ) => {
7375 if ( gestureState . dy > PULL_DOWN_CLOSE_THREESHOLD ) { // Close on swipe below a certain threshold
7476 Animated . timing ( this . state . panY , {
75- toValue : 600 ,
76- duration : 200 ,
77+ toValue : Dimensions . get ( 'screen' ) . height ,
78+ duration : SLIDE_ANIMATION_DURATION ,
7779 useNativeDriver : true ,
7880 } ) . start ( ( ) => {
7981 this . _handleClose ( ) ;
@@ -97,11 +99,22 @@ class FeedbackWidgetProvider extends React.Component<FeedbackWidgetProviderProps
9799 */
98100 public componentDidUpdate ( _prevProps : any , prevState : FeedbackWidgetProviderState ) : void {
99101 if ( ! prevState . isVisible && this . state . isVisible ) {
100- Animated . timing ( this . state . backgroundOpacity , {
101- toValue : 1 ,
102- duration : 300 ,
103- useNativeDriver : true ,
104- } ) . start ( ) ;
102+ Animated . parallel ( [
103+ Animated . timing ( this . state . backgroundOpacity , {
104+ toValue : 1 ,
105+ duration : BACKGROUND_ANIMATION_DURATION ,
106+ useNativeDriver : true ,
107+ easing : Easing . in ( Easing . quad ) ,
108+ } ) ,
109+ Animated . timing ( this . state . panY , {
110+ toValue : 0 ,
111+ duration : SLIDE_ANIMATION_DURATION ,
112+ useNativeDriver : true ,
113+ easing : Easing . in ( Easing . quad ) ,
114+ } )
115+ ] ) . start ( ( ) => {
116+ logger . info ( 'FeedbackWidgetProvider componentDidUpdate' ) ;
117+ } ) ;
105118 } else if ( prevState . isVisible && ! this . state . isVisible ) {
106119 this . state . backgroundOpacity . setValue ( 0 ) ;
107120 }
@@ -130,7 +143,7 @@ class FeedbackWidgetProvider extends React.Component<FeedbackWidgetProviderProps
130143 { this . props . children }
131144 { isVisible && (
132145 < Animated . View style = { [ modalWrapper , { backgroundColor } ] } >
133- < Modal visible = { isVisible } transparent animationType = "slide " onRequestClose = { this . _handleClose } testID = "feedback-form-modal" >
146+ < Modal visible = { isVisible } transparent animationType = "none " onRequestClose = { this . _handleClose } testID = "feedback-form-modal" >
134147 < KeyboardAvoidingView
135148 behavior = { Platform . OS === 'ios' ? 'padding' : 'height' }
136149 style = { modalBackground }
@@ -153,15 +166,35 @@ class FeedbackWidgetProvider extends React.Component<FeedbackWidgetProviderProps
153166 }
154167
155168 private _setVisibilityFunction = ( visible : boolean ) : void => {
156- this . setState ( { isVisible : visible } ) ;
157- if ( visible ) {
158- this . state . panY . setValue ( 0 ) ;
169+ const updateState = ( ) : void => {
170+ this . setState ( { isVisible : visible } ) ;
171+ } ;
172+ if ( ! visible ) {
173+ Animated . parallel ( [
174+ Animated . timing ( this . state . panY , {
175+ toValue : Dimensions . get ( 'screen' ) . height ,
176+ duration : SLIDE_ANIMATION_DURATION ,
177+ useNativeDriver : true ,
178+ easing : Easing . out ( Easing . quad ) ,
179+ } ) ,
180+ Animated . timing ( this . state . backgroundOpacity , {
181+ toValue : 0 ,
182+ duration : BACKGROUND_ANIMATION_DURATION ,
183+ useNativeDriver : true ,
184+ easing : Easing . out ( Easing . quad ) ,
185+ } )
186+ ] ) . start ( ( ) => {
187+ // Change of the state unmount the component
188+ // which would cancel the animation
189+ updateState ( ) ;
190+ } ) ;
191+ } else {
192+ updateState ( ) ;
159193 }
160194 } ;
161195
162196 private _handleClose = ( ) : void => {
163197 FeedbackWidgetManager . hide ( ) ;
164- this . setState ( { isVisible : false } ) ;
165198 } ;
166199}
167200
0 commit comments