Skip to content

Commit 2135c96

Browse files
chore(feedback): Improve widget animations (#4555)
* chore(feedback): Improve widget animations * add comment * when widget is about to be shown it should not animate slide down
1 parent 7579a06 commit 2135c96

File tree

2 files changed

+55
-17
lines changed

2 files changed

+55
-17
lines changed

packages/core/src/js/feedback/FeedbackWidget.tsx

+8-3
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,9 @@ export class FeedbackWidget extends React.Component<FeedbackWidgetProps, Feedbac
8888
};
8989

9090
try {
91-
this.setState({ isVisible: false });
91+
if (!onFormSubmitted) {
92+
this.setState({ isVisible: false });
93+
}
9294
captureFeedback(userFeedback, attachments ? { attachments } : undefined);
9395
onSubmitSuccess({ name: trimmedName, email: trimmedEmail, message: trimmedDescription, attachments: undefined });
9496
Alert.alert(text.successMessageText);
@@ -161,8 +163,11 @@ export class FeedbackWidget extends React.Component<FeedbackWidgetProps, Feedbac
161163
const text: FeedbackTextConfiguration = this.props;
162164
const styles: FeedbackWidgetStyles = { ...defaultStyles, ...this.props.styles };
163165
const onCancel = (): void => {
164-
onFormClose();
165-
this.setState({ isVisible: false });
166+
if (onFormClose) {
167+
onFormClose();
168+
} else {
169+
this.setState({ isVisible: false });
170+
}
166171
}
167172

168173
if (!this.state.isVisible) {

packages/core/src/js/feedback/FeedbackWidgetManager.tsx

+47-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { logger } from '@sentry/core';
22
import * 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

55
import { FeedbackWidget } from './FeedbackWidget';
66
import { modalBackground, modalSheetContainer, modalWrapper } from './FeedbackWidget.styles';
@@ -10,6 +10,8 @@ import { isModalSupported } from './utils';
1010

1111
const PULL_DOWN_CLOSE_THREESHOLD = 200;
1212
const PULL_DOWN_ANDROID_ACTIVATION_HEIGHT = 150;
13+
const SLIDE_ANIMATION_DURATION = 200;
14+
const BACKGROUND_ANIMATION_DURATION = 200;
1315

1416
class 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

Comments
 (0)