Browse Source

Improve about components to match linter

Arnaud Vergnet 3 years ago
parent
commit
483970c9a8
3 changed files with 599 additions and 530 deletions
  1. 52
    50
      src/screens/About/AboutDependenciesScreen.js
  2. 352
    313
      src/screens/About/AboutScreen.js
  3. 195
    167
      src/screens/About/DebugScreen.js

+ 52
- 50
src/screens/About/AboutDependenciesScreen.js View File

@@ -1,36 +1,31 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import packageJson from '../../../package';
5 4
 import {List} from 'react-native-paper';
6
-import {StackNavigationProp} from "@react-navigation/stack";
7
-import CollapsibleFlatList from "../../components/Collapsible/CollapsibleFlatList";
8
-import {View} from "react-native-animatable";
5
+import {View} from 'react-native-animatable';
6
+import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
7
+import packageJson from '../../../package.json';
9 8
 
10
-type listItem = {
11
-    name: string,
12
-    version: string
9
+type ListItemType = {
10
+  name: string,
11
+  version: string,
13 12
 };
14 13
 
15 14
 /**
16 15
  * Generates the dependencies list from the raw json
17 16
  *
18 17
  * @param object The raw json
19
- * @return {Array<listItem>}
18
+ * @return {Array<ListItemType>}
20 19
  */
21
-function generateListFromObject(object: { [key: string]: string }): Array<listItem> {
22
-    let list = [];
23
-    let keys = Object.keys(object);
24
-    let values = Object.values(object);
25
-    for (let i = 0; i < keys.length; i++) {
26
-        list.push({name: keys[i], version: values[i]});
27
-    }
28
-    //$FlowFixMe
29
-    return list;
30
-}
31
-
32
-type Props = {
33
-    navigation: StackNavigationProp,
20
+function generateListFromObject(object: {
21
+  [key: string]: string,
22
+}): Array<ListItemType> {
23
+  const list = [];
24
+  const keys = Object.keys(object);
25
+  keys.forEach((key: string) => {
26
+    list.push({name: key, version: object[key]});
27
+  });
28
+  return list;
34 29
 }
35 30
 
36 31
 const LIST_ITEM_HEIGHT = 64;
@@ -38,38 +33,45 @@ const LIST_ITEM_HEIGHT = 64;
38 33
 /**
39 34
  * Class defining a screen showing the list of libraries used by the app, taken from package.json
40 35
  */
41
-export default class AboutDependenciesScreen extends React.Component<Props> {
42
-
43
-    data: Array<listItem>;
36
+export default class AboutDependenciesScreen extends React.Component<null> {
37
+  data: Array<ListItemType>;
44 38
 
45
-    constructor() {
46
-        super();
47
-        this.data = generateListFromObject(packageJson.dependencies);
48
-    }
39
+  constructor() {
40
+    super();
41
+    this.data = generateListFromObject(packageJson.dependencies);
42
+  }
49 43
 
50
-    keyExtractor = (item: listItem) => item.name;
44
+  keyExtractor = (item: ListItemType): string => item.name;
51 45
 
52
-    renderItem = ({item}: { item: listItem }) =>
53
-        <List.Item
54
-            title={item.name}
55
-            description={item.version.replace('^', '').replace('~', '')}
56
-            style={{height: LIST_ITEM_HEIGHT}}
57
-        />;
46
+  getRenderItem = ({item}: {item: ListItemType}): React.Node => (
47
+    <List.Item
48
+      title={item.name}
49
+      description={item.version.replace('^', '').replace('~', '')}
50
+      style={{height: LIST_ITEM_HEIGHT}}
51
+    />
52
+  );
58 53
 
59
-    itemLayout = (data: any, index: number) => ({length: LIST_ITEM_HEIGHT, offset: LIST_ITEM_HEIGHT * index, index});
54
+  getItemLayout = (
55
+    data: ListItemType,
56
+    index: number,
57
+  ): {length: number, offset: number, index: number} => ({
58
+    length: LIST_ITEM_HEIGHT,
59
+    offset: LIST_ITEM_HEIGHT * index,
60
+    index,
61
+  });
60 62
 
61
-    render() {
62
-        return (
63
-            <View>
64
-                <CollapsibleFlatList
65
-                    data={this.data}
66
-                    keyExtractor={this.keyExtractor}
67
-                    renderItem={this.renderItem}
68
-                    // Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
69
-                    removeClippedSubviews={true}
70
-                    getItemLayout={this.itemLayout}
71
-                />
72
-            </View>
73
-        );
74
-    }
63
+  render(): React.Node {
64
+    return (
65
+      <View>
66
+        <CollapsibleFlatList
67
+          data={this.data}
68
+          keyExtractor={this.keyExtractor}
69
+          renderItem={this.getRenderItem}
70
+          // Performance props, see https://reactnative.dev/docs/optimizing-flatlist-configuration
71
+          removeClippedSubviews
72
+          getItemLayout={this.getItemLayout}
73
+        />
74
+      </View>
75
+    );
76
+  }
75 77
 }

+ 352
- 313
src/screens/About/AboutScreen.js View File

@@ -1,351 +1,390 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {FlatList, Linking, Platform, View} from 'react-native';
5
-import i18n from "i18n-js";
4
+import {FlatList, Linking, Platform} from 'react-native';
5
+import i18n from 'i18n-js';
6 6
 import {Avatar, Card, List, Title, withTheme} from 'react-native-paper';
7
-import packageJson from "../../../package.json";
8
-import {StackNavigationProp} from "@react-navigation/stack";
9
-import CollapsibleFlatList from "../../components/Collapsible/CollapsibleFlatList";
7
+import {StackNavigationProp} from '@react-navigation/stack';
8
+import packageJson from '../../../package.json';
9
+import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
10
+import APP_LOGO from '../../../assets/android.icon.png';
10 11
 
11
-type ListItem = {
12
-    onPressCallback: () => void,
13
-    icon: string,
14
-    text: string,
15
-    showChevron: boolean
12
+type ListItemType = {
13
+  onPressCallback: () => void,
14
+  icon: string,
15
+  text: string,
16
+  showChevron: boolean,
16 17
 };
17 18
 
18 19
 const links = {
19
-    appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
20
-    playstore: 'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application',
21
-    git: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
22
-    changelog: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
23
-    license: 'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
24
-    authorMail: "mailto:vergnet@etud.insa-toulouse.fr?" +
25
-        "subject=" +
26
-        "Application Amicale INSA Toulouse" +
27
-        "&body=" +
28
-        "Coucou !\n\n",
29
-    authorLinkedin: 'https://www.linkedin.com/in/arnaud-vergnet-434ba5179/',
30
-    yohanMail: "mailto:ysimard@etud.insa-toulouse.fr?" +
31
-        "subject=" +
32
-        "Application Amicale INSA Toulouse" +
33
-        "&body=" +
34
-        "Coucou !\n\n",
35
-    yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard',
36
-    react: 'https://facebook.github.io/react-native/',
37
-    meme: "https://www.youtube.com/watch?v=dQw4w9WgXcQ"
20
+  appstore: 'https://apps.apple.com/us/app/campus-amicale-insat/id1477722148',
21
+  playstore:
22
+    'https://play.google.com/store/apps/details?id=fr.amicaleinsat.application',
23
+  git:
24
+    'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/README.md',
25
+  changelog:
26
+    'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/Changelog.md',
27
+  license:
28
+    'https://git.etud.insa-toulouse.fr/vergnet/application-amicale/src/branch/master/LICENSE',
29
+  authorMail:
30
+    'mailto:vergnet@etud.insa-toulouse.fr?' +
31
+    'subject=' +
32
+    'Application Amicale INSA Toulouse' +
33
+    '&body=' +
34
+    'Coucou !\n\n',
35
+  authorLinkedin: 'https://www.linkedin.com/in/arnaud-vergnet-434ba5179/',
36
+  yohanMail:
37
+    'mailto:ysimard@etud.insa-toulouse.fr?' +
38
+    'subject=' +
39
+    'Application Amicale INSA Toulouse' +
40
+    '&body=' +
41
+    'Coucou !\n\n',
42
+  yohanLinkedin: 'https://www.linkedin.com/in/yohan-simard',
43
+  react: 'https://facebook.github.io/react-native/',
44
+  meme: 'https://www.youtube.com/watch?v=dQw4w9WgXcQ',
38 45
 };
39 46
 
40
-type Props = {
41
-    navigation: StackNavigationProp,
47
+type PropsType = {
48
+  navigation: StackNavigationProp,
42 49
 };
43 50
 
44 51
 /**
45 52
  * Opens a link in the device's browser
46 53
  * @param link The link to open
47 54
  */
48
-function openWebLink(link) {
49
-    Linking.openURL(link).catch((err) => console.error('Error opening link', err));
55
+function openWebLink(link: string) {
56
+  Linking.openURL(link);
50 57
 }
51 58
 
52 59
 /**
53 60
  * Class defining an about screen. This screen shows the user information about the app and it's author.
54 61
  */
55
-class AboutScreen extends React.Component<Props> {
62
+class AboutScreen extends React.Component<PropsType> {
63
+  /**
64
+   * Data to be displayed in the app card
65
+   */
66
+  appData = [
67
+    {
68
+      onPressCallback: () => {
69
+        openWebLink(Platform.OS === 'ios' ? links.appstore : links.playstore);
70
+      },
71
+      icon: Platform.OS === 'ios' ? 'apple' : 'google-play',
72
+      text:
73
+        Platform.OS === 'ios'
74
+          ? i18n.t('screens.about.appstore')
75
+          : i18n.t('screens.about.playstore'),
76
+      showChevron: true,
77
+    },
78
+    {
79
+      onPressCallback: () => {
80
+        const {navigation} = this.props;
81
+        navigation.navigate('feedback');
82
+      },
83
+      icon: 'bug',
84
+      text: i18n.t('screens.feedback.homeButtonTitle'),
85
+      showChevron: true,
86
+    },
87
+    {
88
+      onPressCallback: () => {
89
+        openWebLink(links.git);
90
+      },
91
+      icon: 'git',
92
+      text: 'Git',
93
+      showChevron: true,
94
+    },
95
+    {
96
+      onPressCallback: () => {
97
+        openWebLink(links.changelog);
98
+      },
99
+      icon: 'refresh',
100
+      text: i18n.t('screens.about.changelog'),
101
+      showChevron: true,
102
+    },
103
+    {
104
+      onPressCallback: () => {
105
+        openWebLink(links.license);
106
+      },
107
+      icon: 'file-document',
108
+      text: i18n.t('screens.about.license'),
109
+      showChevron: true,
110
+    },
111
+  ];
56 112
 
57
-    /**
58
-     * Data to be displayed in the app card
59
-     */
60
-    appData = [
61
-        {
62
-            onPressCallback: () => openWebLink(Platform.OS === "ios" ? links.appstore : links.playstore),
63
-            icon: Platform.OS === "ios" ? 'apple' : 'google-play',
64
-            text: Platform.OS === "ios" ? i18n.t('screens.about.appstore') : i18n.t('screens.about.playstore'),
65
-            showChevron: true
66
-        },
67
-        {
68
-            onPressCallback: () => this.props.navigation.navigate("feedback"),
69
-            icon: 'bug',
70
-            text: i18n.t("screens.feedback.homeButtonTitle"),
71
-            showChevron: true
72
-        },
73
-        {
74
-            onPressCallback: () => openWebLink(links.git),
75
-            icon: 'git',
76
-            text: 'Git',
77
-            showChevron: true
78
-        },
79
-        {
80
-            onPressCallback: () => openWebLink(links.changelog),
81
-            icon: 'refresh',
82
-            text: i18n.t('screens.about.changelog'),
83
-            showChevron: true
84
-        },
85
-        {
86
-            onPressCallback: () => openWebLink(links.license),
87
-            icon: 'file-document',
88
-            text: i18n.t('screens.about.license'),
89
-            showChevron: true
90
-        },
91
-    ];
92
-    /**
93
-     * Data to be displayed in the author card
94
-     */
95
-    authorData = [
96
-        {
97
-            onPressCallback: () => openWebLink(links.meme),
98
-            icon: 'account-circle',
99
-            text: 'Arnaud VERGNET',
100
-            showChevron: false
101
-        },
102
-        {
103
-            onPressCallback: () => openWebLink(links.authorMail),
104
-            icon: 'email',
105
-            text: i18n.t('screens.about.authorMail'),
106
-            showChevron: true
107
-        },
108
-        {
109
-            onPressCallback: () => openWebLink(links.authorLinkedin),
110
-            icon: 'linkedin',
111
-            text: 'Linkedin',
112
-            showChevron: true
113
-        },
114
-    ];
115
-    /**
116
-     * Data to be displayed in the additional developer card
117
-     */
118
-    additionalDevData = [
119
-        {
120
-            onPressCallback: () => console.log('Meme this'),
121
-            icon: 'account',
122
-            text: 'Yohan SIMARD',
123
-            showChevron: false
124
-        },
125
-        {
126
-            onPressCallback: () => openWebLink(links.yohanMail),
127
-            icon: 'email',
128
-            text: i18n.t('screens.about.authorMail'),
129
-            showChevron: true
130
-        },
131
-        {
132
-            onPressCallback: () => openWebLink(links.yohanLinkedin),
133
-            icon: 'linkedin',
134
-            text: 'Linkedin',
135
-            showChevron: true
136
-        },
137
-    ];
138
-    /**
139
-     * Data to be displayed in the technologies card
140
-     */
141
-    technoData = [
142
-        {
143
-            onPressCallback: () => openWebLink(links.react),
144
-            icon: 'react',
145
-            text: i18n.t('screens.about.reactNative'),
146
-            showChevron: true
147
-        },
148
-        {
149
-            onPressCallback: () => this.props.navigation.navigate('dependencies'),
150
-            icon: 'developer-board',
151
-            text: i18n.t('screens.about.libs'),
152
-            showChevron: true
153
-        },
154
-    ];
155
-    /**
156
-     * Order of information cards
157
-     */
158
-    dataOrder = [
159
-        {
160
-            id: 'app',
161
-        },
162
-        {
163
-            id: 'team',
164
-        },
165
-        {
166
-            id: 'techno',
167
-        },
168
-    ];
113
+  /**
114
+   * Data to be displayed in the author card
115
+   */
116
+  authorData = [
117
+    {
118
+      onPressCallback: () => {
119
+        openWebLink(links.meme);
120
+      },
121
+      icon: 'account-circle',
122
+      text: 'Arnaud VERGNET',
123
+      showChevron: false,
124
+    },
125
+    {
126
+      onPressCallback: () => {
127
+        openWebLink(links.authorMail);
128
+      },
129
+      icon: 'email',
130
+      text: i18n.t('screens.about.authorMail'),
131
+      showChevron: true,
132
+    },
133
+    {
134
+      onPressCallback: () => {
135
+        openWebLink(links.authorLinkedin);
136
+      },
137
+      icon: 'linkedin',
138
+      text: 'Linkedin',
139
+      showChevron: true,
140
+    },
141
+  ];
169 142
 
170
-    /**
171
-     * Gets the app icon
172
-     *
173
-     * @param props
174
-     * @return {*}
175
-     */
176
-    getAppIcon(props) {
177
-        return (
143
+  /**
144
+   * Data to be displayed in the additional developer card
145
+   */
146
+  additionalDevData = [
147
+    {
148
+      onPressCallback: () => {
149
+        console.log('Meme this');
150
+      },
151
+      icon: 'account',
152
+      text: 'Yohan SIMARD',
153
+      showChevron: false,
154
+    },
155
+    {
156
+      onPressCallback: () => {
157
+        openWebLink(links.yohanMail);
158
+      },
159
+      icon: 'email',
160
+      text: i18n.t('screens.about.authorMail'),
161
+      showChevron: true,
162
+    },
163
+    {
164
+      onPressCallback: () => {
165
+        openWebLink(links.yohanLinkedin);
166
+      },
167
+      icon: 'linkedin',
168
+      text: 'Linkedin',
169
+      showChevron: true,
170
+    },
171
+  ];
172
+
173
+  /**
174
+   * Data to be displayed in the technologies card
175
+   */
176
+  technoData = [
177
+    {
178
+      onPressCallback: () => {
179
+        openWebLink(links.react);
180
+      },
181
+      icon: 'react',
182
+      text: i18n.t('screens.about.reactNative'),
183
+      showChevron: true,
184
+    },
185
+    {
186
+      onPressCallback: () => {
187
+        const {navigation} = this.props;
188
+        navigation.navigate('dependencies');
189
+      },
190
+      icon: 'developer-board',
191
+      text: i18n.t('screens.about.libs'),
192
+      showChevron: true,
193
+    },
194
+  ];
195
+
196
+  /**
197
+   * Order of information cards
198
+   */
199
+  dataOrder = [
200
+    {
201
+      id: 'app',
202
+    },
203
+    {
204
+      id: 'team',
205
+    },
206
+    {
207
+      id: 'techno',
208
+    },
209
+  ];
210
+
211
+  /**
212
+   * Gets the app card showing information and links about the app.
213
+   *
214
+   * @return {*}
215
+   */
216
+  getAppCard(): React.Node {
217
+    return (
218
+      <Card style={{marginBottom: 10}}>
219
+        <Card.Title
220
+          title="Campus"
221
+          subtitle={packageJson.version}
222
+          left={({size}: {size: number}): React.Node => (
178 223
             <Avatar.Image
179
-                {...props}
180
-                source={require('../../../assets/android.icon.png')}
181
-                style={{backgroundColor: 'transparent'}}
224
+              size={size}
225
+              source={APP_LOGO}
226
+              style={{backgroundColor: 'transparent'}}
182 227
             />
183
-        );
184
-    }
228
+          )}
229
+        />
230
+        <Card.Content>
231
+          <FlatList
232
+            data={this.appData}
233
+            keyExtractor={this.keyExtractor}
234
+            renderItem={this.getCardItem}
235
+          />
236
+        </Card.Content>
237
+      </Card>
238
+    );
239
+  }
185 240
 
186
-    /**
187
-     * Extracts a key from the given item
188
-     *
189
-     * @param item The item to extract the key from
190
-     * @return {string} The extracted key
191
-     */
192
-    keyExtractor(item: ListItem): string {
193
-        return item.icon;
194
-    }
241
+  /**
242
+   * Gets the team card showing information and links about the team
243
+   *
244
+   * @return {*}
245
+   */
246
+  getTeamCard(): React.Node {
247
+    return (
248
+      <Card style={{marginBottom: 10}}>
249
+        <Card.Title
250
+          title={i18n.t('screens.about.team')}
251
+          left={({size, color}: {size: number, color: string}): React.Node => (
252
+            <Avatar.Icon size={size} color={color} icon="account-multiple" />
253
+          )}
254
+        />
255
+        <Card.Content>
256
+          <Title>{i18n.t('screens.about.author')}</Title>
257
+          <FlatList
258
+            data={this.authorData}
259
+            keyExtractor={this.keyExtractor}
260
+            listKey="1"
261
+            renderItem={this.getCardItem}
262
+          />
263
+          <Title>{i18n.t('screens.about.additionalDev')}</Title>
264
+          <FlatList
265
+            data={this.additionalDevData}
266
+            keyExtractor={this.keyExtractor}
267
+            listKey="2"
268
+            renderItem={this.getCardItem}
269
+          />
270
+        </Card.Content>
271
+      </Card>
272
+    );
273
+  }
195 274
 
196
-    /**
197
-     * Gets the app card showing information and links about the app.
198
-     *
199
-     * @return {*}
200
-     */
201
-    getAppCard() {
202
-        return (
203
-            <Card style={{marginBottom: 10}}>
204
-                <Card.Title
205
-                    title={"Campus"}
206
-                    subtitle={packageJson.version}
207
-                    left={this.getAppIcon}/>
208
-                <Card.Content>
209
-                    <FlatList
210
-                        data={this.appData}
211
-                        keyExtractor={this.keyExtractor}
212
-                        renderItem={this.getCardItem}
213
-                    />
214
-                </Card.Content>
215
-            </Card>
216
-        );
217
-    }
275
+  /**
276
+   * Gets the techno card showing information and links about the technologies used in the app
277
+   *
278
+   * @return {*}
279
+   */
280
+  getTechnoCard(): React.Node {
281
+    return (
282
+      <Card style={{marginBottom: 10}}>
283
+        <Card.Content>
284
+          <Title>{i18n.t('screens.about.technologies')}</Title>
285
+          <FlatList
286
+            data={this.technoData}
287
+            keyExtractor={this.keyExtractor}
288
+            renderItem={this.getCardItem}
289
+          />
290
+        </Card.Content>
291
+      </Card>
292
+    );
293
+  }
218 294
 
219
-    /**
220
-     * Gets the team card showing information and links about the team
221
-     *
222
-     * @return {*}
223
-     */
224
-    getTeamCard() {
225
-        return (
226
-            <Card style={{marginBottom: 10}}>
227
-                <Card.Title
228
-                    title={i18n.t('screens.about.team')}
229
-                    left={(props) => <Avatar.Icon {...props} icon={'account-multiple'}/>}/>
230
-                <Card.Content>
231
-                    <Title>{i18n.t('screens.about.author')}</Title>
232
-                    <FlatList
233
-                        data={this.authorData}
234
-                        keyExtractor={this.keyExtractor}
235
-                        listKey={"1"}
236
-                        renderItem={this.getCardItem}
237
-                    />
238
-                    <Title>{i18n.t('screens.about.additionalDev')}</Title>
239
-                    <FlatList
240
-                        data={this.additionalDevData}
241
-                        keyExtractor={this.keyExtractor}
242
-                        listKey={"2"}
243
-                        renderItem={this.getCardItem}
244
-                    />
245
-                </Card.Content>
246
-            </Card>
247
-        );
248
-    }
295
+  /**
296
+   * Gets a chevron icon
297
+   *
298
+   * @param props
299
+   * @return {*}
300
+   */
301
+  static getChevronIcon({
302
+    size,
303
+    color,
304
+  }: {
305
+    size: number,
306
+    color: string,
307
+  }): React.Node {
308
+    return <List.Icon size={size} color={color} icon="chevron-right" />;
309
+  }
249 310
 
250
-    /**
251
-     * Gets the techno card showing information and links about the technologies used in the app
252
-     *
253
-     * @return {*}
254
-     */
255
-    getTechnoCard() {
256
-        return (
257
-            <Card style={{marginBottom: 10}}>
258
-                <Card.Content>
259
-                    <Title>{i18n.t('screens.about.technologies')}</Title>
260
-                    <FlatList
261
-                        data={this.technoData}
262
-                        keyExtractor={this.keyExtractor}
263
-                        renderItem={this.getCardItem}
264
-                    />
265
-                </Card.Content>
266
-            </Card>
267
-        );
268
-    }
311
+  /**
312
+   * Gets a custom list item icon
313
+   *
314
+   * @param item The item to show the icon for
315
+   * @param props
316
+   * @return {*}
317
+   */
318
+  static getItemIcon(
319
+    item: ListItemType,
320
+    {size, color}: {size: number, color: string},
321
+  ): React.Node {
322
+    return <List.Icon size={size} color={color} icon={item.icon} />;
323
+  }
269 324
 
270
-    /**
271
-     * Gets a chevron icon
272
-     *
273
-     * @param props
274
-     * @return {*}
275
-     */
276
-    getChevronIcon(props) {
277
-        return (
278
-            <List.Icon {...props} icon={'chevron-right'}/>
279
-        );
325
+  /**
326
+   * Gets a clickable card item to be rendered inside a card.
327
+   *
328
+   * @returns {*}
329
+   */
330
+  getCardItem = ({item}: {item: ListItemType}): React.Node => {
331
+    const getItemIcon = (props: {size: number, color: string}): React.Node =>
332
+      AboutScreen.getItemIcon(item, props);
333
+    if (item.showChevron) {
334
+      return (
335
+        <List.Item
336
+          title={item.text}
337
+          left={getItemIcon}
338
+          right={AboutScreen.getChevronIcon}
339
+          onPress={item.onPressCallback}
340
+        />
341
+      );
280 342
     }
343
+    return (
344
+      <List.Item
345
+        title={item.text}
346
+        left={getItemIcon}
347
+        onPress={item.onPressCallback}
348
+      />
349
+    );
350
+  };
281 351
 
282
-    /**
283
-     * Gets a custom list item icon
284
-     *
285
-     * @param item The item to show the icon for
286
-     * @param props
287
-     * @return {*}
288
-     */
289
-    getItemIcon(item: ListItem, props) {
290
-        return (
291
-            <List.Icon {...props} icon={item.icon}/>
292
-        );
352
+  /**
353
+   * Gets a card, depending on the given item's id
354
+   *
355
+   * @param item The item to show
356
+   * @return {*}
357
+   */
358
+  getMainCard = ({item}: {item: {id: string}}): React.Node => {
359
+    switch (item.id) {
360
+      case 'app':
361
+        return this.getAppCard();
362
+      case 'team':
363
+        return this.getTeamCard();
364
+      case 'techno':
365
+        return this.getTechnoCard();
366
+      default:
367
+        return null;
293 368
     }
369
+  };
294 370
 
295
-    /**
296
-     * Gets a clickable card item to be rendered inside a card.
297
-     *
298
-     * @returns {*}
299
-     */
300
-    getCardItem = ({item}: { item: ListItem }) => {
301
-        const getItemIcon = this.getItemIcon.bind(this, item);
302
-        if (item.showChevron) {
303
-            return (
304
-                <List.Item
305
-                    title={item.text}
306
-                    left={getItemIcon}
307
-                    right={this.getChevronIcon}
308
-                    onPress={item.onPressCallback}
309
-                />
310
-            );
311
-        } else {
312
-            return (
313
-                <List.Item
314
-                    title={item.text}
315
-                    left={getItemIcon}
316
-                    onPress={item.onPressCallback}
317
-                />
318
-            );
319
-        }
320
-    };
321
-
322
-    /**
323
-     * Gets a card, depending on the given item's id
324
-     *
325
-     * @param item The item to show
326
-     * @return {*}
327
-     */
328
-    getMainCard = ({item}: { item: { id: string } }) => {
329
-        switch (item.id) {
330
-            case 'app':
331
-                return this.getAppCard();
332
-            case 'team':
333
-                return this.getTeamCard();
334
-            case 'techno':
335
-                return this.getTechnoCard();
336
-        }
337
-        return <View/>;
338
-    };
371
+  /**
372
+   * Extracts a key from the given item
373
+   *
374
+   * @param item The item to extract the key from
375
+   * @return {string} The extracted key
376
+   */
377
+  keyExtractor = (item: ListItemType): string => item.icon;
339 378
 
340
-    render() {
341
-        return (
342
-            <CollapsibleFlatList
343
-                style={{padding: 5}}
344
-                data={this.dataOrder}
345
-                renderItem={this.getMainCard}
346
-            />
347
-        );
348
-    }
379
+  render(): React.Node {
380
+    return (
381
+      <CollapsibleFlatList
382
+        style={{padding: 5}}
383
+        data={this.dataOrder}
384
+        renderItem={this.getMainCard}
385
+      />
386
+    );
387
+  }
349 388
 }
350 389
 
351 390
 export default withTheme(AboutScreen);

+ 195
- 167
src/screens/About/DebugScreen.js View File

@@ -1,183 +1,211 @@
1 1
 // @flow
2 2
 
3 3
 import * as React from 'react';
4
-import {View} from "react-native";
5
-import AsyncStorageManager from "../../managers/AsyncStorageManager";
6
-import CustomModal from "../../components/Overrides/CustomModal";
7
-import {Button, List, Subheading, TextInput, Title, withTheme} from 'react-native-paper';
8
-import {StackNavigationProp} from "@react-navigation/stack";
9
-import {Modalize} from "react-native-modalize";
10
-import type {CustomTheme} from "../../managers/ThemeManager";
11
-import CollapsibleFlatList from "../../components/Collapsible/CollapsibleFlatList";
12
-
13
-type PreferenceItem = {
14
-    key: string,
15
-    default: string,
16
-    current: string,
17
-}
4
+import {View} from 'react-native';
5
+import {
6
+  Button,
7
+  List,
8
+  Subheading,
9
+  TextInput,
10
+  Title,
11
+  withTheme,
12
+} from 'react-native-paper';
13
+import {Modalize} from 'react-native-modalize';
14
+import CustomModal from '../../components/Overrides/CustomModal';
15
+import AsyncStorageManager from '../../managers/AsyncStorageManager';
16
+import type {CustomThemeType} from '../../managers/ThemeManager';
17
+import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
18
+
19
+type PreferenceItemType = {
20
+  key: string,
21
+  default: string,
22
+  current: string,
23
+};
18 24
 
19
-type Props = {
20
-    navigation: StackNavigationProp,
21
-    theme: CustomTheme
25
+type PropsType = {
26
+  theme: CustomThemeType,
22 27
 };
23 28
 
24
-type State = {
25
-    modalCurrentDisplayItem: PreferenceItem,
26
-    currentPreferences: Array<PreferenceItem>,
27
-}
29
+type StateType = {
30
+  modalCurrentDisplayItem: PreferenceItemType,
31
+  currentPreferences: Array<PreferenceItemType>,
32
+};
28 33
 
29 34
 /**
30 35
  * Class defining the Debug screen.
31 36
  * This screen allows the user to get and modify information on the app/device.
32 37
  */
33
-class DebugScreen extends React.Component<Props, State> {
34
-
35
-    modalRef: Modalize;
36
-    modalInputValue: string;
37
-
38
-    /**
39
-     * Copies user preferences to state for easier manipulation
40
-     *
41
-     * @param props
42
-     */
43
-    constructor(props) {
44
-        super(props);
45
-        this.modalInputValue = "";
46
-        let currentPreferences : Array<PreferenceItem> = [];
47
-        Object.values(AsyncStorageManager.PREFERENCES).map((object: any) => {
48
-            let newObject: PreferenceItem = {...object};
49
-            newObject.current = AsyncStorageManager.getString(newObject.key);
50
-            currentPreferences.push(newObject);
51
-        });
52
-        this.state = {
53
-            modalCurrentDisplayItem: {},
54
-            currentPreferences: currentPreferences
55
-        };
56
-    }
57
-
58
-    /**
59
-     * Shows the edit modal
60
-     *
61
-     * @param item
62
-     */
63
-    showEditModal(item: PreferenceItem) {
64
-        this.setState({
65
-            modalCurrentDisplayItem: item
66
-        });
67
-        if (this.modalRef) {
68
-            this.modalRef.open();
69
-        }
70
-    }
71
-
72
-    /**
73
-     * Gets the edit modal content
74
-     *
75
-     * @return {*}
76
-     */
77
-    getModalContent() {
78
-        return (
79
-            <View style={{
80
-                flex: 1,
81
-                padding: 20
82
-            }}>
83
-                <Title>{this.state.modalCurrentDisplayItem.key}</Title>
84
-                <Subheading>Default: {this.state.modalCurrentDisplayItem.default}</Subheading>
85
-                <Subheading>Current: {this.state.modalCurrentDisplayItem.current}</Subheading>
86
-                <TextInput
87
-                    label='New Value'
88
-                    onChangeText={(text) => this.modalInputValue = text}
89
-                />
90
-                <View style={{
91
-                    flexDirection: 'row',
92
-                    marginTop: 10,
93
-                }}>
94
-                    <Button
95
-                        mode="contained"
96
-                        dark={true}
97
-                        color={this.props.theme.colors.success}
98
-                        onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.modalInputValue)}>
99
-                        Save new value
100
-                    </Button>
101
-                    <Button
102
-                        mode="contained"
103
-                        dark={true}
104
-                        color={this.props.theme.colors.danger}
105
-                        onPress={() => this.saveNewPrefs(this.state.modalCurrentDisplayItem.key, this.state.modalCurrentDisplayItem.default)}>
106
-                        Reset to default
107
-                    </Button>
108
-                </View>
109
-
110
-            </View>
111
-        );
112
-    }
113
-
114
-    /**
115
-     * Finds the index of the given key in the preferences array
116
-     *
117
-     * @param key THe key to find the index of
118
-     * @returns {number}
119
-     */
120
-    findIndexOfKey(key: string) {
121
-        let index = -1;
122
-        for (let i = 0; i < this.state.currentPreferences.length; i++) {
123
-            if (this.state.currentPreferences[i].key === key) {
124
-                index = i;
125
-                break;
126
-            }
127
-        }
128
-        return index;
129
-    }
130
-
131
-    /**
132
-     * Saves the new value of the given preference
133
-     *
134
-     * @param key The pref key
135
-     * @param value The pref value
136
-     */
137
-    saveNewPrefs(key: string, value: string) {
138
-        this.setState((prevState) => {
139
-            let currentPreferences = [...prevState.currentPreferences];
140
-            currentPreferences[this.findIndexOfKey(key)].current = value;
141
-            return {currentPreferences};
142
-        });
143
-        AsyncStorageManager.set(key, value);
144
-        this.modalRef.close();
145
-    }
146
-
147
-    /**
148
-     * Callback used when receiving the modal ref
149
-     *
150
-     * @param ref
151
-     */
152
-    onModalRef = (ref: Modalize) => {
153
-        this.modalRef = ref;
154
-    }
155
-
156
-    renderItem = ({item}: {item: PreferenceItem}) => {
157
-        return (
158
-            <List.Item
159
-                title={item.key}
160
-                description={'Click to edit'}
161
-                onPress={() => this.showEditModal(item)}
162
-            />
163
-        );
38
+class DebugScreen extends React.Component<PropsType, StateType> {
39
+  modalRef: Modalize;
40
+
41
+  modalInputValue: string;
42
+
43
+  /**
44
+   * Copies user preferences to state for easier manipulation
45
+   *
46
+   * @param props
47
+   */
48
+  constructor(props: PropsType) {
49
+    super(props);
50
+    this.modalInputValue = '';
51
+    const currentPreferences: Array<PreferenceItemType> = [];
52
+    // eslint-disable-next-line flowtype/no-weak-types
53
+    Object.values(AsyncStorageManager.PREFERENCES).forEach((object: any) => {
54
+      const newObject: PreferenceItemType = {...object};
55
+      newObject.current = AsyncStorageManager.getString(newObject.key);
56
+      currentPreferences.push(newObject);
57
+    });
58
+    this.state = {
59
+      modalCurrentDisplayItem: {},
60
+      currentPreferences,
164 61
     };
165
-
166
-    render() {
167
-        return (
168
-            <View>
169
-                <CustomModal onRef={this.onModalRef}>
170
-                    {this.getModalContent()}
171
-                </CustomModal>
172
-                {/*$FlowFixMe*/}
173
-                <CollapsibleFlatList
174
-                    data={this.state.currentPreferences}
175
-                    extraData={this.state.currentPreferences}
176
-                    renderItem={this.renderItem}
177
-                />
178
-            </View>
179
-        );
62
+  }
63
+
64
+  /**
65
+   * Gets the edit modal content
66
+   *
67
+   * @return {*}
68
+   */
69
+  getModalContent(): React.Node {
70
+    const {props, state} = this;
71
+    return (
72
+      <View
73
+        style={{
74
+          flex: 1,
75
+          padding: 20,
76
+        }}>
77
+        <Title>{state.modalCurrentDisplayItem.key}</Title>
78
+        <Subheading>
79
+          Default: {state.modalCurrentDisplayItem.default}
80
+        </Subheading>
81
+        <Subheading>
82
+          Current: {state.modalCurrentDisplayItem.current}
83
+        </Subheading>
84
+        <TextInput
85
+          label="New Value"
86
+          onChangeText={(text: string) => {
87
+            this.modalInputValue = text;
88
+          }}
89
+        />
90
+        <View
91
+          style={{
92
+            flexDirection: 'row',
93
+            marginTop: 10,
94
+          }}>
95
+          <Button
96
+            mode="contained"
97
+            dark
98
+            color={props.theme.colors.success}
99
+            onPress={() => {
100
+              this.saveNewPrefs(
101
+                state.modalCurrentDisplayItem.key,
102
+                this.modalInputValue,
103
+              );
104
+            }}>
105
+            Save new value
106
+          </Button>
107
+          <Button
108
+            mode="contained"
109
+            dark
110
+            color={props.theme.colors.danger}
111
+            onPress={() => {
112
+              this.saveNewPrefs(
113
+                state.modalCurrentDisplayItem.key,
114
+                state.modalCurrentDisplayItem.default,
115
+              );
116
+            }}>
117
+            Reset to default
118
+          </Button>
119
+        </View>
120
+      </View>
121
+    );
122
+  }
123
+
124
+  getRenderItem = ({item}: {item: PreferenceItemType}): React.Node => {
125
+    return (
126
+      <List.Item
127
+        title={item.key}
128
+        description="Click to edit"
129
+        onPress={() => {
130
+          this.showEditModal(item);
131
+        }}
132
+      />
133
+    );
134
+  };
135
+
136
+  /**
137
+   * Callback used when receiving the modal ref
138
+   *
139
+   * @param ref
140
+   */
141
+  onModalRef = (ref: Modalize) => {
142
+    this.modalRef = ref;
143
+  };
144
+
145
+  /**
146
+   * Shows the edit modal
147
+   *
148
+   * @param item
149
+   */
150
+  showEditModal(item: PreferenceItemType) {
151
+    this.setState({
152
+      modalCurrentDisplayItem: item,
153
+    });
154
+    if (this.modalRef) this.modalRef.open();
155
+  }
156
+
157
+  /**
158
+   * Finds the index of the given key in the preferences array
159
+   *
160
+   * @param key THe key to find the index of
161
+   * @returns {number}
162
+   */
163
+  findIndexOfKey(key: string): number {
164
+    const {currentPreferences} = this.state;
165
+    let index = -1;
166
+    for (let i = 0; i < currentPreferences.length; i += 1) {
167
+      if (currentPreferences[i].key === key) {
168
+        index = i;
169
+        break;
170
+      }
180 171
     }
172
+    return index;
173
+  }
174
+
175
+  /**
176
+   * Saves the new value of the given preference
177
+   *
178
+   * @param key The pref key
179
+   * @param value The pref value
180
+   */
181
+  saveNewPrefs(key: string, value: string) {
182
+    this.setState((prevState: StateType): {
183
+      currentPreferences: Array<PreferenceItemType>,
184
+    } => {
185
+      const currentPreferences = [...prevState.currentPreferences];
186
+      currentPreferences[this.findIndexOfKey(key)].current = value;
187
+      return {currentPreferences};
188
+    });
189
+    AsyncStorageManager.set(key, value);
190
+    this.modalRef.close();
191
+  }
192
+
193
+  render(): React.Node {
194
+    const {state} = this;
195
+    return (
196
+      <View>
197
+        <CustomModal onRef={this.onModalRef}>
198
+          {this.getModalContent()}
199
+        </CustomModal>
200
+        {/* $FlowFixMe */}
201
+        <CollapsibleFlatList
202
+          data={state.currentPreferences}
203
+          extraData={state.currentPreferences}
204
+          renderItem={this.getRenderItem}
205
+        />
206
+      </View>
207
+    );
208
+  }
181 209
 }
182 210
 
183 211
 export default withTheme(DebugScreen);

Loading…
Cancel
Save