Browse Source

Implemented collapsible header on major lists and webviews

Arnaud Vergnet 4 years ago
parent
commit
c67e2fa405

+ 1
- 0
package.json View File

@@ -51,6 +51,7 @@
51 51
     "react-native-safe-area-context": "0.7.3",
52 52
     "react-native-screens": "~2.2.0",
53 53
     "react-native-webview": "8.1.1",
54
+    "react-navigation-collapsible": "^5.4.0",
54 55
     "react-navigation-header-buttons": "^3.0.5"
55 56
   },
56 57
   "devDependencies": {

+ 7
- 5
src/components/Custom/BasicLoadingScreen.js View File

@@ -1,8 +1,8 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
+import {View} from 'react-native';
4 5
 import {ActivityIndicator, withTheme} from 'react-native-paper';
5
-import {View} from "react-native";
6 6
 
7 7
 /**
8 8
  * Component used to display a header button
@@ -12,17 +12,19 @@ import {View} from "react-native";
12 12
  */
13 13
 function BasicLoadingScreen(props) {
14 14
     const {colors} = props.theme;
15
+    let position = undefined;
16
+    if (props.isAbsolute !== undefined && props.isAbsolute)
17
+        position = 'absolute';
18
+
15 19
     return (
16 20
         <View style={{
17 21
             backgroundColor: colors.background,
18
-            position: 'absolute',
22
+            position: position,
19 23
             top: 0,
20 24
             right: 0,
21 25
             width: '100%',
22 26
             height: '100%',
23
-            flex: 1,
24
-            alignItems: 'center',
25
-            justifyContent: 'center'
27
+            justifyContent: 'center',
26 28
         }}>
27 29
             <ActivityIndicator
28 30
                 animating={true}

+ 18
- 3
src/components/Lists/WebSectionList.js View File

@@ -7,6 +7,7 @@ import {Snackbar} from 'react-native-paper';
7 7
 import {Animated, RefreshControl, View} from "react-native";
8 8
 import ErrorView from "../Custom/ErrorView";
9 9
 import BasicLoadingScreen from "../Custom/BasicLoadingScreen";
10
+import {withCollapsible} from "../../utils/withCollapsible";
10 11
 
11 12
 type Props = {
12 13
     navigation: Object,
@@ -20,6 +21,7 @@ type Props = {
20 21
     updateData: number,
21 22
     itemHeight: number | null,
22 23
     onScroll: Function,
24
+    collapsibleStack: Object,
23 25
 }
24 26
 
25 27
 type State = {
@@ -31,13 +33,14 @@ type State = {
31 33
 
32 34
 
33 35
 const MIN_REFRESH_TIME = 5 * 1000;
36
+
34 37
 /**
35 38
  * Component used to render a SectionList with data fetched from the web
36 39
  *
37 40
  * This is a pure component, meaning it will only update if a shallow comparison of state and props is different.
38 41
  * To force the component to update, change the value of updateData.
39 42
  */
40
-export default class WebSectionList extends React.PureComponent<Props, State> {
43
+class WebSectionList extends React.PureComponent<Props, State> {
41 44
 
42 45
     static defaultProps = {
43 46
         renderSectionHeader: null,
@@ -171,11 +174,16 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
171 174
         index
172 175
     });
173 176
 
177
+    onListScroll= (event) => {
178
+
179
+    };
180
+
174 181
     render() {
175 182
         let dataset = [];
176 183
         if (this.state.fetchedData !== undefined)
177 184
             dataset = this.props.createDataset(this.state.fetchedData);
178 185
         const shouldRenderHeader = this.props.renderSectionHeader !== null;
186
+        const {containerPaddingTop, scrollIndicatorInsetTop, onScrollWithListener} = this.props.collapsibleStack;
179 187
         return (
180 188
             <View>
181 189
                 {/*$FlowFixMe*/}
@@ -184,6 +192,7 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
184 192
                     extraData={this.props.updateData}
185 193
                     refreshControl={
186 194
                         <RefreshControl
195
+                            progressViewOffset={containerPaddingTop}
187 196
                             refreshing={this.state.refreshing}
188 197
                             onRefresh={this.onRefresh}
189 198
                         />
@@ -193,7 +202,6 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
193 202
                     //$FlowFixMe
194 203
                     renderItem={this.props.renderItem}
195 204
                     stickySectionHeadersEnabled={this.props.stickyHeader}
196
-                    contentContainerStyle={{minHeight: '100%'}}
197 205
                     style={{minHeight: '100%'}}
198 206
                     ListEmptyComponent={this.state.refreshing
199 207
                         ? <BasicLoadingScreen/>
@@ -204,7 +212,12 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
204 212
                     }
205 213
                     getItemLayout={this.props.itemHeight !== null ? this.itemLayout : undefined}
206 214
                     // Animations
207
-                    onScroll={this.props.onScroll}
215
+                    onScroll={onScrollWithListener(this.props.onScroll)}
216
+                    contentContainerStyle={{
217
+                        paddingTop: containerPaddingTop,
218
+                        minHeight: '100%'
219
+                    }}
220
+                    scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
208 221
                 />
209 222
                 <Snackbar
210 223
                     visible={this.state.snackbarVisible}
@@ -222,3 +235,5 @@ export default class WebSectionList extends React.PureComponent<Props, State> {
222 235
         );
223 236
     }
224 237
 }
238
+
239
+export default withCollapsible(WebSectionList);

+ 45
- 6
src/components/Screens/WebViewScreen.js View File

@@ -9,14 +9,18 @@ import MaterialHeaderButtons, {Item} from '../Custom/HeaderButton';
9 9
 import {HiddenItem} from "react-navigation-header-buttons";
10 10
 import {Linking} from "expo";
11 11
 import i18n from 'i18n-js';
12
-import {BackHandler} from "react-native";
12
+import {Animated, BackHandler} from "react-native";
13
+import {withCollapsible} from "../../utils/withCollapsible";
13 14
 
14 15
 type Props = {
15 16
     navigation: Object,
16 17
     url: string,
17 18
     customJS: string,
19
+    collapsibleStack: Object,
18 20
 }
19 21
 
22
+const AnimatedWebView = Animated.createAnimatedComponent(WebView);
23
+
20 24
 /**
21 25
  * Class defining a webview screen.
22 26
  */
@@ -63,7 +67,7 @@ class WebViewScreen extends React.PureComponent<Props> {
63 67
     }
64 68
 
65 69
     onBackButtonPressAndroid = () => {
66
-        if (this.canGoBack){
70
+        if (this.canGoBack) {
67 71
             this.onGoBackClicked();
68 72
             return true;
69 73
         }
@@ -112,15 +116,48 @@ class WebViewScreen extends React.PureComponent<Props> {
112 116
      *
113 117
      * @return {*}
114 118
      */
115
-    getRenderLoading = () => <BasicLoadingScreen/>;
119
+    getRenderLoading = () => <BasicLoadingScreen isAbsolute={true}/>;
120
+
121
+// document.getElementsByTagName('body')[0].style.paddingTop = '100px';
122
+
123
+// $( 'body *' ).filter(function(){
124
+//   var position = $(this).css('position');
125
+//   var top = $(this).css('top');
126
+//   if((position === 'fixed') && top !== 'auto'){
127
+//     console.log(top);
128
+//     $(this).css('top', 'calc(' + top + ' + 100px)');
129
+//     console.log($(this).css('top'));
130
+//   };
131
+// });
132
+
133
+// document.querySelectorAll('body *').forEach(function(node){
134
+//   var style = window.getComputedStyle(node);
135
+//   var position = style.getPropertyValue('position');
136
+//   var top = style.getPropertyValue('top');
137
+//   if((position === 'fixed') && top !== 'auto'){
138
+//     console.log(top);
139
+//     node.style.top = 'calc(' + top + ' + 100px)';
140
+//     console.log(node.style.top);
141
+//   	console.log(node);
142
+//   };
143
+// });
144
+
145
+    getJavascriptPadding(padding: number) {
146
+        return (
147
+            "document.getElementsByTagName('body')[0].style.paddingTop = '" + padding + "px';\n" +
148
+            "true;"
149
+        );
150
+    }
116 151
 
117 152
     render() {
153
+        const {containerPaddingTop, onScroll} = this.props.collapsibleStack;
154
+        const customJS = this.getJavascriptPadding(containerPaddingTop);
118 155
         return (
119
-            <WebView
156
+            <AnimatedWebView
120 157
                 ref={this.webviewRef}
121 158
                 source={{uri: this.props.url}}
122 159
                 startInLoadingState={true}
123
-                injectedJavaScript={this.props.customJS}
160
+                injectedJavaScript={this.props.customJS + customJS}
124 161
                 javaScriptEnabled={true}
125 162
                 renderLoading={this.getRenderLoading}
126 163
                 renderError={() => <ErrorView
@@ -130,9 +167,11 @@ class WebViewScreen extends React.PureComponent<Props> {
130 167
                 onNavigationStateChange={navState => {
131 168
                     this.canGoBack = navState.canGoBack;
132 169
                 }}
170
+                // Animations
171
+                onScroll={onScroll}
133 172
             />
134 173
         );
135 174
     }
136 175
 }
137 176
 
138
-export default WebViewScreen;
177
+export default withCollapsible(WebViewScreen);

+ 170
- 89
src/navigation/DrawerNavigator.js View File

@@ -26,6 +26,8 @@ import {AmicaleWebsiteScreen} from "../screens/Websites/AmicaleWebsiteScreen";
26 26
 import {TutorInsaWebsiteScreen} from "../screens/Websites/TutorInsaWebsiteScreen";
27 27
 import {WiketudWebsiteScreen} from "../screens/Websites/WiketudWebsiteScreen";
28 28
 import {ElusEtudiantsWebsiteScreen} from "../screens/Websites/ElusEtudiantsWebsiteScreen";
29
+import {createCollapsibleStack} from "react-navigation-collapsible";
30
+import {useTheme} from "react-native-paper";
29 31
 
30 32
 const defaultScreenOptions = {
31 33
     gestureEnabled: true,
@@ -106,23 +108,33 @@ function SettingsStackComponent() {
106 108
 const SelfMenuStack = createStackNavigator();
107 109
 
108 110
 function SelfMenuStackComponent() {
111
+    const {colors} = useTheme();
109 112
     return (
110 113
         <SelfMenuStack.Navigator
111 114
             initialRouteName="self-menu"
112 115
             headerMode="float"
113 116
             screenOptions={defaultScreenOptions}
114 117
         >
115
-            <SelfMenuStack.Screen
116
-                name="self-menu"
117
-                component={SelfMenuScreen}
118
-                options={({navigation}) => {
119
-                    const openDrawer = getDrawerButton.bind(this, navigation);
120
-                    return {
121
-                        title: i18n.t('screens.menuSelf'),
122
-                        headerLeft: openDrawer
123
-                    };
124
-                }}
125
-            />
118
+            {createCollapsibleStack(
119
+                <SelfMenuStack.Screen
120
+                    name="self-menu"
121
+                    component={SelfMenuScreen}
122
+                    options={({navigation}) => {
123
+                        const openDrawer = getDrawerButton.bind(this, navigation);
124
+                        return {
125
+                            title: i18n.t('screens.menuSelf'),
126
+                            headerLeft: openDrawer,
127
+                            headerStyle: {
128
+                                backgroundColor: colors.surface,
129
+                            },
130
+                        };
131
+                    }}
132
+                />,
133
+                {
134
+                    collapsedColor: 'transparent',
135
+                    useNativeDriver: true,
136
+                }
137
+            )}
126 138
         </SelfMenuStack.Navigator>
127 139
     );
128 140
 }
@@ -130,23 +142,33 @@ function SelfMenuStackComponent() {
130 142
 const AvailableRoomStack = createStackNavigator();
131 143
 
132 144
 function AvailableRoomStackComponent() {
145
+    const {colors} = useTheme();
133 146
     return (
134 147
         <AvailableRoomStack.Navigator
135 148
             initialRouteName="available-rooms"
136 149
             headerMode="float"
137 150
             screenOptions={defaultScreenOptions}
138 151
         >
139
-            <AvailableRoomStack.Screen
140
-                name="available-rooms"
141
-                component={AvailableRoomScreen}
142
-                options={({navigation}) => {
143
-                    const openDrawer = getDrawerButton.bind(this, navigation);
144
-                    return {
145
-                        title: i18n.t('screens.availableRooms'),
146
-                        headerLeft: openDrawer
147
-                    };
148
-                }}
149
-            />
152
+            {createCollapsibleStack(
153
+                <AvailableRoomStack.Screen
154
+                    name="available-rooms"
155
+                    component={AvailableRoomScreen}
156
+                    options={({navigation}) => {
157
+                        const openDrawer = getDrawerButton.bind(this, navigation);
158
+                        return {
159
+                            title: i18n.t('screens.availableRooms'),
160
+                            headerLeft: openDrawer,
161
+                            headerStyle: {
162
+                                backgroundColor: colors.surface,
163
+                            },
164
+                        };
165
+                    }}
166
+                />,
167
+                {
168
+                    collapsedColor: 'transparent',
169
+                    useNativeDriver: false, // native driver does not work with webview
170
+                }
171
+            )}
150 172
         </AvailableRoomStack.Navigator>
151 173
     );
152 174
 }
@@ -154,23 +176,33 @@ function AvailableRoomStackComponent() {
154 176
 const BibStack = createStackNavigator();
155 177
 
156 178
 function BibStackComponent() {
179
+    const {colors} = useTheme();
157 180
     return (
158 181
         <BibStack.Navigator
159 182
             initialRouteName="bib"
160 183
             headerMode="float"
161 184
             screenOptions={defaultScreenOptions}
162 185
         >
163
-            <BibStack.Screen
164
-                name="bib"
165
-                component={BibScreen}
166
-                options={({navigation}) => {
167
-                    const openDrawer = getDrawerButton.bind(this, navigation);
168
-                    return {
169
-                        title: i18n.t('screens.bib'),
170
-                        headerLeft: openDrawer
171
-                    };
172
-                }}
173
-            />
186
+            {createCollapsibleStack(
187
+                <BibStack.Screen
188
+                    name="bib"
189
+                    component={BibScreen}
190
+                    options={({navigation}) => {
191
+                        const openDrawer = getDrawerButton.bind(this, navigation);
192
+                        return {
193
+                            title: i18n.t('screens.bib'),
194
+                            headerLeft: openDrawer,
195
+                            headerStyle: {
196
+                                backgroundColor: colors.surface,
197
+                            },
198
+                        };
199
+                    }}
200
+                />,
201
+                {
202
+                    collapsedColor: 'transparent',
203
+                    useNativeDriver: false, // native driver does not work with webview
204
+                }
205
+            )}
174 206
         </BibStack.Navigator>
175 207
     );
176 208
 }
@@ -178,23 +210,33 @@ function BibStackComponent() {
178 210
 const AmicaleWebsiteStack = createStackNavigator();
179 211
 
180 212
 function AmicaleWebsiteStackComponent() {
213
+    const {colors} = useTheme();
181 214
     return (
182 215
         <AmicaleWebsiteStack.Navigator
183 216
             initialRouteName="amicale-website"
184 217
             headerMode="float"
185 218
             screenOptions={defaultScreenOptions}
186 219
         >
187
-            <AmicaleWebsiteStack.Screen
188
-                name="amicale-website"
189
-                component={AmicaleWebsiteScreen}
190
-                options={({navigation}) => {
191
-                    const openDrawer = getDrawerButton.bind(this, navigation);
192
-                    return {
193
-                        title: "Amicale",
194
-                        headerLeft: openDrawer
195
-                    };
196
-                }}
197
-            />
220
+            {createCollapsibleStack(
221
+                <AmicaleWebsiteStack.Screen
222
+                    name="amicale-website"
223
+                    component={AmicaleWebsiteScreen}
224
+                    options={({navigation}) => {
225
+                        const openDrawer = getDrawerButton.bind(this, navigation);
226
+                        return {
227
+                            title: "Amicale",
228
+                            headerLeft: openDrawer,
229
+                            headerStyle: {
230
+                                backgroundColor: colors.surface,
231
+                            },
232
+                        };
233
+                    }}
234
+                />,
235
+                {
236
+                    collapsedColor: 'transparent',
237
+                    useNativeDriver: false, // native driver does not work with webview
238
+                }
239
+            )}
198 240
         </AmicaleWebsiteStack.Navigator>
199 241
     );
200 242
 }
@@ -202,23 +244,33 @@ function AmicaleWebsiteStackComponent() {
202 244
 const ElusEtudiantsStack = createStackNavigator();
203 245
 
204 246
 function ElusEtudiantsStackComponent() {
247
+    const {colors} = useTheme();
205 248
     return (
206 249
         <ElusEtudiantsStack.Navigator
207 250
             initialRouteName="elus-etudiants"
208 251
             headerMode="float"
209 252
             screenOptions={defaultScreenOptions}
210 253
         >
211
-            <ElusEtudiantsStack.Screen
212
-                name="elus-etudiants"
213
-                component={ElusEtudiantsWebsiteScreen}
214
-                options={({navigation}) => {
215
-                    const openDrawer = getDrawerButton.bind(this, navigation);
216
-                    return {
217
-                        title: "Élus Étudiants",
218
-                        headerLeft: openDrawer
219
-                    };
220
-                }}
221
-            />
254
+            {createCollapsibleStack(
255
+                <ElusEtudiantsStack.Screen
256
+                    name="elus-etudiants"
257
+                    component={ElusEtudiantsWebsiteScreen}
258
+                    options={({navigation}) => {
259
+                        const openDrawer = getDrawerButton.bind(this, navigation);
260
+                        return {
261
+                            title: "Élus Étudiants",
262
+                            headerLeft: openDrawer,
263
+                            headerStyle: {
264
+                                backgroundColor: colors.surface,
265
+                            },
266
+                        };
267
+                    }}
268
+                />,
269
+                {
270
+                    collapsedColor: 'transparent',
271
+                    useNativeDriver: false, // native driver does not work with webview
272
+                }
273
+            )}
222 274
         </ElusEtudiantsStack.Navigator>
223 275
     );
224 276
 }
@@ -226,23 +278,33 @@ function ElusEtudiantsStackComponent() {
226 278
 const WiketudStack = createStackNavigator();
227 279
 
228 280
 function WiketudStackComponent() {
281
+    const {colors} = useTheme();
229 282
     return (
230 283
         <WiketudStack.Navigator
231 284
             initialRouteName="wiketud"
232 285
             headerMode="float"
233 286
             screenOptions={defaultScreenOptions}
234 287
         >
235
-            <WiketudStack.Screen
236
-                name="wiketud"
237
-                component={WiketudWebsiteScreen}
238
-                options={({navigation}) => {
239
-                    const openDrawer = getDrawerButton.bind(this, navigation);
240
-                    return {
241
-                        title: "Wiketud",
242
-                        headerLeft: openDrawer
243
-                    };
244
-                }}
245
-            />
288
+            {createCollapsibleStack(
289
+                <WiketudStack.Screen
290
+                    name="wiketud"
291
+                    component={WiketudWebsiteScreen}
292
+                    options={({navigation}) => {
293
+                        const openDrawer = getDrawerButton.bind(this, navigation);
294
+                        return {
295
+                            title: "Wiketud",
296
+                            headerLeft: openDrawer,
297
+                            headerStyle: {
298
+                                backgroundColor: colors.surface,
299
+                            },
300
+                        };
301
+                    }}
302
+                />,
303
+                {
304
+                    collapsedColor: 'transparent',
305
+                    useNativeDriver: false, // native driver does not work with webview
306
+                }
307
+            )}
246 308
         </WiketudStack.Navigator>
247 309
     );
248 310
 }
@@ -250,29 +312,38 @@ function WiketudStackComponent() {
250 312
 const TutorInsaStack = createStackNavigator();
251 313
 
252 314
 function TutorInsaStackComponent() {
315
+    const {colors} = useTheme();
253 316
     return (
254 317
         <TutorInsaStack.Navigator
255 318
             initialRouteName="tutorinsa"
256 319
             headerMode="float"
257 320
             screenOptions={defaultScreenOptions}
258 321
         >
259
-            <TutorInsaStack.Screen
260
-                name="tutorinsa"
261
-                component={TutorInsaWebsiteScreen}
262
-                options={({navigation}) => {
263
-                    const openDrawer = getDrawerButton.bind(this, navigation);
264
-                    return {
265
-                        title: "Tutor'INSA",
266
-                        headerLeft: openDrawer
267
-                    };
268
-                }}
269
-            />
322
+            {createCollapsibleStack(
323
+                <TutorInsaStack.Screen
324
+                    name="tutorinsa"
325
+                    component={TutorInsaWebsiteScreen}
326
+                    options={({navigation}) => {
327
+                        const openDrawer = getDrawerButton.bind(this, navigation);
328
+                        return {
329
+                            title: "Tutor'INSA",
330
+                            headerLeft: openDrawer,
331
+                            headerStyle: {
332
+                                backgroundColor: colors.surface,
333
+                            },
334
+                        };
335
+                    }}
336
+                />,
337
+                {
338
+                    collapsedColor: 'transparent',
339
+                    useNativeDriver: false, // native driver does not work with webview
340
+                }
341
+            )}
270 342
         </TutorInsaStack.Navigator>
271 343
     );
272 344
 }
273 345
 
274 346
 
275
-
276 347
 const TetrisStack = createStackNavigator();
277 348
 
278 349
 function TetrisStackComponent() {
@@ -408,23 +479,33 @@ function AmicaleContactStackComponent() {
408 479
 const ClubStack = createStackNavigator();
409 480
 
410 481
 function ClubStackComponent() {
482
+    const {colors} = useTheme();
411 483
     return (
412 484
         <ClubStack.Navigator
413 485
             initialRouteName={"club-list"}
414 486
             headerMode="float"
415 487
             screenOptions={defaultScreenOptions}
416 488
         >
417
-            <ClubStack.Screen
418
-                name="club-list"
419
-                component={ClubListScreen}
420
-                options={({navigation}) => {
421
-                    const openDrawer = getDrawerButton.bind(this, navigation);
422
-                    return {
423
-                        title: i18n.t('clubs.clubList'),
424
-                        headerLeft: openDrawer
425
-                    };
426
-                }}
427
-            />
489
+            {createCollapsibleStack(
490
+                <ClubStack.Screen
491
+                    name="club-list"
492
+                    component={ClubListScreen}
493
+                    options={({navigation}) => {
494
+                        const openDrawer = getDrawerButton.bind(this, navigation);
495
+                        return {
496
+                            title: i18n.t('clubs.clubList'),
497
+                            headerLeft: openDrawer,
498
+                            headerStyle: {
499
+                                backgroundColor: colors.surface,
500
+                            },
501
+                        };
502
+                    }}
503
+                />,
504
+                {
505
+                    collapsedColor: 'transparent',
506
+                    useNativeDriver: true,
507
+                }
508
+            )}
428 509
             <ClubStack.Screen
429 510
                 name="club-information"
430 511
                 component={ClubDisplayScreen}

+ 104
- 54
src/navigation/MainTabNavigator.js View File

@@ -13,12 +13,13 @@ import ProximoAboutScreen from "../screens/Proximo/ProximoAboutScreen";
13 13
 import PlanexScreen from '../screens/Websites/PlanexScreen';
14 14
 import {MaterialCommunityIcons} from "@expo/vector-icons";
15 15
 import AsyncStorageManager from "../managers/AsyncStorageManager";
16
-import {withTheme} from 'react-native-paper';
16
+import {useTheme, withTheme} from 'react-native-paper';
17 17
 import i18n from "i18n-js";
18 18
 import ClubDisplayScreen from "../screens/Amicale/Clubs/ClubDisplayScreen";
19 19
 import ScannerScreen from "../screens/ScannerScreen";
20 20
 import MaterialHeaderButtons, {Item} from "../components/Custom/HeaderButton";
21 21
 import FeedItemScreen from "../screens/FeedItemScreen";
22
+import {createCollapsibleStack} from "react-navigation-collapsible";
22 23
 
23 24
 
24 25
 const TAB_ICONS = {
@@ -46,30 +47,49 @@ function getDrawerButton(navigation: Object) {
46 47
 const ProximoStack = createStackNavigator();
47 48
 
48 49
 function ProximoStackComponent() {
50
+    const {colors} = useTheme();
49 51
     return (
50 52
         <ProximoStack.Navigator
51 53
             initialRouteName="index"
52 54
             headerMode="float"
53 55
             screenOptions={defaultScreenOptions}
54 56
         >
55
-            <ProximoStack.Screen
56
-                name="index"
57
-                options={({navigation}) => {
58
-                    const openDrawer = getDrawerButton.bind(this, navigation);
59
-                    return {
60
-                        title: 'Proximo',
61
-                        headerLeft: openDrawer
62
-                    };
63
-                }}
64
-                component={ProximoMainScreen}
65
-            />
66
-            <ProximoStack.Screen
67
-                name="proximo-list"
68
-                options={{
69
-                    title: i18n.t('screens.proximoArticles')
70
-                }}
71
-                component={ProximoListScreen}
72
-            />
57
+            {createCollapsibleStack(
58
+                <ProximoStack.Screen
59
+                    name="index"
60
+                    options={({navigation}) => {
61
+                        const openDrawer = getDrawerButton.bind(this, navigation);
62
+                        return {
63
+                            title: 'Proximo',
64
+                            headerLeft: openDrawer,
65
+                            headerStyle: {
66
+                                backgroundColor: colors.surface,
67
+                            },
68
+                        };
69
+                    }}
70
+                    component={ProximoMainScreen}
71
+                />,
72
+                {
73
+                    collapsedColor: 'transparent',
74
+                    useNativeDriver: true,
75
+                }
76
+            )}
77
+            {createCollapsibleStack(
78
+                <ProximoStack.Screen
79
+                    name="proximo-list"
80
+                    options={{
81
+                        title: i18n.t('screens.proximoArticles'),
82
+                        headerStyle: {
83
+                            backgroundColor: colors.surface,
84
+                        }
85
+                    }}
86
+                    component={ProximoListScreen}
87
+                />,
88
+                {
89
+                    collapsedColor: 'transparent',
90
+                    useNativeDriver: true,
91
+                }
92
+            )}
73 93
             <ProximoStack.Screen
74 94
                 name="proximo-about"
75 95
                 component={ProximoAboutScreen}
@@ -85,23 +105,33 @@ function ProximoStackComponent() {
85 105
 const ProxiwashStack = createStackNavigator();
86 106
 
87 107
 function ProxiwashStackComponent() {
108
+    const {colors} = useTheme();
88 109
     return (
89 110
         <ProxiwashStack.Navigator
90 111
             initialRouteName="index"
91 112
             headerMode='float'
92 113
             screenOptions={defaultScreenOptions}
93 114
         >
94
-            <ProxiwashStack.Screen
95
-                name="index"
96
-                component={ProxiwashScreen}
97
-                options={({navigation}) => {
98
-                    const openDrawer = getDrawerButton.bind(this, navigation);
99
-                    return {
100
-                        title: i18n.t('screens.proxiwash'),
101
-                        headerLeft: openDrawer
102
-                    };
103
-                }}
104
-            />
115
+            {createCollapsibleStack(
116
+                <ProxiwashStack.Screen
117
+                    name="index"
118
+                    component={ProxiwashScreen}
119
+                    options={({navigation}) => {
120
+                        const openDrawer = getDrawerButton.bind(this, navigation);
121
+                        return {
122
+                            title: i18n.t('screens.proxiwash'),
123
+                            headerLeft: openDrawer,
124
+                            headerStyle: {
125
+                                backgroundColor: colors.surface,
126
+                            },
127
+                        };
128
+                    }}
129
+                />,
130
+                {
131
+                    collapsedColor: 'transparent',
132
+                    useNativeDriver: true,
133
+                }
134
+            )}
105 135
             <ProxiwashStack.Screen
106 136
                 name="proxiwash-about"
107 137
                 component={ProxiwashAboutScreen}
@@ -117,6 +147,7 @@ function ProxiwashStackComponent() {
117 147
 const PlanningStack = createStackNavigator();
118 148
 
119 149
 function PlanningStackComponent() {
150
+    const {colors} = useTheme();
120 151
     return (
121 152
         <PlanningStack.Navigator
122 153
             initialRouteName="index"
@@ -152,25 +183,34 @@ function HomeStackComponent(initialRoute: string | null, defaultData: Object) {
152 183
     let data;
153 184
     if (initialRoute !== null)
154 185
         data = {data: defaultData, nextScreen: initialRoute, shouldOpen: true};
155
-
186
+    const {colors} = useTheme();
156 187
     return (
157 188
         <HomeStack.Navigator
158 189
             initialRouteName={"index"}
159 190
             headerMode="float"
160 191
             screenOptions={defaultScreenOptions}
161 192
         >
162
-            <HomeStack.Screen
163
-                name="index"
164
-                component={HomeScreen}
165
-                options={({navigation}) => {
166
-                    const openDrawer = getDrawerButton.bind(this, navigation);
167
-                    return {
168
-                        title: i18n.t('screens.home'),
169
-                        headerLeft: openDrawer
170
-                    };
171
-                }}
172
-                initialParams={data}
173
-            />
193
+            {createCollapsibleStack(
194
+                <HomeStack.Screen
195
+                    name="index"
196
+                    component={HomeScreen}
197
+                    options={({navigation}) => {
198
+                        const openDrawer = getDrawerButton.bind(this, navigation);
199
+                        return {
200
+                            title: i18n.t('screens.home'),
201
+                            headerLeft: openDrawer,
202
+                            headerStyle: {
203
+                                backgroundColor: colors.surface,
204
+                            },
205
+                        };
206
+                    }}
207
+                    initialParams={data}
208
+                />,
209
+                {
210
+                    collapsedColor: 'transparent',
211
+                    useNativeDriver: true,
212
+                }
213
+            )}
174 214
             <HomeStack.Screen
175 215
                 name="home-planning-information"
176 216
                 component={PlanningDisplayScreen}
@@ -216,23 +256,33 @@ function HomeStackComponent(initialRoute: string | null, defaultData: Object) {
216 256
 const PlanexStack = createStackNavigator();
217 257
 
218 258
 function PlanexStackComponent() {
259
+    const {colors} = useTheme();
219 260
     return (
220 261
         <PlanexStack.Navigator
221 262
             initialRouteName="index"
222 263
             headerMode="float"
223 264
             screenOptions={defaultScreenOptions}
224 265
         >
225
-            <PlanexStack.Screen
226
-                name="index"
227
-                component={PlanexScreen}
228
-                options={({navigation}) => {
229
-                    const openDrawer = getDrawerButton.bind(this, navigation);
230
-                    return {
231
-                        title: 'Planex',
232
-                        headerLeft: openDrawer
233
-                    };
234
-                }}
235
-            />
266
+            {createCollapsibleStack(
267
+                <PlanexStack.Screen
268
+                    name="index"
269
+                    component={PlanexScreen}
270
+                    options={({navigation}) => {
271
+                        const openDrawer = getDrawerButton.bind(this, navigation);
272
+                        return {
273
+                            title: 'Planex',
274
+                            headerLeft: openDrawer,
275
+                            headerStyle: {
276
+                                backgroundColor: colors.surface,
277
+                            },
278
+                        };
279
+                    }}
280
+                />,
281
+                {
282
+                    collapsedColor: 'transparent',
283
+                    useNativeDriver: false, // native driver does not work with webview
284
+                }
285
+            )}
236 286
         </PlanexStack.Navigator>
237 287
     );
238 288
 }

+ 10
- 3
src/screens/Amicale/Clubs/ClubListScreen.js View File

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {FlatList, Platform} from "react-native";
4
+import {Animated, Platform} from "react-native";
5 5
 import {Chip, Searchbar, withTheme} from 'react-native-paper';
6 6
 import AuthenticatedScreen from "../../../components/Amicale/AuthenticatedScreen";
7 7
 import i18n from "i18n-js";
@@ -9,10 +9,12 @@ import ClubListItem from "../../../components/Lists/ClubListItem";
9 9
 import {isItemInCategoryFilter, stringMatchQuery} from "../../../utils/Search";
10 10
 import ClubListHeader from "../../../components/Lists/ClubListHeader";
11 11
 import MaterialHeaderButtons, {Item} from "../../../components/Custom/HeaderButton";
12
+import {withCollapsible} from "../../../utils/withCollapsible";
12 13
 
13 14
 type Props = {
14 15
     navigation: Object,
15 16
     theme: Object,
17
+    collapsibleStack: Object,
16 18
 }
17 19
 
18 20
 type State = {
@@ -94,9 +96,10 @@ class ClubListScreen extends React.Component<Props, State> {
94 96
 
95 97
     getScreen = (data: Object) => {
96 98
         this.categories = data[0].categories;
99
+        const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
97 100
         return (
98 101
             //$FlowFixMe
99
-            <FlatList
102
+            <Animated.FlatList
100 103
                 data={data[0].clubs}
101 104
                 keyExtractor={this.keyExtractor}
102 105
                 renderItem={this.getRenderItem}
@@ -104,6 +107,10 @@ class ClubListScreen extends React.Component<Props, State> {
104 107
                 // Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
105 108
                 removeClippedSubviews={true}
106 109
                 getItemLayout={this.itemLayout}
110
+                // Animations
111
+                onScroll={onScroll}
112
+                contentContainerStyle={{paddingTop: containerPaddingTop}}
113
+                scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
107 114
             />
108 115
         )
109 116
     };
@@ -208,4 +215,4 @@ class ClubListScreen extends React.Component<Props, State> {
208 215
     }
209 216
 }
210 217
 
211
-export default withTheme(ClubListScreen);
218
+export default withCollapsible(withTheme(ClubListScreen));

+ 10
- 3
src/screens/Proximo/ProximoListScreen.js View File

@@ -1,13 +1,14 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {FlatList, Image, Platform, ScrollView, View} from "react-native";
4
+import {Animated, Image, Platform, ScrollView, View} from "react-native";
5 5
 import i18n from "i18n-js";
6 6
 import CustomModal from "../../components/Custom/CustomModal";
7 7
 import {RadioButton, Searchbar, Subheading, Text, Title, withTheme} from "react-native-paper";
8 8
 import {stringMatchQuery} from "../../utils/Search";
9 9
 import ProximoListItem from "../../components/Lists/ProximoListItem";
10 10
 import MaterialHeaderButtons, {Item} from "../../components/Custom/HeaderButton";
11
+import {withCollapsible} from "../../utils/withCollapsible";
11 12
 
12 13
 function sortPrice(a, b) {
13 14
     return a.price - b.price;
@@ -39,6 +40,7 @@ type Props = {
39 40
     navigation: Object,
40 41
     route: Object,
41 42
     theme: Object,
43
+    collapsibleStack: Object,
42 44
 }
43 45
 
44 46
 type State = {
@@ -295,6 +297,7 @@ class ProximoListScreen extends React.Component<Props, State> {
295 297
     itemLayout = (data, index) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
296 298
 
297 299
     render() {
300
+        const {containerPaddingTop, scrollIndicatorInsetTop, onScroll} = this.props.collapsibleStack;
298 301
         return (
299 302
             <View style={{
300 303
                 height: '100%'
@@ -303,7 +306,7 @@ class ProximoListScreen extends React.Component<Props, State> {
303 306
                     {this.state.modalCurrentDisplayItem}
304 307
                 </CustomModal>
305 308
                 {/*$FlowFixMe*/}
306
-                <FlatList
309
+                <Animated.FlatList
307 310
                     data={this.listData}
308 311
                     extraData={this.state.currentSearchString + this.state.currentSortMode}
309 312
                     keyExtractor={this.keyExtractor}
@@ -312,10 +315,14 @@ class ProximoListScreen extends React.Component<Props, State> {
312 315
                     removeClippedSubviews={true}
313 316
                     getItemLayout={this.itemLayout}
314 317
                     initialNumToRender={10}
318
+                    // Animations
319
+                    onScroll={onScroll}
320
+                    contentContainerStyle={{paddingTop: containerPaddingTop}}
321
+                    scrollIndicatorInsets={{top: scrollIndicatorInsetTop}}
315 322
                 />
316 323
             </View>
317 324
         );
318 325
     }
319 326
 }
320 327
 
321
-export default withTheme(ProximoListScreen);
328
+export default withCollapsible(withTheme(ProximoListScreen));

+ 8
- 0
src/utils/withCollapsible.js View File

@@ -0,0 +1,8 @@
1
+import React from 'react';
2
+import {useCollapsibleStack} from "react-navigation-collapsible";
3
+
4
+export const withCollapsible = (Component: any) => {
5
+    return (props: any) => {
6
+        return <Component collapsibleStack={useCollapsibleStack()} {...props} />;
7
+    };
8
+};

Loading…
Cancel
Save