Browse Source

Merge branch 'dev'

keplyx 4 years ago
parent
commit
e3e5dac314

+ 10
- 3
App.js View File

@@ -31,9 +31,16 @@ export default class App extends React.Component<Props, State> {
31 31
         currentTheme: null,
32 32
     };
33 33
 
34
+    onIntroDone: Function;
35
+    loadAssetsAsync: Function;
36
+    onLoadFinished: Function;
37
+
34 38
     constructor(props: Object) {
35 39
         super(props);
36 40
         LocaleManager.initTranslations();
41
+        this.onIntroDone = this.onIntroDone.bind(this);
42
+        this.loadAssetsAsync = this.loadAssetsAsync.bind(this);
43
+        this.onLoadFinished = this.onLoadFinished.bind(this);
37 44
     }
38 45
 
39 46
     /**
@@ -102,14 +109,14 @@ export default class App extends React.Component<Props, State> {
102 109
         if (this.state.isLoading) {
103 110
             return (
104 111
                 <AppLoading
105
-                    startAsync={() => this.loadAssetsAsync()}
106
-                    onFinish={() => this.onLoadFinished()}
112
+                    startAsync={this.loadAssetsAsync}
113
+                    onFinish={this.onLoadFinished}
107 114
                     onError={console.warn}
108 115
                 />
109 116
             );
110 117
         }
111 118
         if (this.state.showIntro || this.state.showUpdate) {
112
-            return <CustomIntroSlider onDone={() => this.onIntroDone()}
119
+            return <CustomIntroSlider onDone={this.onIntroDone}
113 120
                                       isUpdate={this.state.showUpdate && !this.state.showIntro}/>;
114 121
         } else {
115 122
             const AppNavigator = createAppContainerWithInitialRoute(AsyncStorageManager.getInstance().preferences.defaultStartScreen.current);

+ 1
- 1
README.md View File

@@ -13,7 +13,7 @@ Ce dépot contient les sources de cette application, modifiable par les étudian
13 13
 
14 14
 Vous voulez influencer le développement ? C'est très simple !
15 15
 
16
-Pas besoin de connaissance, il est possible d'aider simplement en proposant des améliorations ou en rapportant des bugs par mail (vergnet@etud.insa-toulouse.fr) ou sur [cette page](https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/issues), en vous connectant avec vos login INSA.
16
+Pas besoin de connaissance, il est possible d'aider simplement en proposant des améliorations ou en rapportant des bugs par mail (vergnet@etud.insa-toulouse.fr) ou sur [cette page](https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues), en vous connectant avec vos login INSA.
17 17
 
18 18
 Si vous avez assez de connaissances et vous souhaitez proposer des modifications dans le code, installez l'application sur votre machine, réalisez votre modification et créez une 'pull request'.
19 19
 

+ 2
- 2
app.json View File

@@ -10,7 +10,7 @@
10 10
       "android",
11 11
       "web"
12 12
     ],
13
-    "version": "1.5.0",
13
+    "version": "1.5.1",
14 14
     "orientation": "portrait",
15 15
     "primaryColor": "#be1522",
16 16
     "icon": "./assets/android.icon.png",
@@ -36,7 +36,7 @@
36 36
     },
37 37
     "android": {
38 38
       "package": "fr.amicaleinsat.application",
39
-      "versionCode": 13,
39
+      "versionCode": 14,
40 40
       "icon": "./assets/android.icon.png",
41 41
       "adaptiveIcon": {
42 42
         "foregroundImage": "./assets/android.adaptive-icon.png",

BIN
assets/icon.png View File


BIN
assets/image-missing.png View File


+ 49
- 32
components/BaseContainer.js View File

@@ -30,7 +30,6 @@ type State = {
30 30
 
31 31
 
32 32
 export default class BaseContainer extends React.Component<Props, State> {
33
-
34 33
     static defaultProps = {
35 34
         headerRightButton: <View/>,
36 35
         hasTabs: false,
@@ -46,40 +45,61 @@ export default class BaseContainer extends React.Component<Props, State> {
46 45
         isHeaderVisible: true,
47 46
     };
48 47
 
49
-    toggle() {
48
+    onDrawerPress: Function;
49
+    onWillFocus: Function;
50
+    onWillBlur: Function;
51
+    onChangeOrientation: Function;
52
+
53
+    constructor() {
54
+        super();
55
+        this.onDrawerPress = this.onDrawerPress.bind(this);
56
+        this.onWillFocus = this.onWillFocus.bind(this);
57
+        this.onWillBlur = this.onWillBlur.bind(this);
58
+        this.onChangeOrientation = this.onChangeOrientation.bind(this);
59
+    }
60
+
61
+    onDrawerPress() {
50 62
         this.props.navigation.toggleDrawer();
51 63
     }
64
+
65
+    onWillFocus() {
66
+        if (this.props.enableRotation) {
67
+            ScreenOrientation.unlockAsync();
68
+            ScreenOrientation.addOrientationChangeListener(this.onChangeOrientation);
69
+        }
70
+    }
71
+
72
+    onWillBlur() {
73
+        if (this.props.enableRotation)
74
+            ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT);
75
+    }
76
+
77
+    onChangeOrientation(OrientationChangeEvent) {
78
+        if (this.props.hideHeaderOnLandscape) {
79
+            let isLandscape = OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE ||
80
+                OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
81
+                OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
82
+            this.setState({isHeaderVisible: !isLandscape});
83
+            const setParamsAction = NavigationActions.setParams({
84
+                params: {showTabBar: !isLandscape},
85
+                key: this.props.navigation.state.key,
86
+            });
87
+            this.props.navigation.dispatch(setParamsAction);
88
+            StatusBar.setHidden(isLandscape);
89
+        }
90
+    }
91
+
52 92
     /**
53 93
      * Register for blur event to close side menu on screen change
54 94
      */
55 95
     componentDidMount() {
56 96
         this.willFocusSubscription = this.props.navigation.addListener(
57 97
             'willFocus',
58
-            () => {
59
-                if (this.props.enableRotation) {
60
-                    ScreenOrientation.unlockAsync();
61
-                    ScreenOrientation.addOrientationChangeListener((OrientationChangeEvent) => {
62
-                        if (this.props.hideHeaderOnLandscape) {
63
-                            let isLandscape = OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE ||
64
-                                OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_LEFT ||
65
-                                OrientationChangeEvent.orientationInfo.orientation === ScreenOrientation.Orientation.LANDSCAPE_RIGHT;
66
-                            this.setState({isHeaderVisible: !isLandscape});
67
-                            const setParamsAction = NavigationActions.setParams({
68
-                                params: {showTabBar: !isLandscape},
69
-                                key: this.props.navigation.state.key,
70
-                            });
71
-                            this.props.navigation.dispatch(setParamsAction);
72
-                            StatusBar.setHidden(isLandscape);
73
-                        }
74
-                    });
75
-                }
76
-            });
98
+            this.onWillFocus
99
+        );
77 100
         this.willBlurSubscription = this.props.navigation.addListener(
78 101
             'willBlur',
79
-            () => {
80
-                if (this.props.enableRotation)
81
-                    ScreenOrientation.lockAsync(ScreenOrientation.Orientation.PORTRAIT);
82
-            }
102
+            this.onWillBlur
83 103
         );
84 104
     }
85 105
 
@@ -93,7 +113,9 @@ export default class BaseContainer extends React.Component<Props, State> {
93 113
             this.willFocusSubscription.remove();
94 114
     }
95 115
 
96
-    getMainContainer() {
116
+
117
+    render() {
118
+        // console.log("rendering BaseContainer");
97 119
         return (
98 120
             <Container>
99 121
                 {this.state.isHeaderVisible ?
@@ -104,7 +126,7 @@ export default class BaseContainer extends React.Component<Props, State> {
104 126
                         leftButton={
105 127
                             <Touchable
106 128
                                 style={{padding: 6}}
107
-                                onPress={() => this.toggle()}>
129
+                                onPress={this.onDrawerPress}>
108 130
                                 <CustomMaterialIcon
109 131
                                     color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
110 132
                                     icon="menu"/>
@@ -118,9 +140,4 @@ export default class BaseContainer extends React.Component<Props, State> {
118 140
             </Container>
119 141
         );
120 142
     }
121
-
122
-
123
-    render() {
124
-        return (this.getMainContainer());
125
-    }
126 143
 }

+ 29
- 9
components/CustomHeader.js View File

@@ -32,11 +32,10 @@ type Props = {
32 32
  * @prop navigation {Object} The navigation object from react navigation
33 33
  */
34 34
 export default class CustomHeader extends React.Component<Props> {
35
-
36 35
     static defaultProps = {
37 36
         hasBackButton: false,
38 37
         hasSearchField: false,
39
-        searchCallback: () => null,
38
+        searchCallback: null,
40 39
         shouldFocusSearchBar: false,
41 40
         title: '',
42 41
         subtitle: '',
@@ -45,10 +44,28 @@ export default class CustomHeader extends React.Component<Props> {
45 44
         hasTabs: false,
46 45
     };
47 46
 
47
+    onPressBack: Function;
48
+
49
+    constructor() {
50
+        super();
51
+        this.onPressBack = this.onPressBack.bind(this);
52
+    }
53
+
54
+    shouldComponentUpdate(nextProps: Props): boolean {
55
+        return nextProps.title !== this.props.title ||
56
+            nextProps.subtitle !== this.props.subtitle ||
57
+            nextProps.hasBackButton !== this.props.hasBackButton ||
58
+            nextProps.hasSearchField !== this.props.hasSearchField ||
59
+            nextProps.shouldFocusSearchBar !== this.props.shouldFocusSearchBar ||
60
+            nextProps.hasTabs !== this.props.hasTabs ||
61
+            nextProps.rightButton !== this.props.rightButton ||
62
+            nextProps.leftButton !== this.props.leftButton;
63
+    }
64
+
48 65
     componentDidMount() {
49 66
         if (this.refs.searchInput !== undefined && this.refs.searchInput._root !== undefined && this.props.shouldFocusSearchBar) {
50
-            // does not work if called to early for some reason...
51
-            setTimeout(() => this.refs.searchInput._root.focus(), 500);
67
+            // does not work if called too early for some reason...
68
+            setTimeout(this.refs.searchInput._root.focus, 500);
52 69
         }
53 70
     }
54 71
 
@@ -67,7 +84,7 @@ export default class CustomHeader extends React.Component<Props> {
67 84
                         ref="searchInput"
68 85
                         placeholder={i18n.t('proximoScreen.search')}
69 86
                         placeholderTextColor={ThemeManager.getCurrentThemeVariables().toolbarPlaceholderColor}
70
-                        onChangeText={(text) => this.props.searchCallback(text)}/>
87
+                        onChangeText={this.props.searchCallback}/>
71 88
                 </Item>
72 89
             </Body>
73 90
         );
@@ -87,17 +104,20 @@ export default class CustomHeader extends React.Component<Props> {
87 104
     }
88 105
 
89 106
 
107
+    onPressBack() {
108
+        const backAction = NavigationActions.back();
109
+        this.props.navigation.dispatch(backAction);
110
+    }
111
+
90 112
     render() {
113
+        // console.log("rendering CustomHeader");
91 114
         let button;
92 115
         // Does the app have a back button or a burger menu ?
93 116
         if (this.props.hasBackButton)
94 117
             button =
95 118
                 <Touchable
96 119
                     style={{padding: 6}}
97
-                    onPress={() => {
98
-                        const backAction = NavigationActions.back();
99
-                        this.props.navigation.dispatch(backAction);
100
-                    }}>
120
+                    onPress={this.onPressBack}>
101 121
                     <CustomMaterialIcon
102 122
                         color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
103 123
                         icon={Platform.OS === 'ios' ? 'chevron-left' : "arrow-left"}/>

+ 3
- 3
components/CustomIntroSlider.js View File

@@ -117,7 +117,7 @@ export default class CustomIntroSlider extends React.Component<Props> {
117 117
      * @param item
118 118
      * @param dimensions
119 119
      */
120
-    static getIntroRenderItem(item: Object, dimensions: Object) {
120
+    static getIntroRenderItem({item, dimensions}: Object) {
121 121
 
122 122
         return (
123 123
             <LinearGradient
@@ -143,9 +143,9 @@ export default class CustomIntroSlider extends React.Component<Props> {
143 143
     render() {
144 144
         return (
145 145
             <AppIntroSlider
146
-                renderItem={({item, dimensions}) => CustomIntroSlider.getIntroRenderItem(item, dimensions)}
146
+                renderItem={CustomIntroSlider.getIntroRenderItem}
147 147
                 slides={this.props.isUpdate ? this.updateSlides : this.introSlides}
148
-                onDone={() => this.props.onDone()}
148
+                onDone={this.props.onDone}
149 149
                 bottomButton
150 150
                 showSkipButton
151 151
                 skipLabel={i18n.t('intro.buttons.skip')}

+ 9
- 0
components/CustomMaterialIcon.js View File

@@ -30,7 +30,16 @@ export default class CustomMaterialIcon extends React.Component<Props> {
30 30
         width: 30,
31 31
     };
32 32
 
33
+    shouldComponentUpdate(nextProps: Props): boolean {
34
+        return nextProps.icon !== this.props.icon ||
35
+            nextProps.active !== this.props.active ||
36
+            nextProps.width !== this.props.width ||
37
+            nextProps.fontSize !== this.props.fontSize ||
38
+            nextProps.color !== this.props.color;
39
+    }
40
+
33 41
     render() {
42
+        // console.log("rendering icon " + this.props.icon);
34 43
         return (
35 44
             <Icon
36 45
                 active

+ 7
- 1
components/DashboardItem.js View File

@@ -25,13 +25,18 @@ type Props = {
25 25
 }
26 26
 
27 27
 export default class DashboardItem extends React.Component<Props> {
28
-
29 28
     static defaultProps = {
30 29
         isSquare: false,
31 30
         isSquareLeft: true,
32 31
         displayEvent: undefined,
33 32
     };
34 33
 
34
+    shouldComponentUpdate(nextProps: Props): boolean {
35
+        return nextProps.isAvailable !== this.props.isAvailable ||
36
+            nextProps.subtitle !== this.props.subtitle;
37
+    }
38
+
39
+
35 40
     /**
36 41
      * Convert the date string given by in the event list json to a date object
37 42
      * @param dateString
@@ -203,6 +208,7 @@ export default class DashboardItem extends React.Component<Props> {
203 208
 
204 209
 
205 210
     render() {
211
+        // console.log("rendering DashboardItem " + this.props.title);
206 212
         let marginRight = 10;
207 213
         if (this.props.isSquare) {
208 214
             if (this.props.isSquareLeft)

+ 69
- 49
components/FetchedDataSectionList.js View File

@@ -25,7 +25,6 @@ type State = {
25 25
  * Used by inheriting from it and redefining getters.
26 26
  */
27 27
 export default class FetchedDataSectionList extends React.Component<Props, State> {
28
-
29 28
     webDataManager: WebDataManager;
30 29
 
31 30
     willFocusSubscription: function;
@@ -42,12 +41,29 @@ export default class FetchedDataSectionList extends React.Component<Props, State
42 41
         machinesWatched: [],
43 42
     };
44 43
 
44
+    onRefresh: Function;
45
+    onFetchSuccess: Function;
46
+    onFetchError: Function;
47
+    renderSectionHeaderEmpty: Function;
48
+    renderSectionHeaderNotEmpty: Function;
49
+    renderItemEmpty: Function;
50
+    renderItemNotEmpty: Function;
51
+
45 52
     constructor(fetchUrl: string, refreshTime: number) {
46 53
         super();
47 54
         this.webDataManager = new WebDataManager(fetchUrl);
48 55
         this.refreshTime = refreshTime;
56
+        // creating references to functions used in render()
57
+        this.onRefresh = this.onRefresh.bind(this);
58
+        this.onFetchSuccess = this.onFetchSuccess.bind(this);
59
+        this.onFetchError = this.onFetchError.bind(this);
60
+        this.renderSectionHeaderEmpty = this.renderSectionHeader.bind(this, true);
61
+        this.renderSectionHeaderNotEmpty = this.renderSectionHeader.bind(this, false);
62
+        this.renderItemEmpty = this.renderItem.bind(this, true);
63
+        this.renderItemNotEmpty = this.renderItem.bind(this, false);
49 64
     }
50 65
 
66
+
51 67
     /**
52 68
      * Get the translation for the header in the current language
53 69
      * @return {string}
@@ -74,26 +90,18 @@ export default class FetchedDataSectionList extends React.Component<Props, State
74 90
      */
75 91
     componentDidMount() {
76 92
         this.willFocusSubscription = this.props.navigation.addListener(
77
-            'willFocus',
78
-            () => {
79
-                this.onScreenFocus();
80
-            }
81
-        );
93
+            'willFocus', this.onScreenFocus.bind(this));
82 94
         this.willBlurSubscription = this.props.navigation.addListener(
83
-            'willBlur',
84
-            () => {
85
-                this.onScreenBlur();
86
-            }
87
-        );
95
+            'willBlur', this.onScreenBlur.bind(this));
88 96
     }
89 97
 
90 98
     /**
91 99
      * Refresh data when focusing the screen and setup a refresh interval if asked to
92 100
      */
93 101
     onScreenFocus() {
94
-        this._onRefresh();
102
+        this.onRefresh();
95 103
         if (this.refreshTime > 0)
96
-            this.refreshInterval = setInterval(() => this._onRefresh(), this.refreshTime)
104
+            this.refreshInterval = setInterval(this.onRefresh.bind(this), this.refreshTime)
97 105
     }
98 106
 
99 107
     /**
@@ -113,11 +121,29 @@ export default class FetchedDataSectionList extends React.Component<Props, State
113 121
             this.willFocusSubscription.remove();
114 122
     }
115 123
 
124
+    onFetchSuccess(fetchedData: Object) {
125
+        this.setState({
126
+            fetchedData: fetchedData,
127
+            refreshing: false,
128
+            firstLoading: false
129
+        });
130
+        this.lastRefresh = new Date();
131
+    }
132
+
133
+    onFetchError() {
134
+        this.setState({
135
+            fetchedData: {},
136
+            refreshing: false,
137
+            firstLoading: false
138
+        });
139
+        this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]);
140
+    }
141
+
116 142
     /**
117 143
      * Refresh data and show a toast if any error occurred
118 144
      * @private
119 145
      */
120
-    _onRefresh = () => {
146
+    onRefresh() {
121 147
         let canRefresh;
122 148
         if (this.lastRefresh !== undefined)
123 149
             canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
@@ -127,25 +153,10 @@ export default class FetchedDataSectionList extends React.Component<Props, State
127 153
         if (canRefresh) {
128 154
             this.setState({refreshing: true});
129 155
             this.webDataManager.readData()
130
-                .then((fetchedData) => {
131
-                    this.setState({
132
-                        fetchedData: fetchedData,
133
-                        refreshing: false,
134
-                        firstLoading: false
135
-                    });
136
-                    this.lastRefresh = new Date();
137
-                })
138
-                .catch(() => {
139
-                    this.setState({
140
-                        fetchedData: {},
141
-                        refreshing: false,
142
-                        firstLoading: false
143
-                    });
144
-                    this.webDataManager.showUpdateToast(this.getUpdateToastTranslations()[0], this.getUpdateToastTranslations()[1]);
145
-                });
156
+                .then(this.onFetchSuccess)
157
+                .catch(this.onFetchError);
146 158
         }
147
-
148
-    };
159
+    }
149 160
 
150 161
     /**
151 162
      * Get the render item to be used for display in the list.
@@ -153,10 +164,9 @@ export default class FetchedDataSectionList extends React.Component<Props, State
153 164
      *
154 165
      * @param item
155 166
      * @param section
156
-     * @param data
157 167
      * @return {*}
158 168
      */
159
-    getRenderItem(item: Object, section: Object, data: Object) {
169
+    getRenderItem(item: Object, section: Object) {
160 170
         return <View/>;
161 171
     }
162 172
 
@@ -222,6 +232,11 @@ export default class FetchedDataSectionList extends React.Component<Props, State
222 232
         return [];
223 233
     }
224 234
 
235
+
236
+    datasetKeyExtractor(item: Object) {
237
+        return item.text
238
+    }
239
+
225 240
     /**
226 241
      * Create the dataset when no fetched data is available.
227 242
      * No need to be overridden, has good defaults.
@@ -243,7 +258,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
243 258
                             'access-point-network-off'
244 259
                     }
245 260
                 ],
246
-                keyExtractor: (item: Object) => item.text,
261
+                keyExtractor: this.datasetKeyExtractor,
247 262
             }
248 263
         ];
249 264
     }
@@ -275,6 +290,19 @@ export default class FetchedDataSectionList extends React.Component<Props, State
275 290
         return true;
276 291
     }
277 292
 
293
+
294
+    renderSectionHeader(isEmpty: boolean, {section: {title}} : Object) {
295
+        return isEmpty ?
296
+            <View/> :
297
+            this.getRenderSectionHeader(title)
298
+    }
299
+
300
+    renderItem(isEmpty: boolean, {item, section}: Object) {
301
+        return isEmpty ?
302
+            this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) :
303
+            this.getRenderItem(item, section)
304
+    }
305
+
278 306
     /**
279 307
      * Get the section list render using the generated dataset
280 308
      *
@@ -292,19 +320,11 @@ export default class FetchedDataSectionList extends React.Component<Props, State
292 320
                 refreshControl={
293 321
                     <RefreshControl
294 322
                         refreshing={this.state.refreshing}
295
-                        onRefresh={this._onRefresh}
323
+                        onRefresh={this.onRefresh}
296 324
                     />
297 325
                 }
298
-                renderSectionHeader={({section: {title}}) =>
299
-                    isEmpty ?
300
-                        <View/> :
301
-                        this.getRenderSectionHeader(title)
302
-                }
303
-                renderItem={({item, section}) =>
304
-                    isEmpty ?
305
-                        this.getEmptyRenderItem(item.text, item.isSpinner, item.icon) :
306
-                        this.getRenderItem(item, section, dataset)
307
-                }
326
+                renderSectionHeader={isEmpty ? this.renderSectionHeaderEmpty : this.renderSectionHeaderNotEmpty}
327
+                renderItem={isEmpty ? this.renderItemEmpty : this.renderItemNotEmpty}
308 328
                 style={{minHeight: 300, width: '100%'}}
309 329
                 contentContainerStyle={
310 330
                     isEmpty ?
@@ -351,11 +371,12 @@ export default class FetchedDataSectionList extends React.Component<Props, State
351 371
     }
352 372
 
353 373
     render() {
354
-        const nav = this.props.navigation;
374
+        // console.log("rendering FetchedDataSectionList");
355 375
         const dataset = this.createDataset(this.state.fetchedData);
356 376
         return (
357 377
             <BaseContainer
358
-                navigation={nav} headerTitle={this.getHeaderTranslation()}
378
+                navigation={this.props.navigation}
379
+                headerTitle={this.getHeaderTranslation()}
359 380
                 headerRightButton={this.getRightButton()}
360 381
                 hasTabs={this.hasTabs()}
361 382
                 hasBackButton={this.hasBackButton()}
@@ -375,5 +396,4 @@ export default class FetchedDataSectionList extends React.Component<Props, State
375 396
             </BaseContainer>
376 397
         );
377 398
     }
378
-
379 399
 }

+ 25
- 18
components/Sidebar.js View File

@@ -30,6 +30,8 @@ export default class SideBar extends React.Component<Props, State> {
30 30
         active: 'Home',
31 31
     };
32 32
 
33
+    getRenderItem: Function;
34
+
33 35
     /**
34 36
      * Generate the datasets
35 37
      *
@@ -38,7 +40,6 @@ export default class SideBar extends React.Component<Props, State> {
38 40
     constructor(props: Props) {
39 41
         super(props);
40 42
         // Dataset used to render the drawer
41
-        // If the link field is defined, clicking on the item will open the link
42 43
         this.dataSet = [
43 44
             {
44 45
                 name: i18n.t('sidenav.divider1'),
@@ -103,21 +104,34 @@ export default class SideBar extends React.Component<Props, State> {
103 104
                 icon: "information",
104 105
             },
105 106
         ];
107
+        this.getRenderItem = this.getRenderItem.bind(this);
108
+    }
109
+
110
+    shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
111
+        return nextState.active !== this.state.active;
106 112
     }
107 113
 
108
-    getRenderItem(item: Object) {
114
+
115
+    onListItemPress(route: string) {
116
+        this.props.navigation.navigate(route);
117
+    }
118
+
119
+
120
+    listKeyExtractor(item: Object) {
121
+        return item.route;
122
+    }
123
+
124
+
125
+    getRenderItem({item}: Object) {
126
+        const onListItemPress = this.onListItemPress.bind(this, item.route);
127
+
109 128
         if (item.icon !== undefined) {
110 129
             return (
111 130
                 <ListItem
112 131
                     button
113 132
                     noBorder
114 133
                     selected={this.state.active === item.route}
115
-                    onPress={() => {
116
-                        if (item.link !== undefined)
117
-                            Linking.openURL(item.link).catch((err) => console.error('Error opening link', err));
118
-                        else
119
-                            this.navigateToScreen(item.route);
120
-                    }}
134
+                    onPress={onListItemPress}
121 135
                 >
122 136
                     <Left>
123 137
                         <CustomMaterialIcon
@@ -155,15 +169,8 @@ export default class SideBar extends React.Component<Props, State> {
155 169
 
156 170
     }
157 171
 
158
-    /**
159
-     * Navigate to the selected route
160
-     * @param route {string} The route name to navigate to
161
-     */
162
-    navigateToScreen(route: string) {
163
-        this.props.navigation.navigate(route);
164
-    };
165
-
166 172
     render() {
173
+        // console.log("rendering SideBar");
167 174
         return (
168 175
             <Container style={{
169 176
                 backgroundColor: ThemeManager.getCurrentThemeVariables().sideMenuBgColor,
@@ -172,8 +179,8 @@ export default class SideBar extends React.Component<Props, State> {
172 179
                 <FlatList
173 180
                     data={this.dataSet}
174 181
                     extraData={this.state}
175
-                    keyExtractor={(item) => item.route}
176
-                    renderItem={({item}) => this.getRenderItem(item)}
182
+                    keyExtractor={this.listKeyExtractor}
183
+                    renderItem={this.getRenderItem}
177 184
                 />
178 185
             </Container>
179 186
         );

+ 52
- 24
components/WebViewScreen.js View File

@@ -35,6 +35,21 @@ export default class WebViewScreen extends React.Component<Props> {
35 35
     };
36 36
     webviewArray: Array<WebView> = [];
37 37
 
38
+    onRefreshClicked: Function;
39
+    onWebviewRef: Function;
40
+    onGoBackWebview: Function;
41
+    onGoForwardWebview: Function;
42
+    onOpenWebLink: Function;
43
+
44
+    constructor() {
45
+        super();
46
+        this.onRefreshClicked = this.onRefreshClicked.bind(this);
47
+        this.onWebviewRef = this.onWebviewRef.bind(this);
48
+        this.onGoBackWebview = this.onGoBackWebview.bind(this);
49
+        this.onGoForwardWebview = this.onGoForwardWebview.bind(this);
50
+        this.onOpenWebLink = this.onOpenWebLink.bind(this);
51
+    }
52
+
38 53
     openWebLink(url: string) {
39 54
         Linking.openURL(url).catch((err) => console.error('Error opening link', err));
40 55
     }
@@ -43,7 +58,7 @@ export default class WebViewScreen extends React.Component<Props> {
43 58
         return (
44 59
             <Touchable
45 60
                 style={{padding: 6}}
46
-                onPress={() => clickAction()}>
61
+                onPress={clickAction}>
47 62
                 <CustomMaterialIcon
48 63
                     color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
49 64
                     icon={icon}/>
@@ -54,36 +69,62 @@ export default class WebViewScreen extends React.Component<Props> {
54 69
     getRefreshButton() {
55 70
         return (
56 71
             <View style={{flexDirection: 'row'}}>
57
-                {this.getHeaderButton(() => this.refreshWebview(), 'refresh')}
72
+                {this.getHeaderButton(this.onRefreshClicked, 'refresh')}
58 73
             </View>
59 74
         );
60 75
     };
61 76
 
62
-    refreshWebview() {
77
+    onRefreshClicked() {
63 78
         for (let view of this.webviewArray) {
64 79
             if (view !== null)
65 80
                 view.reload();
66 81
         }
67 82
     }
68 83
 
69
-    goBackWebview() {
84
+    onGoBackWebview() {
70 85
         for (let view of this.webviewArray) {
71 86
             if (view !== null)
72 87
                 view.goBack();
73 88
         }
74 89
     }
75 90
 
76
-    goForwardWebview() {
91
+    onGoForwardWebview() {
77 92
         for (let view of this.webviewArray) {
78 93
             if (view !== null)
79 94
                 view.goForward();
80 95
         }
81 96
     }
82 97
 
98
+    onOpenWebLink() {
99
+        this.openWebLink(this.props.data[0]['url'])
100
+    }
101
+
102
+    onWebviewRef(ref: WebView) {
103
+        this.webviewArray.push(ref)
104
+    }
105
+
106
+    getRenderLoading() {
107
+        return (
108
+            <View style={{
109
+                backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
110
+                position: 'absolute',
111
+                top: 0,
112
+                right: 0,
113
+                width: '100%',
114
+                height: '100%',
115
+                flex: 1,
116
+                alignItems: 'center',
117
+                justifyContent: 'center'
118
+            }}>
119
+                <Spinner/>
120
+            </View>
121
+        );
122
+    }
123
+
83 124
     getWebview(obj: Object) {
84 125
         return (
85 126
             <WebView
86
-                ref={ref => (this.webviewArray.push(ref))}
127
+                ref={this.onWebviewRef}
87 128
                 source={{uri: obj['url']}}
88 129
                 style={{
89 130
                     width: '100%',
@@ -92,21 +133,7 @@ export default class WebViewScreen extends React.Component<Props> {
92 133
                 startInLoadingState={true}
93 134
                 injectedJavaScript={obj['customJS']}
94 135
                 javaScriptEnabled={true}
95
-                renderLoading={() =>
96
-                    <View style={{
97
-                        backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor,
98
-                        position: 'absolute',
99
-                        top: 0,
100
-                        right: 0,
101
-                        width: '100%',
102
-                        height: '100%',
103
-                        flex: 1,
104
-                        alignItems: 'center',
105
-                        justifyContent: 'center'
106
-                    }}>
107
-                        <Spinner/>
108
-                    </View>
109
-                }
136
+                renderLoading={this.getRenderLoading}
110 137
             />
111 138
         );
112 139
     }
@@ -133,6 +160,7 @@ export default class WebViewScreen extends React.Component<Props> {
133 160
     }
134 161
 
135 162
     render() {
163
+        // console.log("rendering WebViewScreen");
136 164
         const nav = this.props.navigation;
137 165
         this.webviewArray = [];
138 166
         return (
@@ -166,7 +194,7 @@ export default class WebViewScreen extends React.Component<Props> {
166 194
                         <Left style={{
167 195
                             paddingLeft: 6,
168 196
                         }}>
169
-                            {this.getHeaderButton(() => this.openWebLink(this.props.data[0]['url']), 'open-in-new')}
197
+                            {this.getHeaderButton(this.onOpenWebLink, 'open-in-new')}
170 198
                         </Left>
171 199
                         <Body/>
172 200
                         <Right style={{
@@ -179,8 +207,8 @@ export default class WebViewScreen extends React.Component<Props> {
179 207
                                 marginRight: 0,
180 208
                                 marginLeft: 'auto'
181 209
                             }}>
182
-                                {this.getHeaderButton(() => this.goBackWebview(), 'chevron-left')}
183
-                                {this.getHeaderButton(() => this.goForwardWebview(), 'chevron-right')}
210
+                                {this.getHeaderButton(this.onGoBackWebview, 'chevron-left')}
211
+                                {this.getHeaderButton(this.onGoForwardWebview, 'chevron-right')}
184 212
                             </View>
185 213
                         </Right>
186 214
                     </Footer> : <View/>}

+ 30
- 38
screens/About/AboutScreen.js View File

@@ -15,7 +15,7 @@ import ThemeManager from "../../utils/ThemeManager";
15 15
 const links = {
16 16
     appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
17 17
     playstore: 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application',
18
-    git: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
18
+    git: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
19 19
     bugsMail: 'mailto:vergnet@etud.insa-toulouse.fr?' +
20 20
         'subject=' +
21 21
         '[BUG] Application Amicale INSA Toulouse' +
@@ -25,9 +25,9 @@ const links = {
25 25
         'Nature du problème :\n\n\n' +
26 26
         'Étapes pour reproduire ce pb :\n\n\n\n' +
27 27
         'Stp corrige le pb, bien cordialement.',
28
-    bugsGit: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/issues',
29
-    changelog: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
30
-    license: 'https://git.srv-falcon.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
28
+    bugsGit: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/issues',
29
+    changelog: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
30
+    license: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
31 31
     authorMail: "mailto:vergnet@etud.insa-toulouse.fr?" +
32 32
         "subject=" +
33 33
         "Application Amicale INSA Toulouse" +
@@ -187,9 +187,14 @@ export default class AboutScreen extends React.Component<Props, State> {
187 187
         },
188 188
     ];
189 189
 
190
+    getCardItem: Function;
191
+    getMainCard: Function;
192
+
190 193
     constructor(props: any) {
191 194
         super(props);
192 195
         this.modalRef = React.createRef();
196
+        this.getCardItem = this.getCardItem.bind(this);
197
+        this.getMainCard = this.getMainCard.bind(this);
193 198
     }
194 199
 
195 200
     getAppCard() {
@@ -197,7 +202,7 @@ export default class AboutScreen extends React.Component<Props, State> {
197 202
             <Card>
198 203
                 <CardItem>
199 204
                     <Left>
200
-                        <Thumbnail square source={require('../../assets/icon.png')}/>
205
+                        <Thumbnail square source={require('../../assets/android.icon.png')}/>
201 206
                         <Body>
202 207
                             <H1>{appJson.expo.name}</H1>
203 208
                             <Text note>
@@ -210,10 +215,8 @@ export default class AboutScreen extends React.Component<Props, State> {
210 215
                     data={this.appData}
211 216
                     extraData={this.state}
212 217
                     keyExtractor={(item) => item.icon}
213
-                    listKey={(item) => "app"}
214
-                    renderItem={({item}) =>
215
-                        this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
216
-                    }
218
+                    listKey={"app"}
219
+                    renderItem={this.getCardItem}
217 220
                 />
218 221
             </Card>
219 222
         );
@@ -241,10 +244,8 @@ export default class AboutScreen extends React.Component<Props, State> {
241 244
                     data={this.authorData}
242 245
                     extraData={this.state}
243 246
                     keyExtractor={(item) => item.icon}
244
-                    listKey={(item) => "team1"}
245
-                    renderItem={({item}) =>
246
-                        this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
247
-                    }
247
+                    listKey={"team1"}
248
+                    renderItem={this.getCardItem}
248 249
                 />
249 250
                 <CardItem header>
250 251
                     <Text>{i18n.t('aboutScreen.additionalDev')}</Text>
@@ -253,10 +254,8 @@ export default class AboutScreen extends React.Component<Props, State> {
253 254
                     data={this.additionalDevData}
254 255
                     extraData={this.state}
255 256
                     keyExtractor={(item) => item.icon}
256
-                    listKey={(item) => "team2"}
257
-                    renderItem={({item}) =>
258
-                        this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
259
-                    }
257
+                    listKey={"team2"}
258
+                    renderItem={this.getCardItem}
260 259
                 />
261 260
             </Card>
262 261
         );
@@ -272,10 +271,8 @@ export default class AboutScreen extends React.Component<Props, State> {
272 271
                     data={this.technoData}
273 272
                     extraData={this.state}
274 273
                     keyExtractor={(item) => item.icon}
275
-                    listKey={(item) => "techno"}
276
-                    renderItem={({item}) =>
277
-                        this.getCardItem(item.onPressCallback, item.icon, item.text, item.showChevron, item.showOnlyDebug)
278
-                    }
274
+                    listKey={"techno"}
275
+                    renderItem={this.getCardItem}
279 276
                 />
280 277
             </Card>
281 278
         );
@@ -284,24 +281,19 @@ export default class AboutScreen extends React.Component<Props, State> {
284 281
     /**
285 282
      * Get a clickable card item to be rendered inside a card.
286 283
      *
287
-     * @param onPressCallback The callback to use when the item is clicked
288
-     * @param icon The icon name to use from MaterialCommunityIcons
289
-     * @param text The text to show
290
-     * @param showChevron Whether to show a chevron indicating this button will change screen
291
-     * @param showOnlyInDebug Should we show te current item only in debug mode?
292 284
      * @returns {React.Node}
293 285
      */
294
-    getCardItem(onPressCallback: Function, icon: string, text: string, showChevron: boolean, showOnlyInDebug: boolean) {
295
-        let shouldShow = !showOnlyInDebug || (showOnlyInDebug && this.state.isDebugUnlocked);
286
+    getCardItem({item}: Object) {
287
+        let shouldShow = !item.showOnlyInDebug || (item.showOnlyInDebug && this.state.isDebugUnlocked);
296 288
         if (shouldShow) {
297 289
             return (
298 290
                 <CardItem button
299
-                          onPress={onPressCallback}>
291
+                          onPress={item.onPressCallback}>
300 292
                     <Left>
301
-                        <CustomMaterialIcon icon={icon}/>
302
-                        <Text>{text}</Text>
293
+                        <CustomMaterialIcon icon={item.icon}/>
294
+                        <Text>{item.text}</Text>
303 295
                     </Left>
304
-                    {showChevron ?
296
+                    {item.showChevron ?
305 297
                         <Right>
306 298
                             <CustomMaterialIcon icon="chevron-right"
307 299
                                                 fontSize={20}/>
@@ -331,6 +323,8 @@ export default class AboutScreen extends React.Component<Props, State> {
331 323
     }
332 324
 
333 325
     getBugReportModal() {
326
+        const onPressMail = openWebLink.bind(this, links.bugsMail);
327
+        const onPressGit = openWebLink.bind(this, links.bugsGit);
334 328
         return (
335 329
             <Modalize ref={this.modalRef}
336 330
                       adjustToContentHeight
@@ -349,7 +343,7 @@ export default class AboutScreen extends React.Component<Props, State> {
349 343
                             marginLeft: 'auto',
350 344
                             marginRight: 'auto',
351 345
                         }}
352
-                        onPress={() => openWebLink(links.bugsMail)}>
346
+                        onPress={onPressMail}>
353 347
                         <CustomMaterialIcon
354 348
                             icon={'email'}
355 349
                             color={'#fff'}/>
@@ -361,7 +355,7 @@ export default class AboutScreen extends React.Component<Props, State> {
361 355
                             marginLeft: 'auto',
362 356
                             marginRight: 'auto',
363 357
                         }}
364
-                        onPress={() => openWebLink(links.bugsGit)}>
358
+                        onPress={onPressGit}>
365 359
                         <CustomMaterialIcon
366 360
                             icon={'git'}
367 361
                             color={'#fff'}/>
@@ -378,7 +372,7 @@ export default class AboutScreen extends React.Component<Props, State> {
378 372
         }
379 373
     }
380 374
 
381
-    getMainCard(item: Object) {
375
+    getMainCard({item}: Object) {
382 376
         switch (item.id) {
383 377
             case 'app':
384 378
                 return this.getAppCard();
@@ -401,9 +395,7 @@ export default class AboutScreen extends React.Component<Props, State> {
401 395
                     data={this.dataOrder}
402 396
                     extraData={this.state}
403 397
                     keyExtractor={(item) => item.id}
404
-                    renderItem={({item}) =>
405
-                        this.getMainCard(item)
406
-                    }
398
+                    renderItem={this.getMainCard}
407 399
                 />
408 400
             </Container>
409 401
         );

+ 43
- 19
screens/HomeScreen.js View File

@@ -14,7 +14,7 @@ import DashboardItem from "../components/DashboardItem";
14 14
 
15 15
 const ICON_AMICALE = require('../assets/amicale.png');
16 16
 const NAME_AMICALE = 'Amicale INSA Toulouse';
17
-const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/dashboard/dashboard_data.json";
17
+const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/dashboard/dashboard_data.json";
18 18
 
19 19
 const SECTIONS_ID = [
20 20
     'dashboard',
@@ -38,8 +38,33 @@ function openWebLink(link) {
38 38
  */
39 39
 export default class HomeScreen extends FetchedDataSectionList {
40 40
 
41
+    onProxiwashClick: Function;
42
+    onTutorInsaClick: Function;
43
+    onMenuClick: Function;
44
+    onProximoClick: Function;
45
+
41 46
     constructor() {
42 47
         super(DATA_URL, REFRESH_TIME);
48
+        this.onProxiwashClick = this.onProxiwashClick.bind(this);
49
+        this.onTutorInsaClick = this.onTutorInsaClick.bind(this);
50
+        this.onMenuClick = this.onMenuClick.bind(this);
51
+        this.onProximoClick = this.onProximoClick.bind(this);
52
+    }
53
+
54
+    onProxiwashClick() {
55
+        this.props.navigation.navigate('Proxiwash');
56
+    }
57
+
58
+    onTutorInsaClick() {
59
+        this.props.navigation.navigate('TutorInsaScreen');
60
+    }
61
+
62
+    onProximoClick() {
63
+        this.props.navigation.navigate('Proximo');
64
+    }
65
+
66
+    onMenuClick() {
67
+        this.props.navigation.navigate('SelfMenuScreen');
43 68
     }
44 69
 
45 70
     /**
@@ -289,6 +314,14 @@ export default class HomeScreen extends FetchedDataSectionList {
289 314
     }
290 315
 
291 316
 
317
+    clickAction(isAvailable: boolean, displayEvent: Object) {
318
+        if (isAvailable)
319
+            this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
320
+        else
321
+            this.props.navigation.navigate('PlanningScreen');
322
+    };
323
+
324
+
292 325
     getDashboardEventItem(content: Array<Object>) {
293 326
         let icon = 'calendar-range';
294 327
         let color = ThemeManager.getCurrentThemeVariables().planningColor;
@@ -310,12 +343,6 @@ export default class HomeScreen extends FetchedDataSectionList {
310 343
                 </Text>;
311 344
         } else
312 345
             subtitle = i18n.t('homeScreen.dashboard.todayEventsSubtitleNA');
313
-        let clickAction = () => {
314
-            if (isAvailable)
315
-                this.props.navigation.navigate('PlanningDisplayScreen', {data: displayEvent});
316
-            else
317
-                this.props.navigation.navigate('PlanningScreen');
318
-        };
319 346
 
320 347
         let displayEvent = this.getDisplayEvent(futureEvents);
321 348
 
@@ -324,7 +351,7 @@ export default class HomeScreen extends FetchedDataSectionList {
324 351
                 subtitle={subtitle}
325 352
                 color={color}
326 353
                 icon={icon}
327
-                clickAction={() => clickAction()}
354
+                clickAction={this.clickAction.bind(this, isAvailable, displayEvent)}
328 355
                 title={title}
329 356
                 isAvailable={isAvailable}
330 357
                 displayEvent={displayEvent}
@@ -355,7 +382,6 @@ export default class HomeScreen extends FetchedDataSectionList {
355 382
                 </Text>;
356 383
         } else
357 384
             proximoSubtitle = i18n.t('homeScreen.dashboard.proximoSubtitleNA');
358
-        let proximoClickAction = () => this.props.navigation.navigate('Proximo');
359 385
 
360 386
 
361 387
         let menuIcon = 'silverware-fork-knife';
@@ -367,7 +393,6 @@ export default class HomeScreen extends FetchedDataSectionList {
367 393
             menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitle');
368 394
         } else
369 395
             menuSubtitle = i18n.t('homeScreen.dashboard.menuSubtitleNA');
370
-        let menuClickAction = () => this.props.navigation.navigate('SelfMenuScreen');
371 396
         return (
372 397
             <View style={{
373 398
                 flexDirection: 'row',
@@ -379,7 +404,7 @@ export default class HomeScreen extends FetchedDataSectionList {
379 404
                     subtitle={menuSubtitle}
380 405
                     color={menuColor}
381 406
                     icon={menuIcon}
382
-                    clickAction={() => menuClickAction()}
407
+                    clickAction={this.onMenuClick}
383 408
                     title={menuTitle}
384 409
                     isAvailable={isMenuAvailable}
385 410
                     isSquareLeft={true}/>
@@ -388,13 +413,14 @@ export default class HomeScreen extends FetchedDataSectionList {
388 413
                     subtitle={proximoSubtitle}
389 414
                     color={proximoColor}
390 415
                     icon={proximoIcon}
391
-                    clickAction={() => proximoClickAction()}
416
+                    clickAction={this.onProximoClick}
392 417
                     title={proximoTitle}
393 418
                     isAvailable={isProximoAvailable}/>
394 419
             </View>
395 420
         );
396 421
     }
397 422
 
423
+
398 424
     getDashboardMiddleItem(content: Array<Object>) {
399 425
         let proxiwashData = content[0]['data'];
400 426
         let tutorinsaData = content[1]['data'];
@@ -449,7 +475,6 @@ export default class HomeScreen extends FetchedDataSectionList {
449 475
                 </Text>;
450 476
         } else
451 477
             proxiwashSubtitle = i18n.t('homeScreen.dashboard.proxiwashSubtitleNA');
452
-        let proxiwashClickAction = () => this.props.navigation.navigate('Proxiwash');
453 478
 
454 479
         let tutorinsaIcon = 'school';
455 480
         let tutorinsaColor = ThemeManager.getCurrentThemeVariables().tutorinsaColor;
@@ -470,7 +495,6 @@ export default class HomeScreen extends FetchedDataSectionList {
470 495
                 </Text>;
471 496
         } else
472 497
             tutorinsaSubtitle = i18n.t('homeScreen.dashboard.tutorinsaSubtitleNA');
473
-        let tutorinsaClickAction = () => this.props.navigation.navigate('TutorInsaScreen');
474 498
 
475 499
         return (
476 500
             <View style={{
@@ -483,7 +507,7 @@ export default class HomeScreen extends FetchedDataSectionList {
483 507
                     subtitle={proxiwashSubtitle}
484 508
                     color={proxiwashColor}
485 509
                     icon={proxiwashIcon}
486
-                    clickAction={() => proxiwashClickAction()}
510
+                    clickAction={this.onProxiwashClick}
487 511
                     title={proxiwashTitle}
488 512
                     isAvailable={proxiwashIsAvailable}
489 513
                     isSquareLeft={true}/>
@@ -492,7 +516,7 @@ export default class HomeScreen extends FetchedDataSectionList {
492 516
                     subtitle={tutorinsaSubtitle}
493 517
                     color={tutorinsaColor}
494 518
                     icon={tutorinsaIcon}
495
-                    clickAction={() => tutorinsaClickAction()}
519
+                    clickAction={this.onTutorInsaClick}
496 520
                     title={tutorinsaTitle}
497 521
                     isAvailable={tutorinsaIsAvailable}/>
498 522
             </View>
@@ -500,7 +524,7 @@ export default class HomeScreen extends FetchedDataSectionList {
500 524
     }
501 525
 
502 526
 
503
-    getRenderItem(item: Object, section: Object, data: Object) {
527
+    getRenderItem(item: Object, section: Object) {
504 528
         return (
505 529
             section['id'] === SECTIONS_ID[0] ? this.getDashboardItem(item) :
506 530
                 <Card style={{
@@ -525,7 +549,7 @@ export default class HomeScreen extends FetchedDataSectionList {
525 549
                     }}>
526 550
                         <Body>
527 551
                             {item.full_picture !== '' && item.full_picture !== undefined ?
528
-                                <TouchableOpacity onPress={() => openWebLink(item.full_picture)}
552
+                                <TouchableOpacity onPress={openWebLink.bind(null, item.full_picture)}
529 553
                                                   style={{width: '100%', height: 250, marginBottom: 5}}>
530 554
                                     <Image source={{uri: item.full_picture}}
531 555
                                            style={{flex: 1, resizeMode: "contain"}}
@@ -547,7 +571,7 @@ export default class HomeScreen extends FetchedDataSectionList {
547 571
                     }}>
548 572
                         <Left>
549 573
                             <Button transparent
550
-                                    onPress={() => openWebLink(item.permalink_url)}>
574
+                                    onPress={openWebLink.bind(null, item.permalink_url)}>
551 575
                                 <CustomMaterialIcon
552 576
                                     icon="facebook"
553 577
                                     color="#57aeff"

+ 3
- 4
screens/PlanningDisplayScreen.js View File

@@ -8,13 +8,12 @@ import ThemeManager from "../utils/ThemeManager";
8 8
 import HTML from "react-native-render-html";
9 9
 import {Linking} from "expo";
10 10
 import PlanningEventManager from '../utils/PlanningEventManager';
11
-import i18n from 'i18n-js';
12 11
 
13 12
 type Props = {
14 13
     navigation: Object,
15 14
 };
16 15
 
17
-function openWebLink(link) {
16
+function openWebLink(event, link) {
18 17
     Linking.openURL(link).catch((err) => console.error('Error opening link', err));
19 18
 }
20 19
 
@@ -22,8 +21,8 @@ function openWebLink(link) {
22 21
  * Class defining an about screen. This screen shows the user information about the app and it's author.
23 22
  */
24 23
 export default class PlanningDisplayScreen extends React.Component<Props> {
25
-
26 24
     render() {
25
+        // console.log("rendering planningDisplayScreen");
27 26
         const nav = this.props.navigation;
28 27
         const displayData = nav.getParam('data', []);
29 28
         return (
@@ -60,7 +59,7 @@ export default class PlanningDisplayScreen extends React.Component<Props> {
60 59
                                   },
61 60
                                   div: {color: ThemeManager.getCurrentThemeVariables().textColor}
62 61
                               }}
63
-                              onLinkPress={(event, link) => openWebLink(link)}/>
62
+                              onLinkPress={openWebLink}/>
64 63
                         : <View/>}
65 64
                 </Content>
66 65
             </Container>

+ 49
- 30
screens/PlanningScreen.js View File

@@ -5,7 +5,6 @@ import {BackHandler, Image} from 'react-native';
5 5
 import {H3, Text, View} from 'native-base';
6 6
 import i18n from "i18n-js";
7 7
 import ThemeManager from "../utils/ThemeManager";
8
-import {Linking} from "expo";
9 8
 import BaseContainer from "../components/BaseContainer";
10 9
 import {Agenda, LocaleConfig} from 'react-native-calendars';
11 10
 import Touchable from 'react-native-platform-touchable';
@@ -36,14 +35,6 @@ const FETCH_URL = "https://amicale-insat.fr/event/json/list";
36 35
 const AGENDA_MONTH_SPAN = 6;
37 36
 
38 37
 /**
39
- * Opens a link in the device's browser
40
- * @param link The link to open
41
- */
42
-function openWebLink(link) {
43
-    Linking.openURL(link).catch((err) => console.error('Error opening link', err));
44
-}
45
-
46
-/**
47 38
  * Class defining the app's planning screen
48 39
  */
49 40
 export default class PlanningScreen extends React.Component<Props, State> {
@@ -56,12 +47,21 @@ export default class PlanningScreen extends React.Component<Props, State> {
56 47
 
57 48
     didFocusSubscription: Function;
58 49
     willBlurSubscription: Function;
50
+
59 51
     state = {
60 52
         refreshing: false,
61 53
         agendaItems: {},
62 54
         calendarShowing: false,
63 55
     };
64 56
 
57
+    onRefresh: Function;
58
+    onCalendarToggled: Function;
59
+    getRenderItem: Function;
60
+    getRenderEmptyDate: Function;
61
+    onAgendaRef: Function;
62
+    onCalendarToggled: Function;
63
+    onBackButtonPressAndroid: Function;
64
+
65 65
     constructor(props: any) {
66 66
         super(props);
67 67
         this.webDataManager = new WebDataManager(FETCH_URL);
@@ -76,10 +76,25 @@ export default class PlanningScreen extends React.Component<Props, State> {
76 76
         if (i18n.currentLocale().startsWith("fr")) {
77 77
             LocaleConfig.defaultLocale = 'fr';
78 78
         }
79
+
80
+        // Create references for functions required in the render function
81
+        this.onRefresh = this.onRefresh.bind(this);
82
+        this.onCalendarToggled = this.onCalendarToggled.bind(this);
83
+        this.getRenderItem = this.getRenderItem.bind(this);
84
+        this.getRenderEmptyDate = this.getRenderEmptyDate.bind(this);
85
+        this.onAgendaRef = this.onAgendaRef.bind(this);
86
+        this.onCalendarToggled = this.onCalendarToggled.bind(this);
87
+        this.onBackButtonPressAndroid = this.onBackButtonPressAndroid.bind(this);
88
+    }
89
+
90
+    shouldComponentUpdate(nextProps: Props, nextState: State): boolean {
91
+        return nextState.refreshing === false && this.state.refreshing === true ||
92
+            nextState.agendaItems !== this.state.agendaItems ||
93
+            nextState.calendarShowing !== this.state.calendarShowing;
79 94
     }
80 95
 
81 96
     componentDidMount() {
82
-        this._onRefresh();
97
+        this.onRefresh();
83 98
         this.willBlurSubscription = this.props.navigation.addListener(
84 99
             'willBlur',
85 100
             () =>
@@ -90,7 +105,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
90 105
         );
91 106
     }
92 107
 
93
-    onBackButtonPressAndroid = () => {
108
+    onBackButtonPressAndroid() {
94 109
         if (this.state.calendarShowing) {
95 110
             this.agendaRef.chooseDay(this.agendaRef.state.selectedDay);
96 111
             return true;
@@ -126,10 +141,6 @@ export default class PlanningScreen extends React.Component<Props, State> {
126 141
     }
127 142
 
128 143
     getRenderItem(item: Object) {
129
-        let navData = {
130
-            data: item
131
-        };
132
-        const nav = this.props.navigation;
133 144
         return (
134 145
             <Touchable
135 146
                 style={{
@@ -138,7 +149,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
138 149
                     marginRight: 10,
139 150
                     marginTop: 17,
140 151
                 }}
141
-                onPress={() => nav.navigate('PlanningDisplayScreen', navData)}>
152
+                onPress={() => this.props.navigation.navigate('PlanningDisplayScreen', {data: item})}>
142 153
                 <View style={{
143 154
                     padding: 10,
144 155
                     flex: 1,
@@ -200,7 +211,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
200 211
      * Refresh data and show a toast if any error occurred
201 212
      * @private
202 213
      */
203
-    _onRefresh = () => {
214
+    onRefresh = () => {
204 215
         let canRefresh;
205 216
         if (this.lastRefresh !== undefined)
206 217
             canRefresh = (new Date().getTime() - this.lastRefresh.getTime()) / 1000 > this.minTimeBetweenRefresh;
@@ -221,7 +232,7 @@ export default class PlanningScreen extends React.Component<Props, State> {
221 232
                     this.setState({
222 233
                         refreshing: false,
223 234
                     });
224
-                    console.log(err);
235
+                    // console.log(err);
225 236
                 });
226 237
         }
227 238
     };
@@ -252,38 +263,46 @@ export default class PlanningScreen extends React.Component<Props, State> {
252 263
         }
253 264
     }
254 265
 
266
+    onAgendaRef(ref: Agenda) {
267
+        this.agendaRef = ref;
268
+    }
269
+
270
+    onCalendarToggled(isCalendarOpened: boolean) {
271
+        this.setState({calendarShowing: isCalendarOpened});
272
+    }
273
+
274
+    currentDate = this.getCurrentDate();
275
+
255 276
     render() {
256
-        const nav = this.props.navigation;
277
+        // console.log("rendering PlanningScreen");
257 278
         return (
258
-            <BaseContainer navigation={nav} headerTitle={i18n.t('screens.planning')}>
279
+            <BaseContainer navigation={this.props.navigation} headerTitle={i18n.t('screens.planning')}>
259 280
                 <Agenda
260 281
                     // the list of items that have to be displayed in agenda. If you want to render item as empty date
261 282
                     // the value of date key kas to be an empty array []. If there exists no value for date key it is
262 283
                     // considered that the date in question is not yet loaded
263 284
                     items={this.state.agendaItems}
264 285
                     // initially selected day
265
-                    selected={this.getCurrentDate()}
286
+                    selected={this.currentDate}
266 287
                     // Minimum date that can be selected, dates before minDate will be grayed out. Default = undefined
267
-                    minDate={this.getCurrentDate()}
288
+                    minDate={this.currentDate}
268 289
                     // Max amount of months allowed to scroll to the past. Default = 50
269 290
                     pastScrollRange={1}
270 291
                     // Max amount of months allowed to scroll to the future. Default = 50
271 292
                     futureScrollRange={AGENDA_MONTH_SPAN}
272 293
                     // If provided, a standard RefreshControl will be added for "Pull to Refresh" functionality. Make sure to also set the refreshing prop correctly.
273
-                    onRefresh={() => this._onRefresh()}
294
+                    onRefresh={this.onRefresh}
274 295
                     // callback that fires when the calendar is opened or closed
275
-                    onCalendarToggled={(calendarOpened) => {
276
-                        this.setState({calendarShowing: calendarOpened})
277
-                    }}
296
+                    onCalendarToggled={this.onCalendarToggled}
278 297
                     // Set this true while waiting for new data from a refresh
279 298
                     refreshing={this.state.refreshing}
280
-                    renderItem={(item) => this.getRenderItem(item)}
281
-                    renderEmptyDate={() => this.getRenderEmptyDate()}
282
-                    rowHasChanged={() => this.rowHasChanged()}
299
+                    renderItem={this.getRenderItem}
300
+                    renderEmptyDate={this.getRenderEmptyDate}
301
+                    rowHasChanged={this.rowHasChanged}
283 302
                     // If firstDay=1 week starts from Monday. Note that dayNames and dayNamesShort should still start from Sunday.
284 303
                     firstDay={1}
285 304
                     // ref to this agenda in order to handle back button event
286
-                    ref={(ref) => this.agendaRef = ref}
305
+                    ref={this.onAgendaRef}
287 306
                     // agenda theme
288 307
                     theme={{
289 308
                         backgroundColor: ThemeManager.getCurrentThemeVariables().agendaBackgroundColor,

+ 1
- 1
screens/Proximo/ProximoAboutScreen.js View File

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {Image, Linking, View} from 'react-native';
4
+import {Image, View} from 'react-native';
5 5
 import {Card, CardItem, Container, Content, H2, Left, Text} from 'native-base';
6 6
 import CustomHeader from "../../components/CustomHeader";
7 7
 import i18n from "i18n-js";

+ 74
- 41
screens/Proximo/ProximoListScreen.js View File

@@ -70,12 +70,28 @@ export default class ProximoListScreen extends React.Component<Props, State> {
70 70
         sortNameIcon: '',
71 71
         modalCurrentDisplayItem: {},
72 72
     };
73
-    _menu: Menu;
73
+    sortMenuRef: Menu;
74
+
75
+    onMenuRef: Function;
76
+    onSearchStringChange: Function;
77
+    onSelectSortModeName: Function;
78
+    onSelectSortModePrice: Function;
79
+    onSortMenuPress: Function;
80
+    renderItem: Function;
81
+    onListItemPress: Function;
74 82
 
75 83
     constructor(props: any) {
76 84
         super(props);
77 85
         this.modalRef = React.createRef();
78 86
         this.originalData = this.navData['data'];
87
+
88
+        this.onMenuRef = this.onMenuRef.bind(this);
89
+        this.onSearchStringChange = this.onSearchStringChange.bind(this);
90
+        this.onSelectSortModeName = this.onSelectSortModeName.bind(this);
91
+        this.onSelectSortModePrice = this.onSelectSortModePrice.bind(this);
92
+        this.onSortMenuPress = this.onSortMenuPress.bind(this);
93
+        this.renderItem = this.renderItem.bind(this);
94
+        this.onListItemPress = this.onListItemPress.bind(this);
79 95
     }
80 96
 
81 97
     /**
@@ -83,8 +99,8 @@ export default class ProximoListScreen extends React.Component<Props, State> {
83 99
      *
84 100
      * @param ref The menu reference
85 101
      */
86
-    setMenuRef = (ref: Menu) => {
87
-        this._menu = ref;
102
+    onMenuRef(ref: Menu) {
103
+        this.sortMenuRef = ref;
88 104
     };
89 105
 
90 106
     /**
@@ -131,7 +147,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
131 147
                 break;
132 148
         }
133 149
         this.setupSortIcons(mode, isReverse);
134
-        this._menu.hide();
150
+        this.sortMenuRef.hide();
135 151
     }
136 152
 
137 153
     /**
@@ -214,7 +230,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
214 230
         return filteredData;
215 231
     }
216 232
 
217
-    search(str: string) {
233
+    onSearchStringChange(str: string) {
218 234
         this.setState({
219 235
             currentlyDisplayedData: this.filterData(str)
220 236
         })
@@ -251,7 +267,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
251 267
         );
252 268
     }
253 269
 
254
-    showItemDetails(item: Object) {
270
+    onListItemPress(item: Object) {
255 271
         this.setState({
256 272
             modalCurrentDisplayItem: item
257 273
         });
@@ -260,16 +276,27 @@ export default class ProximoListScreen extends React.Component<Props, State> {
260 276
         }
261 277
     }
262 278
 
279
+    onSelectSortModeName() {
280
+        this.sortModeSelected(sortMode.name);
281
+    }
282
+
283
+    onSelectSortModePrice() {
284
+        this.sortModeSelected(sortMode.price);
285
+    }
286
+
287
+    onSortMenuPress() {
288
+        this.sortMenuRef.show();
289
+    }
290
+
291
+
263 292
     getSortMenu() {
264 293
         return (
265 294
             <Menu
266
-                ref={this.setMenuRef}
295
+                ref={this.onMenuRef}
267 296
                 button={
268 297
                     <Touchable
269 298
                         style={{padding: 6}}
270
-                        onPress={() =>
271
-                            this._menu.show()
272
-                        }>
299
+                        onPress={this.onSortMenuPress}>
273 300
                         <CustomMaterialIcon
274 301
                             color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
275 302
                             icon={'sort'}/>
@@ -277,12 +304,12 @@ export default class ProximoListScreen extends React.Component<Props, State> {
277 304
                 }
278 305
             >
279 306
                 <MenuItem
280
-                    onPress={() => this.sortModeSelected(sortMode.name)}>
307
+                    onPress={this.onSelectSortModeName}>
281 308
                     {this.state.sortNameIcon}
282 309
                     {i18n.t('proximoScreen.sortName')}
283 310
                 </MenuItem>
284 311
                 <MenuItem
285
-                    onPress={() => this.sortModeSelected(sortMode.price)}>
312
+                    onPress={this.onSelectSortModePrice}>
286 313
                     {this.state.sortPriceIcon}
287 314
                     {i18n.t('proximoScreen.sortPrice')}
288 315
                 </MenuItem>
@@ -290,7 +317,39 @@ export default class ProximoListScreen extends React.Component<Props, State> {
290 317
         );
291 318
     }
292 319
 
320
+    renderItem({item}: Object) {
321
+        return (<ListItem
322
+            thumbnail
323
+            onPress={this.onListItemPress}
324
+        >
325
+            <Left>
326
+                <Thumbnail square source={{uri: item.image}}/>
327
+            </Left>
328
+            <Body>
329
+                <Text style={{marginLeft: 20}}>
330
+                    {item.name}
331
+                </Text>
332
+                <Text note style={{
333
+                    marginLeft: 20,
334
+                    color: this.getStockColor(parseInt(item.quantity))
335
+                }}>
336
+                    {item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
337
+                </Text>
338
+            </Body>
339
+            <Right>
340
+                <Text style={{fontWeight: "bold"}}>
341
+                    {item.price}€
342
+                </Text>
343
+            </Right>
344
+        </ListItem>);
345
+    }
346
+
347
+    keyExtractor(item: Object) {
348
+        return item.name + item.code;
349
+    }
350
+
293 351
     render() {
352
+        // console.log("rendering ProximoListScreen");
294 353
         const nav = this.props.navigation;
295 354
         return (
296 355
             <Container>
@@ -303,7 +362,7 @@ export default class ProximoListScreen extends React.Component<Props, State> {
303 362
                     hasBackButton={true}
304 363
                     navigation={nav}
305 364
                     hasSearchField={true}
306
-                    searchCallback={(text) => this.search(text)}
365
+                    searchCallback={this.onSearchStringChange}
307 366
                     shouldFocusSearchBar={this.shouldFocusSearchBar}
308 367
                     rightButton={this.getSortMenu()}
309 368
                 />
@@ -311,35 +370,9 @@ export default class ProximoListScreen extends React.Component<Props, State> {
311 370
                 <FlatList
312 371
                     data={this.state.currentlyDisplayedData}
313 372
                     extraData={this.state.currentlyDisplayedData}
314
-                    keyExtractor={(item) => item.name + item.code}
373
+                    keyExtractor={this.keyExtractor}
315 374
                     style={{minHeight: 300, width: '100%'}}
316
-                    renderItem={({item}) =>
317
-                        <ListItem
318
-                            thumbnail
319
-                            onPress={() => {
320
-                                this.showItemDetails(item);
321
-                            }}
322
-                        >
323
-                            <Left>
324
-                                <Thumbnail square source={{uri: item.image}}/>
325
-                            </Left>
326
-                            <Body>
327
-                                <Text style={{marginLeft: 20}}>
328
-                                    {item.name}
329
-                                </Text>
330
-                                <Text note style={{
331
-                                    marginLeft: 20,
332
-                                    color: this.getStockColor(parseInt(item.quantity))
333
-                                }}>
334
-                                    {item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
335
-                                </Text>
336
-                            </Body>
337
-                            <Right>
338
-                                <Text style={{fontWeight: "bold"}}>
339
-                                    {item.price}€
340
-                                </Text>
341
-                            </Right>
342
-                        </ListItem>}
375
+                    renderItem={this.renderItem}
343 376
                 />
344 377
             </Container>
345 378
         );

+ 34
- 10
screens/Proximo/ProximoMainScreen.js View File

@@ -9,7 +9,7 @@ import FetchedDataSectionList from "../../components/FetchedDataSectionList";
9 9
 import ThemeManager from "../../utils/ThemeManager";
10 10
 import Touchable from "react-native-platform-touchable";
11 11
 
12
-const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
12
+const DATA_URL = "https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json";
13 13
 
14 14
 
15 15
 /**
@@ -18,12 +18,31 @@ const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~proximo/data/stock-v
18 18
  */
19 19
 export default class ProximoMainScreen extends FetchedDataSectionList {
20 20
 
21
+    onPressSearchBtn: Function;
22
+    onPressAboutBtn: Function;
23
+
21 24
     constructor() {
22 25
         super(DATA_URL, 0);
26
+        this.onPressSearchBtn = this.onPressSearchBtn.bind(this);
27
+        this.onPressAboutBtn = this.onPressAboutBtn.bind(this);
23 28
     }
24 29
 
25 30
     static sortFinalData(a: Object, b: Object) {
26
-        return a.type.id - b.type.id;
31
+        let str1 = a.type.name.toLowerCase();
32
+        let str2 = b.type.name.toLowerCase();
33
+
34
+        // Make 'All' category with id -1 stick to the top
35
+        if (a.type.id === -1)
36
+            return -1;
37
+        if (b.type.id === -1)
38
+            return 1;
39
+
40
+        // Sort others by name ascending
41
+        if (str1 < str2)
42
+            return -1;
43
+        if (str1 > str2)
44
+            return 1;
45
+        return 0;
27 46
     }
28 47
 
29 48
     getHeaderTranslation() {
@@ -63,7 +82,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
63 82
             let articles = fetchedData.articles;
64 83
             finalData.push({
65 84
                 type: {
66
-                    id: "0",
85
+                    id: -1,
67 86
                     name: i18n.t('proximoScreen.all'),
68 87
                     icon: 'star'
69 88
                 },
@@ -100,7 +119,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
100 119
         return availableArticles;
101 120
     }
102 121
 
103
-    getRightButton() {
122
+    onPressSearchBtn() {
104 123
         let searchScreenData = {
105 124
             shouldFocusSearchBar: true,
106 125
             data: {
@@ -113,8 +132,14 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
113 132
                     this.getAvailableArticles(this.state.fetchedData.articles, undefined) : []
114 133
             },
115 134
         };
135
+        this.props.navigation.navigate('ProximoListScreen', searchScreenData);
136
+    }
116 137
 
138
+    onPressAboutBtn() {
139
+        this.props.navigation.navigate('ProximoAboutScreen');
140
+    }
117 141
 
142
+    getRightButton() {
118 143
         return (
119 144
             <View
120 145
                 style={{
@@ -122,14 +147,14 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
122 147
                 }}>
123 148
                 <Touchable
124 149
                     style={{padding: 6}}
125
-                    onPress={() => this.props.navigation.navigate('ProximoListScreen', searchScreenData)}>
150
+                    onPress={this.onPressSearchBtn}>
126 151
                     <CustomMaterialIcon
127 152
                         color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
128 153
                         icon="magnify"/>
129 154
                 </Touchable>
130 155
                 <Touchable
131 156
                     style={{padding: 6}}
132
-                    onPress={() => this.props.navigation.navigate('ProximoAboutScreen')}>
157
+                    onPress={this.onPressAboutBtn}>
133 158
                     <CustomMaterialIcon
134 159
                         color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
135 160
                         icon="information"/>
@@ -138,19 +163,18 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
138 163
         );
139 164
     }
140 165
 
141
-    getRenderItem(item: Object, section: Object, data: Object) {
166
+    getRenderItem(item: Object, section: Object) {
142 167
         let dataToSend = {
143 168
             shouldFocusSearchBar: false,
144 169
             data: item,
145 170
         };
171
+        const onPress = this.props.navigation.navigate.bind(this, 'ProximoListScreen', dataToSend);
146 172
         if (item.data.length > 0) {
147 173
             return (
148 174
                 <ListItem
149 175
                     button
150 176
                     thumbnail
151
-                    onPress={() => {
152
-                        this.props.navigation.navigate('ProximoListScreen', dataToSend);
153
-                    }}
177
+                    onPress={onPress}
154 178
                 >
155 179
                     <Left>
156 180
                         <CustomMaterialIcon

+ 15
- 7
screens/Proxiwash/ProxiwashScreen.js View File

@@ -13,7 +13,7 @@ import Touchable from "react-native-platform-touchable";
13 13
 import AsyncStorageManager from "../../utils/AsyncStorageManager";
14 14
 import * as Expo from "expo";
15 15
 
16
-const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
16
+const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/washinsa/washinsa.json";
17 17
 
18 18
 const MACHINE_STATES = {
19 19
     "TERMINE": "0",
@@ -36,6 +36,8 @@ const REFRESH_TIME = 1000 * 10; // Refresh every 10 seconds
36 36
  */
37 37
 export default class ProxiwashScreen extends FetchedDataSectionList {
38 38
 
39
+    onAboutPress: Function;
40
+
39 41
     /**
40 42
      * Creates machine state parameters using current theme and translations
41 43
      */
@@ -75,6 +77,8 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
75 77
             machinesWatched: [],
76 78
         };
77 79
         this.setMinTimeRefresh(30);
80
+
81
+        this.onAboutPress = this.onAboutPress.bind(this);
78 82
     }
79 83
 
80 84
     /**
@@ -82,7 +86,6 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
82 86
      */
83 87
     componentDidMount() {
84 88
         super.componentDidMount();
85
-
86 89
         if (AsyncStorageManager.getInstance().preferences.expoToken.current !== '') {
87 90
             // Get latest watchlist from server
88 91
             NotificationsManager.getMachineNotificationWatchlist((fetchedList) => {
@@ -241,13 +244,14 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
241 244
     showAlert(title: string, item: Object, isDryer: boolean) {
242 245
         let buttons = [{text: i18n.t("proxiwashScreen.modal.ok")}];
243 246
         let message = modalStateStrings[MACHINE_STATES[item.state]];
247
+        const onPress = this.setupNotifications.bind(this, item.number);
244 248
         if (MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"]) {
245 249
             buttons = [
246 250
                 {
247 251
                     text: this.isMachineWatched(item.number) ?
248 252
                         i18n.t("proxiwashScreen.modal.disableNotifications") :
249 253
                         i18n.t("proxiwashScreen.modal.enableNotifications"),
250
-                    onPress: () => this.setupNotifications(item.number)
254
+                    onPress: onPress
251 255
                 },
252 256
                 {
253 257
                     text: i18n.t("proxiwashScreen.modal.cancel")
@@ -272,11 +276,15 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
272 276
         );
273 277
     }
274 278
 
279
+    onAboutPress() {
280
+        this.props.navigation.navigate('ProxiwashAboutScreen');
281
+    }
282
+
275 283
     getRightButton(): * {
276 284
         return (
277 285
             <Touchable
278 286
                 style={{padding: 6}}
279
-                onPress={() => this.props.navigation.navigate('ProxiwashAboutScreen')}>
287
+                onPress={this.onAboutPress}>
280 288
                 <CustomMaterialIcon
281 289
                     color={Platform.OS === 'ios' ? ThemeManager.getCurrentThemeVariables().brandPrimary : "#fff"}
282 290
                     icon="information"/>
@@ -289,13 +297,13 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
289 297
      *
290 298
      * @param item The object containing the item's FetchedData
291 299
      * @param section The object describing the current SectionList section
292
-     * @param data The full FetchedData used by the SectionList
293 300
      * @returns {React.Node}
294 301
      */
295
-    getRenderItem(item: Object, section: Object, data: Object) {
302
+    getRenderItem(item: Object, section: Object) {
296 303
         let isMachineRunning = MACHINE_STATES[item.state] === MACHINE_STATES["EN COURS"];
297 304
         let machineName = (section.title === i18n.t('proxiwashScreen.dryers') ? i18n.t('proxiwashScreen.dryer') : i18n.t('proxiwashScreen.washer')) + ' n°' + item.number;
298 305
         let isDryer = section.title === i18n.t('proxiwashScreen.dryers');
306
+        const onPress = this.showAlert.bind(this, machineName, item, isDryer);
299 307
         return (
300 308
             <Card style={{
301 309
                 flex: 0,
@@ -320,7 +328,7 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
320 328
                         backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor
321 329
                     }}/>
322 330
                     <PlatformTouchable
323
-                        onPress={() => this.showAlert(machineName, item, isDryer)}
331
+                        onPress={onPress}
324 332
                         style={{
325 333
                             height: 64,
326 334
                             position: 'absolute',

+ 2
- 2
screens/SelfMenuScreen.js View File

@@ -7,7 +7,7 @@ import ThemeManager from "../utils/ThemeManager";
7 7
 import i18n from "i18n-js";
8 8
 import FetchedDataSectionList from "../components/FetchedDataSectionList";
9 9
 
10
-const DATA_URL = "https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
10
+const DATA_URL = "https://etud.insa-toulouse.fr/~amicale_app/menu/menu_data.json";
11 11
 
12 12
 /**
13 13
  * Class defining the app's menu screen.
@@ -119,7 +119,7 @@ export default class SelfMenuScreen extends FetchedDataSectionList {
119 119
         );
120 120
     }
121 121
 
122
-    getRenderItem(item: Object, section: Object, data: Object) {
122
+    getRenderItem(item: Object, section: Object) {
123 123
         return (
124 124
             <Card style={{
125 125
                 flex: 0,

+ 16
- 5
screens/SettingsScreen.js View File

@@ -43,6 +43,17 @@ export default class SettingsScreen extends React.Component<Props, State> {
43 43
         startScreenPickerSelected: AsyncStorageManager.getInstance().preferences.defaultStartScreen.current,
44 44
     };
45 45
 
46
+    onProxiwashNotifPickerValueChange: Function;
47
+    onStartScreenPickerValueChange: Function;
48
+    onToggleNightMode: Function;
49
+
50
+    constructor() {
51
+        super();
52
+        this.onProxiwashNotifPickerValueChange = this.onProxiwashNotifPickerValueChange.bind(this);
53
+        this.onStartScreenPickerValueChange = this.onStartScreenPickerValueChange.bind(this);
54
+        this.onToggleNightMode = this.onToggleNightMode.bind(this);
55
+    }
56
+
46 57
     /**
47 58
      * Get a list item using the specified control
48 59
      *
@@ -118,7 +129,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
118 129
                 mode="dropdown"
119 130
                 style={{width: 120}}
120 131
                 selectedValue={this.state.proxiwashNotifPickerSelected}
121
-                onValueChange={(value) => this.onProxiwashNotifPickerValueChange(value)}
132
+                onValueChange={this.onProxiwashNotifPickerValueChange}
122 133
             >
123 134
                 <Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.never')} value="never"/>
124 135
                 <Picker.Item label={i18n.t('settingsScreen.proxiwashNotifReminderPicker.5')} value="5"/>
@@ -141,7 +152,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
141 152
                 mode="dropdown"
142 153
                 style={{width: 120}}
143 154
                 selectedValue={this.state.startScreenPickerSelected}
144
-                onValueChange={(value) => this.onStartScreenPickerValueChange(value)}
155
+                onValueChange={this.onStartScreenPickerValueChange}
145 156
             >
146 157
                 <Picker.Item label={i18n.t('screens.home')} value="Home"/>
147 158
                 <Picker.Item label={i18n.t('screens.planning')} value="Planning"/>
@@ -155,7 +166,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
155 166
     /**
156 167
      * Toggle night mode and save it to preferences
157 168
      */
158
-    toggleNightMode() {
169
+    onToggleNightMode() {
159 170
         ThemeManager.getInstance().setNightMode(!this.state.nightMode);
160 171
         this.setState({nightMode: !this.state.nightMode});
161 172
         this.resetStack();
@@ -203,7 +214,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
203 214
                 <Right>
204 215
                     <CheckBox
205 216
                         checked={this.state.nightMode}
206
-                        onPress={() => this.toggleNightMode()}
217
+                        onPress={onPressCallback}
207 218
                         style={{marginRight: 20}}/>
208 219
                 </Right>
209 220
             </ListItem>
@@ -221,7 +232,7 @@ export default class SettingsScreen extends React.Component<Props, State> {
221 232
                             <Text>{i18n.t('settingsScreen.generalCard')}</Text>
222 233
                         </CardItem>
223 234
                         <List>
224
-                            {this.getToggleItem(() => this.toggleNightMode(), 'theme-light-dark', i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.nightModeSub'))}
235
+                            {this.getToggleItem(this.onToggleNightMode, 'theme-light-dark', i18n.t('settingsScreen.nightMode'), i18n.t('settingsScreen.nightModeSub'))}
225 236
                             {SettingsScreen.getGeneralItem(this.getStartScreenPicker(), 'power', i18n.t('settingsScreen.startScreen'), i18n.t('settingsScreen.startScreenSub'))}
226 237
                         </List>
227 238
                     </Card>

+ 1
- 1
screens/Websites/AmicaleScreen.js View File

@@ -8,7 +8,7 @@ type Props = {
8 8
 }
9 9
 
10 10
 
11
-const URL = 'https://www.etud.insa-toulouse.fr/~amicale';
11
+const URL = 'https://amicale-insat.fr/';
12 12
 
13 13
 /**
14 14
  * Class defining the app's planex screen.

+ 2
- 2
screens/Websites/AvailableRoomScreen.js View File

@@ -12,8 +12,8 @@ type Props = {
12 12
 const ROOM_URL = 'http://planex.insa-toulouse.fr/salles.php';
13 13
 const PC_URL = 'http://planex.insa-toulouse.fr/sallesInfo.php';
14 14
 const BIB_URL = 'https://bibbox.insa-toulouse.fr/';
15
-const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
16
-const CUSTOM_CSS_Bib = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
15
+const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customMobile.css';
16
+const CUSTOM_CSS_Bib = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/rooms/customBibMobile.css';
17 17
 
18 18
 /**
19 19
  * Class defining the app's planex screen.

+ 1
- 1
screens/Websites/BlueMindScreen.js View File

@@ -11,7 +11,7 @@ type Props = {
11 11
 
12 12
 const URL = 'https://etud-mel.insa-toulouse.fr/webmail/';
13 13
 
14
-const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/bluemind/customMobile.css';
14
+const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/bluemind/customMobile.css';
15 15
 
16 16
 
17 17
 /**

+ 1
- 1
screens/Websites/ElusEtudScreen.js View File

@@ -8,7 +8,7 @@ type Props = {
8 8
 }
9 9
 
10 10
 
11
-const URL = 'https://srv-falcon.etud.insa-toulouse.fr/~eeinsat/';
11
+const URL = 'https://etud.insa-toulouse.fr/~eeinsat/';
12 12
 
13 13
 /**
14 14
  * Class defining the app's planex screen.

+ 2
- 2
screens/Websites/EntScreen.js View File

@@ -11,12 +11,12 @@ type Props = {
11 11
 
12 12
 const URL = 'https://ent.insa-toulouse.fr/';
13 13
 
14
-const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
14
+const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
15 15
 
16 16
 // let stylesheet = document.createElement('link');
17 17
 // stylesheet.type = 'text/css';
18 18
 // stylesheet.rel = 'stylesheet';
19
-// stylesheet.href = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
19
+// stylesheet.href = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/ent/customMobile.css';
20 20
 // let mobileSpec = document.createElement('meta');
21 21
 // mobileSpec.name = 'viewport';
22 22
 // mobileSpec.content = 'width=device-width, initial-scale=1.0';

+ 2
- 2
screens/Websites/PlanexScreen.js View File

@@ -11,8 +11,8 @@ type Props = {
11 11
 
12 12
 const PLANEX_URL = 'http://planex.insa-toulouse.fr/';
13 13
 
14
-const CUSTOM_CSS_GENERAL = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customMobile3.css';
15
-const CUSTOM_CSS_NIGHTMODE = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customDark2.css';
14
+const CUSTOM_CSS_GENERAL = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customMobile3.css';
15
+const CUSTOM_CSS_NIGHTMODE = 'https://etud.insa-toulouse.fr/~amicale_app/custom_css/planex/customDark2.css';
16 16
 
17 17
 // // JS + JQuery functions used to remove alpha from events. Copy paste in browser console for quick testing
18 18
 // // Remove alpha from given Jquery node

+ 1
- 1
screens/Websites/WiketudScreen.js View File

@@ -8,7 +8,7 @@ type Props = {
8 8
 }
9 9
 
10 10
 
11
-const URL = 'https://www.etud.insa-toulouse.fr/wiketud';
11
+const URL = 'https://wiki.etud.insa-toulouse.fr/';
12 12
 
13 13
 /**
14 14
  * Class defining the app's planex screen.

+ 4
- 32
utils/NotificationsManager.js View File

@@ -6,7 +6,7 @@ import AsyncStorageManager from "./AsyncStorageManager";
6 6
 import LocaleManager from "./LocaleManager";
7 7
 import passwords from "../passwords";
8 8
 
9
-const EXPO_TOKEN_SERVER = 'https://srv-falcon.etud.insa-toulouse.fr/~amicale_app/expo_notifications/save_token.php';
9
+const EXPO_TOKEN_SERVER = 'https://etud.insa-toulouse.fr/~amicale_app/expo_notifications/save_token.php';
10 10
 
11 11
 /**
12 12
  * Static class used to manage notifications sent to the user
@@ -123,18 +123,8 @@ export default class NotificationsManager {
123 123
                     'Content-Type': 'application/json',
124 124
                 }),
125 125
                 body: JSON.stringify(data) // <-- Post parameters
126
-            })
127
-                .then((response) => response.json())
128
-                .then((responseJson) => {
129
-                    callback(responseJson);
130
-                })
131
-                .catch((error) => {
132
-                    console.log(error);
133
-                });
134
-        } else {
135
-            console.log('Expo token not available');
126
+            });
136 127
         }
137
-
138 128
     }
139 129
 
140 130
     /**
@@ -161,16 +151,7 @@ export default class NotificationsManager {
161 151
                     'Content-Type': 'application/json',
162 152
                 }),
163 153
                 body: JSON.stringify(data) // <-- Post parameters
164
-            })
165
-                .then((response) => response.text())
166
-                .then((responseText) => {
167
-                    console.log(responseText);
168
-                })
169
-                .catch((error) => {
170
-                    console.log(error);
171
-                });
172
-        } else {
173
-            console.log('Expo token not available');
154
+            });
174 155
         }
175 156
     }
176 157
 
@@ -194,16 +175,7 @@ export default class NotificationsManager {
194 175
                     'Content-Type': 'application/json',
195 176
                 }),
196 177
                 body: JSON.stringify(data) // <-- Post parameters
197
-            })
198
-                .then((response) => response.text())
199
-                .then((responseText) => {
200
-                    console.log(responseText);
201
-                })
202
-                .catch((error) => {
203
-                    console.log(error);
204
-                });
205
-        } else {
206
-            console.log('Expo token not available');
178
+            });
207 179
         }
208 180
     }
209 181
 }

+ 2
- 2
utils/WebDataManager.js View File

@@ -25,8 +25,8 @@ export default class WebDataManager {
25 25
             let response = await fetch(this.FETCH_URL);
26 26
             fetchedData = await response.json();
27 27
         } catch (error) {
28
-            console.log('Could not read FetchedData from server');
29
-            console.log(error);
28
+            // console.log('Could not read FetchedData from server');
29
+            // console.log(error);
30 30
             throw new Error('Could not read FetchedData from server');
31 31
         }
32 32
         this.lastDataFetched = fetchedData;

Loading…
Cancel
Save