Browse Source

feat: add swipe handler to entire bottom sheet

j8
Bettenbuk Zoltan 5 years ago
parent
commit
9b60537e0f

+ 0
- 5
package-lock.json View File

14873
         }
14873
         }
14874
       }
14874
       }
14875
     },
14875
     },
14876
-    "react-native-swipe-gestures": {
14877
-      "version": "1.0.4",
14878
-      "resolved": "https://registry.npmjs.org/react-native-swipe-gestures/-/react-native-swipe-gestures-1.0.4.tgz",
14879
-      "integrity": "sha512-C/vz0KPHNyqHk3uF4Cz/jzd/0N8z34ZgsjAZUh/RsXPH2FtJJf3Fw73pQDWJSoCMtvVadlztb8xQ+/aEQrll7w=="
14880
-    },
14881
     "react-native-swipeout": {
14876
     "react-native-swipeout": {
14882
       "version": "2.3.6",
14877
       "version": "2.3.6",
14883
       "resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",
14878
       "resolved": "https://registry.npmjs.org/react-native-swipeout/-/react-native-swipeout-2.3.6.tgz",

+ 0
- 1
package.json View File

77
     "react-native-sound": "0.11.0",
77
     "react-native-sound": "0.11.0",
78
     "react-native-svg": "9.7.1",
78
     "react-native-svg": "9.7.1",
79
     "react-native-svg-transformer": "0.13.0",
79
     "react-native-svg-transformer": "0.13.0",
80
-    "react-native-swipe-gestures": "1.0.4",
81
     "react-native-swipeout": "2.3.6",
80
     "react-native-swipeout": "2.3.6",
82
     "react-native-watch-connectivity": "0.2.0",
81
     "react-native-watch-connectivity": "0.2.0",
83
     "react-native-webrtc": "1.75.2",
82
     "react-native-webrtc": "1.75.2",

+ 77
- 2
react/features/base/dialog/components/native/BottomSheet.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import React, { PureComponent, type Node } from 'react';
3
 import React, { PureComponent, type Node } from 'react';
4
-import { SafeAreaView, ScrollView, View } from 'react-native';
4
+import { PanResponder, SafeAreaView, ScrollView, View } from 'react-native';
5
 
5
 
6
 import { ColorSchemeRegistry } from '../../../color-scheme';
6
 import { ColorSchemeRegistry } from '../../../color-scheme';
7
 import { SlidingView } from '../../../react';
7
 import { SlidingView } from '../../../react';
10
 
10
 
11
 import { bottomSheetStyles as styles } from './styles';
11
 import { bottomSheetStyles as styles } from './styles';
12
 
12
 
13
+/**
14
+ * Minimal distance that needs to be moved by the finger to consider it a swipe.
15
+ */
16
+const GESTURE_DISTANCE_THRESHOLD = 5;
17
+
18
+/**
19
+ * The minimal speed needed to be achieved by the finger to consider it as a swipe.
20
+ */
21
+const GESTURE_SPEED_THRESHOLD = 0.2;
22
+
13
 /**
23
 /**
14
  * The type of {@code BottomSheet}'s React {@code Component} prop types.
24
  * The type of {@code BottomSheet}'s React {@code Component} prop types.
15
  */
25
  */
31
      */
41
      */
32
     onCancel: ?Function,
42
     onCancel: ?Function,
33
 
43
 
44
+    /**
45
+     * Callback to be attached to the custom swipe event of the BottomSheet.
46
+     */
47
+    onSwipe?: Function,
48
+
34
     /**
49
     /**
35
      * Function to render a bottom sheet header element, if necessary.
50
      * Function to render a bottom sheet header element, if necessary.
36
      */
51
      */
41
  * A component emulating Android's BottomSheet.
56
  * A component emulating Android's BottomSheet.
42
  */
57
  */
43
 class BottomSheet extends PureComponent<Props> {
58
 class BottomSheet extends PureComponent<Props> {
59
+    panResponder: Object;
60
+
61
+    /**
62
+     * Instantiates a new component.
63
+     *
64
+     * @inheritdoc
65
+     */
66
+    constructor(props: Props) {
67
+        super(props);
68
+
69
+        this.panResponder = PanResponder.create({
70
+            onStartShouldSetPanResponder: this._onShouldSetResponder.bind(this),
71
+            onMoveShouldSetPanResponder: this._onShouldSetResponder.bind(this),
72
+            onPanResponderRelease: this._onGestureEnd.bind(this)
73
+        });
74
+    }
75
+
44
     /**
76
     /**
45
      * Implements React's {@link Component#render()}.
77
      * Implements React's {@link Component#render()}.
46
      *
78
      *
66
                         style = { [
98
                         style = { [
67
                             styles.sheetItemContainer,
99
                             styles.sheetItemContainer,
68
                             _styles.sheet
100
                             _styles.sheet
69
-                        ] }>
101
+                        ] }
102
+                        { ...this.panResponder.panHandlers }>
70
                         <ScrollView
103
                         <ScrollView
71
                             bounces = { false }
104
                             bounces = { false }
72
                             showsVerticalScrollIndicator = { false }
105
                             showsVerticalScrollIndicator = { false }
78
             </SlidingView>
111
             </SlidingView>
79
         );
112
         );
80
     }
113
     }
114
+
115
+    /**
116
+     * Callback to handle a gesture end event.
117
+     *
118
+     * @param {Object} evt - The native gesture event.
119
+     * @param {Object} gestureState - The gesture state.
120
+     * @returns {void}
121
+     */
122
+    _onGestureEnd(evt, gestureState) {
123
+        const verticalSwipe = Math.abs(gestureState.vy) > Math.abs(gestureState.vx)
124
+            && Math.abs(gestureState.vy) > GESTURE_SPEED_THRESHOLD;
125
+
126
+        if (verticalSwipe) {
127
+            const direction = gestureState.vy > 0 ? 'down' : 'up';
128
+            const { onCancel, onSwipe } = this.props;
129
+            let isSwipeHandled = false;
130
+
131
+            if (onSwipe) {
132
+                isSwipeHandled = onSwipe(direction);
133
+            }
134
+
135
+            if (direction === 'down' && !isSwipeHandled) {
136
+                // Swipe down is a special gesture that can be used to close the
137
+                // BottomSheet, so if the swipe is not handled by the parent
138
+                // component, we consider it as a request to close.
139
+                onCancel && onCancel();
140
+            }
141
+        }
142
+    }
143
+
144
+    /**
145
+     * Returns true if the pan responder should activate, false otherwise.
146
+     *
147
+     * @param {Object} evt - The native gesture event.
148
+     * @param {Object} gestureState - The gesture state.
149
+     * @returns {boolean}
150
+     */
151
+    _onShouldSetResponder({ nativeEvent }, gestureState) {
152
+        return nativeEvent.touches.length === 1
153
+            && Math.abs(gestureState.dx) > GESTURE_DISTANCE_THRESHOLD
154
+            && Math.abs(gestureState.dy) > GESTURE_DISTANCE_THRESHOLD;
155
+    }
81
 }
156
 }
82
 
157
 
83
 /**
158
 /**

+ 26
- 28
react/features/toolbox/components/native/OverflowMenu.js View File

1
 // @flow
1
 // @flow
2
 
2
 
3
 import React, { PureComponent } from 'react';
3
 import React, { PureComponent } from 'react';
4
-import { Platform, TouchableOpacity } from 'react-native';
4
+import { Platform, TouchableOpacity, View } from 'react-native';
5
 import Collapsible from 'react-native-collapsible';
5
 import Collapsible from 'react-native-collapsible';
6
-import GestureRecognizer, { swipeDirections } from 'react-native-swipe-gestures';
7
 
6
 
8
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
7
 import { ColorSchemeRegistry } from '../../../base/color-scheme';
9
 import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
8
 import { BottomSheet, hideDialog, isDialogOpen } from '../../../base/dialog';
59
 
58
 
60
 type State = {
59
 type State = {
61
 
60
 
61
+    /**
62
+     * True if the bottom scheet is scrolled to the top.
63
+     */
64
+    scrolledToTop: boolean,
65
+
62
     /**
66
     /**
63
      * True if the 'more' button set needas to be rendered.
67
      * True if the 'more' button set needas to be rendered.
64
      */
68
      */
88
         super(props);
92
         super(props);
89
 
93
 
90
         this.state = {
94
         this.state = {
95
+            scrolledToTop: true,
91
             showMore: false
96
             showMore: false
92
         };
97
         };
93
 
98
 
117
         return (
122
         return (
118
             <BottomSheet
123
             <BottomSheet
119
                 onCancel = { this._onCancel }
124
                 onCancel = { this._onCancel }
125
+                onSwipe = { this._onSwipe }
120
                 renderHeader = { this._renderMenuExpandToggle }>
126
                 renderHeader = { this._renderMenuExpandToggle }>
121
                 <AudioRouteButton { ...buttonProps } />
127
                 <AudioRouteButton { ...buttonProps } />
122
                 <ToggleCameraButton { ...buttonProps } />
128
                 <ToggleCameraButton { ...buttonProps } />
152
      */
158
      */
153
     _renderMenuExpandToggle() {
159
     _renderMenuExpandToggle() {
154
         return (
160
         return (
155
-            <GestureRecognizer
156
-                config = {{
157
-                    velocityThreshold: 0.1,
158
-                    directionalOffsetThreshold: 30
159
-                }}
160
-                onSwipe = { this._onSwipe }
161
+            <View
161
                 style = { [
162
                 style = { [
162
                     this.props._bottomSheetStyles.sheet,
163
                     this.props._bottomSheetStyles.sheet,
163
                     styles.expandMenuContainer
164
                     styles.expandMenuContainer
166
                     { /* $FlowFixMeProps */ }
167
                     { /* $FlowFixMeProps */ }
167
                     <IconDragHandle style = { this.props._bottomSheetStyles.expandIcon } />
168
                     <IconDragHandle style = { this.props._bottomSheetStyles.expandIcon } />
168
                 </TouchableOpacity>
169
                 </TouchableOpacity>
169
-            </GestureRecognizer>
170
+            </View>
170
         );
171
         );
171
     }
172
     }
172
 
173
 
188
         return false;
189
         return false;
189
     }
190
     }
190
 
191
 
191
-    _onSwipe: (string) => void;
192
+    _onSwipe: string => void;
192
 
193
 
193
     /**
194
     /**
194
-     * Callback to be invoked when a swipe gesture is detected on the menu.
195
+     * Callback to be invoked when swipe gesture is detected on the menu. Returns true
196
+     * if the swipe gesture is handled by the menu, false otherwise.
195
      *
197
      *
196
-     * @param {string} gestureName - The name of the swipe gesture.
197
-     * @returns {void}
198
+     * @param {string} direction - Direction of 'up' or 'down'.
199
+     * @returns {boolean}
198
      */
200
      */
199
-    _onSwipe(gestureName) {
201
+    _onSwipe(direction) {
200
         const { showMore } = this.state;
202
         const { showMore } = this.state;
201
 
203
 
202
-        switch (gestureName) {
203
-        case swipeDirections.SWIPE_UP:
204
+        switch (direction) {
205
+        case 'up':
204
             !showMore && this.setState({
206
             !showMore && this.setState({
205
                 showMore: true
207
                 showMore: true
206
             });
208
             });
207
-            break;
208
-        case swipeDirections.SWIPE_DOWN:
209
-            if (showMore) {
210
-                // If the menu is expanded, we collapse it.
211
-                this.setState({
212
-                    showMore: false
213
-                });
214
-            } else {
215
-                // If the menu is not expanded, we close the menu
216
-                this._onCancel();
217
-            }
218
-            break;
209
+
210
+            return !showMore;
211
+        case 'down':
212
+            showMore && this.setState({
213
+                showMore: false
214
+            });
215
+
216
+            return showMore;
219
         }
217
         }
220
     }
218
     }
221
 
219
 

+ 5
- 0
react/features/toolbox/components/native/styles.js View File

60
         flexDirection: 'column'
60
         flexDirection: 'column'
61
     },
61
     },
62
 
62
 
63
+    sheetGestureRecognizer: {
64
+        alignItems: 'stretch',
65
+        flexDirection: 'column'
66
+    },
67
+
63
     /**
68
     /**
64
      * The style of the toolbar.
69
      * The style of the toolbar.
65
      */
70
      */

Loading…
Cancel
Save