Skip to content

feat(feedback): Pull down to cancel #4534

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Feb 17, 2025
Merged
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
fe3dc15
Disable bouncing
antonis Jan 30, 2025
72eef2d
Add modal ui appearance
antonis Jan 30, 2025
ccc808b
Update snapshot tests
antonis Jan 30, 2025
fd47fd2
Fix bottom margin
antonis Jan 30, 2025
dcc5d3b
Merge branch 'feedback-ui' into antonis/feedback-modal-ui
antonis Jan 31, 2025
9ecd8a2
Fix sheet height
antonis Jan 31, 2025
05f94f8
Remove extra modal border
antonis Jan 31, 2025
d88a599
Do not expose modal styles
antonis Jan 31, 2025
ce1de86
Animate background color
antonis Jan 31, 2025
a7a4e56
Avoid keyboard in modal
antonis Jan 31, 2025
8779886
Merge branch 'feedback-ui' into antonis/feedback-modal-ui
antonis Feb 3, 2025
ae80f7d
Merge branch 'feedback-ui' into antonis/feedback-modal-ui
antonis Feb 7, 2025
488658e
Merge branch 'feedback-ui' into antonis/feedback-modal-ui
antonis Feb 10, 2025
c4d502e
Use Image Picker interface matching `expo-image-picker` and `react-na…
antonis Feb 11, 2025
1b74b45
Update samples to pass the ImagePicker library implementation
antonis Feb 11, 2025
1d8a0db
Merge branch 'feedback-ui' into antonis/feedback-ui-imagepicker-integ…
antonis Feb 11, 2025
a0f4a77
Get image data from uri
antonis Feb 11, 2025
357dea8
Add early return and dev note
antonis Feb 11, 2025
192220b
Adds tests
antonis Feb 11, 2025
c3991ff
Adds sample expo plugin configuration
antonis Feb 11, 2025
91e96de
Merge branch 'feedback-ui' into antonis/feedback-ui-imagepicker-integ…
antonis Feb 11, 2025
6666cf6
Update media type for expo
antonis Feb 12, 2025
d1e5107
Update media type for rn
antonis Feb 12, 2025
d780fc1
Add native implementation for getDataFromUri
antonis Feb 13, 2025
85dff80
Bumped to the latest react-native-image-picker version 8
antonis Feb 13, 2025
e92fea6
Add missing null in return type
antonis Feb 13, 2025
becede1
Pull down to cancel on iOS
antonis Feb 13, 2025
529b703
Merge branch 'feedback-ui' into antonis/feedback-ios-pull-down-to-cancel
antonis Feb 14, 2025
3238fe0
On Android allow pulling down only from the top to avoid breaking nat…
antonis Feb 14, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 46 additions & 3 deletions packages/core/src/js/feedback/FeedbackFormManager.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { logger } from '@sentry/core';
import * as React from 'react';
import { Animated, KeyboardAvoidingView, Modal, Platform, View } from 'react-native';
import { Animated, KeyboardAvoidingView, Modal, PanResponder, Platform } from 'react-native';

import { FeedbackForm } from './FeedbackForm';
import { modalBackground, modalSheetContainer, modalWrapper } from './FeedbackForm.styles';
import type { FeedbackFormStyles } from './FeedbackForm.types';
import { getFeedbackOptions } from './integration';
import { isModalSupported } from './utils';

const PULL_DOWN_CLOSE_THREESHOLD = 200;
const PULL_DOWN_ANDROID_ACTIVATION_HEIGHT = 150;

class FeedbackFormManager {
private static _isVisible = false;
private static _setVisibility: (visible: boolean) => void;
Expand Down Expand Up @@ -43,14 +46,48 @@ interface FeedbackFormProviderProps {
interface FeedbackFormProviderState {
isVisible: boolean;
backgroundOpacity: Animated.Value;
panY: Animated.Value;
}

class FeedbackFormProvider extends React.Component<FeedbackFormProviderProps> {
public state: FeedbackFormProviderState = {
isVisible: false,
backgroundOpacity: new Animated.Value(0),
panY: new Animated.Value(0),
};


private _panResponder = PanResponder.create({
onStartShouldSetPanResponder: (evt, _gestureState) => {
// On Android allow pulling down only from the top to avoid breaking native gestures
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for including here the reason why.

return Platform.OS !== 'android' || evt.nativeEvent.pageY < PULL_DOWN_ANDROID_ACTIVATION_HEIGHT;
},
onMoveShouldSetPanResponder: (evt, _gestureState) => {
return Platform.OS !== 'android' || evt.nativeEvent.pageY < PULL_DOWN_ANDROID_ACTIVATION_HEIGHT;
},
onPanResponderMove: (_, gestureState) => {
if (gestureState.dy > 0) {
this.state.panY.setValue(gestureState.dy);
}
},
onPanResponderRelease: (_, gestureState) => {
if (gestureState.dy > PULL_DOWN_CLOSE_THREESHOLD) { // Close on swipe below a certain threshold
Animated.timing(this.state.panY, {
toValue: 600,
duration: 200,
useNativeDriver: true,
}).start(() => {
this._handleClose();
});
} else { // Animate it back to the original position
Animated.spring(this.state.panY, {
toValue: 0,
useNativeDriver: true,
}).start();
}
},
});

public constructor(props: FeedbackFormProviderProps) {
super(props);
FeedbackFormManager.initialize(this._setVisibilityFunction);
Expand Down Expand Up @@ -99,12 +136,15 @@ class FeedbackFormProvider extends React.Component<FeedbackFormProviderProps> {
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={modalBackground}
>
<View style={modalSheetContainer}>
<Animated.View
style={[modalSheetContainer, { transform: [{ translateY: this.state.panY }] }]}
{...this._panResponder.panHandlers}
>
<FeedbackForm {...getFeedbackOptions()}
onFormClose={this._handleClose}
onFormSubmitted={this._handleClose}
/>
</View>
</Animated.View>
</KeyboardAvoidingView>
</Modal>
</Animated.View>
Expand All @@ -115,6 +155,9 @@ class FeedbackFormProvider extends React.Component<FeedbackFormProviderProps> {

private _setVisibilityFunction = (visible: boolean): void => {
this.setState({ isVisible: visible });
if (visible) {
this.state.panY.setValue(0);
}
};

private _handleClose = (): void => {
Expand Down
Loading