Browse Source

improved assets, added more details in app.json

keplyx 4 years ago
parent
commit
405f1769d3

+ 15
- 9
App.js View File

@@ -1,9 +1,8 @@
1 1
 // @flow
2 2
 
3
-import React from 'react';
3
+import * as React from 'react';
4 4
 import {Root, StyleProvider, Text} from 'native-base';
5
-import {Ionicons} from '@expo/vector-icons';
6
-import {StyleSheet, View, Image} from 'react-native'
5
+import {Image, StyleSheet, View} from 'react-native'
7 6
 import AppNavigator from './navigation/AppNavigator';
8 7
 import ThemeManager from './utils/ThemeManager';
9 8
 import LocaleManager from './utils/LocaleManager';
@@ -43,6 +42,7 @@ const styles = StyleSheet.create({
43 42
     },
44 43
 });
45 44
 
45
+// Content to be used int the intro slides
46 46
 const slides = [
47 47
     {
48 48
         key: '1',
@@ -61,7 +61,7 @@ const slides = [
61 61
     {
62 62
         key: '3',
63 63
         title: 'Le proximo',
64
-        text: 'Regardez le stock de la supérette de l\'INSA depuis n\'importe où' ,
64
+        text: 'Regardez le stock de la supérette de l\'INSA depuis n\'importe où',
65 65
         icon: 'shopping',
66 66
         colors: ['#f9a967', '#da5204'],
67 67
     },
@@ -101,12 +101,14 @@ export default class App extends React.Component<Props, State> {
101 101
      * @returns {Promise}
102 102
      */
103 103
     async componentWillMount() {
104
+        // Wait for custom fonts to be loaded before showing the app
104 105
         await Font.loadAsync({
105 106
             'Roboto': require('native-base/Fonts/Roboto.ttf'),
106 107
             'Roboto_medium': require('native-base/Fonts/Roboto_medium.ttf'),
107 108
         });
108 109
         await AsyncStorageManager.getInstance().loadPreferences();
109 110
         ThemeManager.getInstance().setUpdateThemeCallback(() => this.updateTheme());
111
+        // Only show intro if this is the first time starting the app
110 112
         this.setState({
111 113
             isLoading: false,
112 114
             currentTheme: ThemeManager.getCurrentTheme(),
@@ -115,17 +117,20 @@ export default class App extends React.Component<Props, State> {
115 117
     }
116 118
 
117 119
     /**
118
-     * Updates the theme and clears the cache to force reloading the app colors
120
+     * Updates the theme and clears the cache to force reloading the app colors. Need to edit shoutem theme for ti to work
119 121
      */
120 122
     updateTheme() {
121
-        // console.log('update theme called');
122 123
         this.setState({
123 124
             currentTheme: ThemeManager.getCurrentTheme()
124 125
         });
125 126
         clearThemeCache();
126 127
     }
127 128
 
128
-
129
+    /**
130
+     * Render item to be used for the intro slides
131
+     * @param item
132
+     * @param dimensions
133
+     */
129 134
     getIntroRenderItem(item: Object, dimensions: Object) {
130 135
         return (
131 136
             <LinearGradient
@@ -148,6 +153,9 @@ export default class App extends React.Component<Props, State> {
148 153
         );
149 154
     }
150 155
 
156
+    /**
157
+     * Callback when user ends the intro. Save in preferences to avaoid showing back the slides
158
+     */
151 159
     onIntroDone() {
152 160
         this.setState({showIntro: false});
153 161
         AsyncStorageManager.getInstance().savePref(AsyncStorageManager.getInstance().preferences.showIntro.key, '0');
@@ -155,8 +163,6 @@ export default class App extends React.Component<Props, State> {
155 163
 
156 164
     /**
157 165
      * Renders the app based on loading state
158
-     *
159
-     * @returns {*}
160 166
      */
161 167
     render() {
162 168
         if (this.state.isLoading) {

+ 24
- 10
app.json View File

@@ -1,6 +1,7 @@
1 1
 {
2 2
   "expo": {
3 3
     "name": "Amicale INSAT",
4
+    "description": "Application mobile compatible Android et iOS pour l'Amicale INSA Toulouse. Grâce à cette application, vous avez facilement accès aux news du campus, aux emplois du temps, à l'état de la laverie, et bien d'autres services ! Ceci est une version Beta, Toutes les fonctionnalités ne sont pas encore implémentées, et il est possible de rencontrer quelques bugs.",
4 5
     "slug": "application-amicale",
5 6
     "privacy": "public",
6 7
     "sdkVersion": "33.0.0",
@@ -9,29 +10,42 @@
9 10
       "android",
10 11
       "web"
11 12
     ],
12
-    "version": "0.0.4",
13
+    "version": "0.0.5",
13 14
     "orientation": "portrait",
14
-    "icon": "./assets/icon.png",
15 15
     "primaryColor": "#e42612",
16
+    "icon": "./assets/icon.png",
16 17
     "splash": {
17
-      "image": "./assets/splash.png",
18
-      "resizeMode": "cover",
19
-      "backgroundColor": "#fff"
18
+      "backgroundColor": "#fff",
19
+      "resizeMode": "contain",
20
+      "image": "./assets/splash.png"
21
+    },
22
+    "notification": {
23
+      "icon": "./assets/amicale-notification.png",
24
+      "color": "#e42612",
25
+      "androidMode": "default"
20 26
     },
21 27
     "updates": {
22
-      "fallbackToCacheTimeout": 0
28
+      "enabled": false
23 29
     },
24 30
     "assetBundlePatterns": [
25 31
       "**/*"
26 32
     ],
27 33
     "ios": {
28
-      "supportsTablet": true,
29
-      "icon": "./assets/ios.icon.png",
30
-      "bundleIdentifier": "com.test.applicationamicale"
34
+      "bundleIdentifier": "amicale.insat.application",
35
+      "buildNumber": "0.0.5",
36
+      "icon": "./assets/ios.icon.png"
31 37
     },
32 38
     "android": {
39
+      "package": "amicale.insat.application",
40
+      "versionCode": 1,
33 41
       "icon": "./assets/android.icon.png",
34
-      "package": "com.test.applicationamicale"
42
+      "adaptiveIcon": {
43
+        "foregroundImage": "./assets/android.adaptive-icon.png",
44
+        "backgroundColor": "#ffffff"
45
+      },
46
+      "permissions": [
47
+        "VIBRATE"
48
+      ]
35 49
     }
36 50
   }
37 51
 }

BIN
assets/amicale-notification.png View File


BIN
assets/android.icon.png View File


BIN
assets/splash.png View File


+ 3
- 2
components/CustomHeader.js View File

@@ -1,8 +1,8 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from "react";
4
-import {Body, Header, Icon, Left, Right, Title} from "native-base";
5
-import {StyleSheet, Platform} from "react-native";
4
+import {Body, Header, Left, Right, Title} from "native-base";
5
+import {Platform, StyleSheet} from "react-native";
6 6
 import {getStatusBarHeight} from "react-native-status-bar-height";
7 7
 import Touchable from 'react-native-platform-touchable';
8 8
 import ThemeManager from "../utils/ThemeManager";
@@ -34,6 +34,7 @@ export default class CustomHeader extends React.Component<Props> {
34 34
 
35 35
     render() {
36 36
         let button;
37
+        // Does the app have a back button or a burger menu ?
37 38
         if (this.props.backButton)
38 39
             button =
39 40
                 <Touchable

+ 1
- 1
components/CustomMaterialIcon.js View File

@@ -9,7 +9,7 @@ type Props = {
9 9
     icon: string,
10 10
     color: ?string,
11 11
     fontSize: number,
12
-    width: number|string,
12
+    width: number | string,
13 13
 }
14 14
 
15 15
 /**

+ 85
- 12
components/FetchedDataSectionList.js View File

@@ -20,16 +20,20 @@ type State = {
20 20
     machinesWatched: Array<Object>,
21 21
 };
22 22
 
23
+/**
24
+ * Class used to create a basic list view using online json data.
25
+ * Used by inheriting from it and redefining getters.
26
+ */
23 27
 export default class FetchedDataSectionList extends React.Component<Props, State> {
24 28
 
25 29
     webDataManager: WebDataManager;
26 30
 
27
-    willFocusSubscription : function;
28
-    willBlurSubscription : function;
31
+    willFocusSubscription: function;
32
+    willBlurSubscription: function;
29 33
     refreshInterval: IntervalID;
30 34
     refreshTime: number;
31 35
 
32
-    constructor(fetchUrl: string, refreshTime : number) {
36
+    constructor(fetchUrl: string, refreshTime: number) {
33 37
         super();
34 38
         this.webDataManager = new WebDataManager(fetchUrl);
35 39
         this.refreshTime = refreshTime;
@@ -42,16 +46,25 @@ export default class FetchedDataSectionList extends React.Component<Props, State
42 46
         machinesWatched: [],
43 47
     };
44 48
 
45
-    getHeaderTranslation() {
49
+    /**
50
+     * Get the translation for the header in the current language
51
+     * @return {string}
52
+     */
53
+    getHeaderTranslation() : string {
46 54
         return "Header";
47 55
     }
48 56
 
49
-    getUpdateToastTranslations() {
57
+    /**
58
+     * Get the translation for the toasts in the current language
59
+     * @return {string}
60
+     */
61
+    getUpdateToastTranslations(): Array<string> {
50 62
         return ["whoa", "nah"];
51 63
     }
52 64
 
53 65
     /**
54
-     * Register react navigation events on first screen load
66
+     * Register react navigation events on first screen load.
67
+     * Allows to detect when the screen is focused
55 68
      */
56 69
     componentDidMount() {
57 70
         this.willFocusSubscription = this.props.navigation.addListener(
@@ -68,28 +81,37 @@ export default class FetchedDataSectionList extends React.Component<Props, State
68 81
         );
69 82
     }
70 83
 
84
+    /**
85
+     * Refresh data when focusing the screen and setup a refresh interval if asked to
86
+     */
71 87
     onScreenFocus() {
72 88
         this._onRefresh();
73 89
         if (this.refreshTime > 0)
74 90
             this.refreshInterval = setInterval(() => this._onRefresh(), this.refreshTime)
75 91
     }
76 92
 
93
+    /**
94
+     * Remove any interval on un-focus
95
+     */
77 96
     onScreenBlur() {
78 97
         clearInterval(this.refreshInterval);
79 98
     }
80 99
 
81
-
100
+    /**
101
+     * Unregister from event when un-mounting components
102
+     */
82 103
     componentWillUnmount() {
83 104
         if (this.willBlurSubscription !== undefined)
84 105
             this.willBlurSubscription.remove();
85 106
         if (this.willFocusSubscription !== undefined)
86 107
             this.willFocusSubscription.remove();
87
-
88 108
     }
89 109
 
90
-
110
+    /**
111
+     * Refresh data and show a toast if any error occurred
112
+     * @private
113
+     */
91 114
     _onRefresh = () => {
92
-        console.log('refresh');
93 115
         this.setState({refreshing: true});
94 116
         this.webDataManager.readData().then((fetchedData) => {
95 117
             this.setState({
@@ -101,14 +123,38 @@ export default class FetchedDataSectionList extends React.Component<Props, State
101 123
         });
102 124
     };
103 125
 
126
+    /**
127
+     * Get the render item to be used for display in the list.
128
+     * Must be overridden by inheriting class.
129
+     *
130
+     * @param item
131
+     * @param section
132
+     * @param data
133
+     * @return {*}
134
+     */
104 135
     getRenderItem(item: Object, section: Object, data: Object) {
105 136
         return <View/>;
106 137
     }
107 138
 
139
+    /**
140
+     * Get the render item to be used for the section title in the list.
141
+     * Must be overridden by inheriting class.
142
+     *
143
+     * @param title
144
+     * @return {*}
145
+     */
108 146
     getRenderSectionHeader(title: String) {
109 147
         return <View/>;
110 148
     }
111 149
 
150
+    /**
151
+     * Get the render item to be used when the list is empty.
152
+     * No need to be overridden, has good defaults.
153
+     *
154
+     * @param text
155
+     * @param icon
156
+     * @return {*}
157
+     */
112 158
     getEmptyRenderItem(text: string, icon: string) {
113 159
         return (
114 160
             <View>
@@ -138,7 +184,9 @@ export default class FetchedDataSectionList extends React.Component<Props, State
138 184
     }
139 185
 
140 186
     /**
141
-     * Create the dataset to be used in the list from the data fetched
187
+     * Create the dataset to be used in the list from the data fetched.
188
+     * Must be overridden.
189
+     *
142 190
      * @param fetchedData {Object}
143 191
      * @return {Array}
144 192
      */
@@ -146,6 +194,12 @@ export default class FetchedDataSectionList extends React.Component<Props, State
146 194
         return [];
147 195
     }
148 196
 
197
+    /**
198
+     * Create the dataset when no fetched data is available.
199
+     * No need to be overridden, has good defaults.
200
+     *
201
+     * @return
202
+     */
149 203
     createEmptyDataset() {
150 204
         return [
151 205
             {
@@ -165,10 +219,23 @@ export default class FetchedDataSectionList extends React.Component<Props, State
165 219
         ];
166 220
     }
167 221
 
222
+    /**
223
+     * Should the app use a tab layout instead of a section list ?
224
+     * If yes, each section will be rendered in a new tab.
225
+     * Can be overridden.
226
+     *
227
+     * @return {boolean}
228
+     */
168 229
     hasTabs() {
169 230
         return false;
170 231
     }
171 232
 
233
+    /**
234
+     * Get the section list render using the generated dataset
235
+     *
236
+     * @param dataset
237
+     * @return
238
+     */
172 239
     getSectionList(dataset: Array<Object>) {
173 240
         let isEmpty = dataset[0].data.length === 0;
174 241
         if (isEmpty)
@@ -201,6 +268,12 @@ export default class FetchedDataSectionList extends React.Component<Props, State
201 268
         );
202 269
     }
203 270
 
271
+    /**
272
+     * Generate the tabs containing the lists
273
+     *
274
+     * @param dataset
275
+     * @return
276
+     */
204 277
     getTabbedView(dataset: Array<Object>) {
205 278
         let tabbedView = [];
206 279
         for (let i = 0; i < dataset.length; i++) {
@@ -214,7 +287,7 @@ export default class FetchedDataSectionList extends React.Component<Props, State
214 287
                         <Text>{dataset[i].title}</Text>
215 288
                     </TabHeading>}
216 289
                      key={dataset[i].title}
217
-                style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
290
+                     style={{backgroundColor: ThemeManager.getCurrentThemeVariables().containerBgColor}}>
218 291
                     {this.getSectionList(
219 292
                         [
220 293
                             {

+ 4
- 20
components/SideMenu.js View File

@@ -1,8 +1,8 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {Platform, Dimensions, StyleSheet, Image, FlatList, Linking} from 'react-native';
5
-import {Badge, Text, Container, Content, Left, ListItem, Right} from "native-base";
4
+import {Dimensions, FlatList, Image, Linking, Platform, StyleSheet} from 'react-native';
5
+import {Badge, Container, Content, Left, ListItem, Right, Text} from "native-base";
6 6
 import i18n from "i18n-js";
7 7
 import CustomMaterialIcon from '../components/CustomMaterialIcon';
8 8
 
@@ -40,72 +40,56 @@ export default class SideBar extends React.Component<Props, State> {
40 40
      */
41 41
     constructor(props: Props) {
42 42
         super(props);
43
+        // Dataset used to render the drawer
44
+        // If the link field is defined, clicking on the item will open the link
43 45
         this.dataSet = [
44 46
             {
45 47
                 name: i18n.t('screens.home'),
46 48
                 route: "Home",
47 49
                 icon: "home",
48
-                bg: "#C5F442"
49
-                // types: "11" // Shows the badge
50 50
             },
51 51
             {
52 52
                 name: i18n.t('screens.planning'),
53 53
                 route: "Planning",
54 54
                 icon: "calendar-range",
55
-                bg: "#477EEA",
56
-                // types: "11"
57 55
             },
58 56
             {
59 57
                 name: "Proxiwash",
60 58
                 route: "Proxiwash",
61 59
                 icon: "washing-machine",
62
-                bg: "#477EEA",
63
-                // types: "11"
64 60
             },
65 61
             {
66 62
                 name: "Proximo",
67 63
                 route: "Proximo",
68 64
                 icon: "shopping",
69
-                bg: "#477EEA",
70
-                // types: "11"
71 65
             },
72 66
             {
73 67
                 name: "Amicale",
74 68
                 route: "amicale",
75 69
                 icon: "web",
76
-                bg: "#477EEA",
77 70
                 link: Amicale_LINK
78
-                // types: "11"
79 71
             },
80 72
             {
81 73
                 name: i18n.t('screens.timetable'),
82 74
                 route: "timetable",
83 75
                 icon: "timetable",
84
-                bg: "#477EEA",
85 76
                 link: TIMETABLE_LINK
86
-                // types: "11"
87 77
             },
88 78
             {
89 79
                 name: "Wiketud",
90 80
                 route: "wiketud",
91 81
                 icon: "wikipedia",
92
-                bg: "#477EEA",
93 82
                 link: WIKETUD_LINK
94
-                // types: "11"
95 83
             },
96 84
             {
97 85
                 name: i18n.t('screens.settings'),
98 86
                 route: "Settings",
99 87
                 icon: "settings",
100
-                bg: "#477EEA",
101
-                // types: "11"
102 88
             },
103 89
             {
104 90
                 name: i18n.t('screens.about'),
105 91
                 route: "About",
106 92
                 icon: "information",
107
-                bg: "#477EEA",
108
-                // types: "11"
109 93
             },
110 94
         ];
111 95
     }

+ 2
- 2
screens/About/AboutDependenciesScreen.js View File

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {Container, Text, Content, ListItem, Body} from 'native-base';
4
+import {Body, Container, Content, ListItem, Text} from 'native-base';
5 5
 import CustomHeader from "../../components/CustomHeader";
6 6
 import {FlatList} from "react-native";
7 7
 import i18n from "i18n-js";
@@ -30,7 +30,7 @@ export default class AboutDependenciesScreen extends React.Component<Props> {
30 30
         const data = generateListFromObject(nav.getParam('data', {}));
31 31
         return (
32 32
             <Container>
33
-                <CustomHeader backButton={true} navigation={nav} title={i18n.t('aboutScreen.libs')} />
33
+                <CustomHeader backButton={true} navigation={nav} title={i18n.t('aboutScreen.libs')}/>
34 34
                 <Content>
35 35
                     <FlatList
36 36
                         data={data}

+ 2
- 2
screens/About/AboutScreen.js View File

@@ -1,8 +1,8 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {Platform, StyleSheet, Linking, Alert, FlatList} from 'react-native';
5
-import {Container, Content, Text, Card, CardItem, Body, Left, Right, Thumbnail, H1} from 'native-base';
4
+import {Alert, FlatList, Linking, Platform} from 'react-native';
5
+import {Body, Card, CardItem, Container, Content, H1, Left, Right, Text, Thumbnail} from 'native-base';
6 6
 import CustomHeader from "../../components/CustomHeader";
7 7
 import i18n from "i18n-js";
8 8
 import appJson from '../../app';

+ 1
- 1
screens/PlanningScreen.js View File

@@ -65,7 +65,7 @@ export default class PlanningScreen extends React.Component<Props> {
65 65
                     </Text>
66 66
                     {Platform.OS === 'android' ?
67 67
                         <Button block style={{marginTop: 20, marginRight: 10, marginLeft: 10}}
68
-                        onPress={() => openWebLink('https://expo.io/@amicaleinsat/application-amicale')}>
68
+                                onPress={() => openWebLink('https://expo.io/@amicaleinsat/application-amicale')}>
69 69
                             <Text>Try the beta</Text>
70 70
                         </Button>
71 71
                         : <View/>}

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

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {Container, Text, Content, ListItem, Left, Thumbnail, Right, Body} from 'native-base';
4
+import {Body, Container, Content, Left, ListItem, Right, Text, Thumbnail} from 'native-base';
5 5
 import CustomHeader from "../../components/CustomHeader";
6 6
 import {FlatList, Platform} from "react-native";
7 7
 import Touchable from 'react-native-platform-touchable';
@@ -132,8 +132,14 @@ export default class ProximoListScreen extends React.Component<Props, State> {
132 132
         this.setSortMode(this.state.currentSortMode, this.state.isSortReversed);
133 133
     }
134 134
 
135
+    /**
136
+     * get color depending on quantity available
137
+     *
138
+     * @param availableStock
139
+     * @return
140
+     */
135 141
     getStockColor(availableStock: number) {
136
-        let color : string;
142
+        let color: string;
137 143
         if (availableStock > 3)
138 144
             color = ThemeManager.getCurrentThemeVariables().brandSuccess;
139 145
         else if (availableStock > 0)
@@ -234,7 +240,8 @@ export default class ProximoListScreen extends React.Component<Props, State> {
234 240
                                     </Text>
235 241
                                     <Text note style={{
236 242
                                         marginLeft: 20,
237
-                                    color: this.getStockColor(parseInt(item.quantity))}}>
243
+                                        color: this.getStockColor(parseInt(item.quantity))
244
+                                    }}>
238 245
                                         {item.quantity + ' ' + i18n.t('proximoScreen.inStock')}
239 246
                                     </Text>
240 247
                                 </Body>

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

@@ -78,7 +78,7 @@ export default class ProximoMainScreen extends FetchedDataSectionList {
78 78
         return finalData;
79 79
     }
80 80
 
81
-    getRenderItem(item: Object, section : Object, data : Object) {
81
+    getRenderItem(item: Object, section: Object, data: Object) {
82 82
         if (item.data.length > 0) {
83 83
             return (
84 84
                 <ListItem

+ 37
- 8
screens/ProxiwashScreen.js View File

@@ -1,7 +1,7 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {Alert, View, Platform} from 'react-native';
4
+import {Alert, Platform, View} from 'react-native';
5 5
 import {Body, Card, CardItem, Left, Right, Text} from 'native-base';
6 6
 import ThemeManager from '../utils/ThemeManager';
7 7
 import i18n from "i18n-js";
@@ -36,7 +36,7 @@ let stateColors = {};
36 36
  */
37 37
 export default class ProxiwashScreen extends FetchedDataSectionList {
38 38
 
39
-    refreshInterval : IntervalID;
39
+    refreshInterval: IntervalID;
40 40
 
41 41
     /**
42 42
      * Creates machine state parameters using current theme and translations
@@ -77,6 +77,9 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
77 77
         };
78 78
     }
79 79
 
80
+    /**
81
+     * Setup notification channel for android and add listeners to detect notifications fired
82
+     */
80 83
     componentDidMount() {
81 84
         super.componentDidMount();
82 85
         if (Platform.OS === 'android') {
@@ -104,10 +107,6 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
104 107
         return [i18n.t("proxiwashScreen.listUpdated"), i18n.t("proxiwashScreen.listUpdateFail")];
105 108
     }
106 109
 
107
-    getKeyExtractor(item: Object) {
108
-        return item !== undefined ? item.number : undefined;
109
-    }
110
-
111 110
     getDryersKeyExtractor(item: Object) {
112 111
         return item !== undefined ? "dryer" + item.number : undefined;
113 112
     }
@@ -202,13 +201,26 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
202 201
         }
203 202
     }
204 203
 
205
-    getMachineIndexInWatchList(machineId: string) {
204
+    /**
205
+     * Get the index of the given machine ID in the watchlist array
206
+     *
207
+     * @param machineId
208
+     * @return
209
+     */
210
+    getMachineIndexInWatchList(machineId: string): number {
206 211
         let elem = this.state.machinesWatched.find(function (elem) {
207 212
             return elem.machineNumber === machineId
208 213
         });
209 214
         return this.state.machinesWatched.indexOf(elem);
210 215
     }
211 216
 
217
+    /**
218
+     * Add the given notifications associated to a machine ID to the watchlist, and save the array to the preferences
219
+     *
220
+     * @param machineId
221
+     * @param endNotificationID
222
+     * @param reminderNotificationID
223
+     */
212 224
     saveNotificationToPrefs(machineId: string, endNotificationID: string, reminderNotificationID: string | null) {
213 225
         let data = this.state.machinesWatched;
214 226
         data.push({
@@ -219,13 +231,23 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
219 231
         this.updateNotificationPrefs(data);
220 232
     }
221 233
 
234
+    /**
235
+     * remove the given index from the watchlist array and save it to preferences
236
+     *
237
+     * @param index
238
+     */
222 239
     removeNotificationFromPrefs(index: number) {
223 240
         let data = this.state.machinesWatched;
224 241
         data.splice(index, 1);
225 242
         this.updateNotificationPrefs(data);
226 243
     }
227 244
 
228
-    updateNotificationPrefs(data: Object) {
245
+    /**
246
+     * Set the given data as the watchlist and save it to preferences
247
+     *
248
+     * @param data
249
+     */
250
+    updateNotificationPrefs(data: Array<Object>) {
229 251
         this.setState({machinesWatched: data});
230 252
         let prefKey = AsyncStorageManager.getInstance().preferences.proxiwashWatchedMachines.key;
231 253
         AsyncStorageManager.getInstance().savePref(prefKey, JSON.stringify(data));
@@ -266,6 +288,13 @@ export default class ProxiwashScreen extends FetchedDataSectionList {
266 288
         return true;
267 289
     }
268 290
 
291
+    /**
292
+     * Show an alert fo a machine, allowing to enable/disable notifications if running
293
+     *
294
+     * @param title
295
+     * @param item
296
+     * @param remainingTime
297
+     */
269 298
     showAlert(title: string, item: Object, remainingTime: number) {
270 299
         let buttons = [{text: i18n.t("proxiwashScreen.modal.ok")}];
271 300
         let message = modalStateStrings[MACHINE_STATES[item.state]];

+ 6
- 6
screens/SettingsScreen.js View File

@@ -2,18 +2,18 @@
2 2
 
3 3
 import * as React from 'react';
4 4
 import {
5
+    Body,
6
+    Card,
7
+    CardItem,
8
+    CheckBox,
5 9
     Container,
6 10
     Content,
7 11
     Left,
12
+    List,
8 13
     ListItem,
14
+    Picker,
9 15
     Right,
10 16
     Text,
11
-    List,
12
-    CheckBox,
13
-    Body,
14
-    CardItem,
15
-    Card,
16
-    Picker,
17 17
 } from "native-base";
18 18
 import CustomHeader from "../components/CustomHeader";
19 19
 import ThemeManager from '../utils/ThemeManager';

+ 27
- 12
utils/AsyncStorageManager.js View File

@@ -3,7 +3,9 @@
3 3
 import {AsyncStorage} from "react-native";
4 4
 
5 5
 /**
6
- * Static class used to manage preferences
6
+ * Static class used to manage preferences.
7
+ * Preferences are fetched at the start of the app and saved in an instance object.
8
+ * This allows for a synchronous access to saved data.
7 9
  */
8 10
 
9 11
 export default class AsyncStorageManager {
@@ -20,30 +22,36 @@ export default class AsyncStorageManager {
20 22
             AsyncStorageManager.instance;
21 23
     }
22 24
 
23
-
25
+    // Object storing preferences keys, default and current values for use in the app
24 26
     preferences = {
25 27
         showIntro: {
26 28
             key: 'showIntro',
27 29
             default: '1',
28
-            current : '',
30
+            current: '',
29 31
         },
30 32
         proxiwashNotifications: {
31 33
             key: 'proxiwashNotifications',
32 34
             default: '5',
33
-            current : '',
35
+            current: '',
34 36
         },
35
-        proxiwashWatchedMachines : {
37
+        proxiwashWatchedMachines: {
36 38
             key: 'proxiwashWatchedMachines',
37 39
             default: '[]',
38
-            current : '',
40
+            current: '',
39 41
         },
40 42
         nightMode: {
41 43
             key: 'nightMode',
42
-            default : '0',
43
-            current : '',
44
+            default: '0',
45
+            current: '',
44 46
         }
45 47
     };
46 48
 
49
+    /**
50
+     * Set preferences object current values from AsyncStorage.
51
+     * This function should be called at the app's start.
52
+     *
53
+     * @return {Promise<void>}
54
+     */
47 55
     async loadPreferences() {
48 56
         let prefKeys = [];
49 57
         // Get all available keys
@@ -51,18 +59,25 @@ export default class AsyncStorageManager {
51 59
             prefKeys.push(value.key);
52 60
         }
53 61
         // Get corresponding values
54
-        let resultArray : Array<Array<string>> = await AsyncStorage.multiGet(prefKeys);
62
+        let resultArray: Array<Array<string>> = await AsyncStorage.multiGet(prefKeys);
55 63
         // Save those values for later use
56 64
         for (let i = 0; i < resultArray.length; i++) {
57
-            let key : string = resultArray[i][0];
58
-            let val : string | null = resultArray[i][1];
65
+            let key: string = resultArray[i][0];
66
+            let val: string | null = resultArray[i][1];
59 67
             if (val === null)
60 68
                 val = this.preferences[key].default;
61 69
             this.preferences[key].current = val;
62 70
         }
63 71
     }
64 72
 
65
-    savePref(key : string, val : string) {
73
+    /**
74
+     * Save the value associated to the given key to preferences.
75
+     * This updates the preferences object and saves it to AsynStorage.
76
+     *
77
+     * @param key
78
+     * @param val
79
+     */
80
+    savePref(key: string, val: string) {
66 81
         this.preferences[key].current = val;
67 82
         AsyncStorage.setItem(key, val);
68 83
     }

+ 1
- 0
utils/ThemeManager.js View File

@@ -4,6 +4,7 @@ import platform from '../native-base-theme/variables/platform';
4 4
 import platformDark from '../native-base-theme/variables/platformDark';
5 5
 import getTheme from '../native-base-theme/components';
6 6
 import AsyncStorageManager from "./AsyncStorageManager";
7
+
7 8
 /**
8 9
  * Singleton class used to manage themes
9 10
  */

+ 24
- 4
utils/WebDataManager.js View File

@@ -1,17 +1,26 @@
1 1
 import {Toast} from "native-base";
2 2
 
3
+/**
4
+ * Class used to get json data from the web
5
+ */
3 6
 export default class WebDataManager {
4 7
 
5
-    FETCH_URL : string;
6
-    lastDataFetched : Object = {};
8
+    FETCH_URL: string;
9
+    lastDataFetched: Object = {};
7 10
 
8 11
 
9 12
     constructor(url) {
10 13
         this.FETCH_URL = url;
11 14
     }
12 15
 
16
+    /**
17
+     * Read data from FETCH_URL and return it.
18
+     * If no data was found, returns an empty object
19
+     *
20
+     * @return {Promise<Object>}
21
+     */
13 22
     async readData() {
14
-        let fetchedData : Object = {};
23
+        let fetchedData: Object = {};
15 24
         try {
16 25
             let response = await fetch(this.FETCH_URL);
17 26
             fetchedData = await response.json();
@@ -23,10 +32,21 @@ export default class WebDataManager {
23 32
         return fetchedData;
24 33
     }
25 34
 
26
-    isDataObjectValid() {
35
+    /**
36
+     * Detects if the fetched data is not an empty object
37
+     *
38
+     * @return
39
+     */
40
+    isDataObjectValid(): boolean {
27 41
         return Object.keys(this.lastDataFetched).length > 0;
28 42
     }
29 43
 
44
+    /**
45
+     * Show a toast message depending on the validity of the fetched data
46
+     *
47
+     * @param successString
48
+     * @param errorString
49
+     */
30 50
     showUpdateToast(successString, errorString) {
31 51
         let isSuccess = this.isDataObjectValid();
32 52
         if (!isSuccess) {

Loading…
Cancel
Save