Browse Source

Improve planex group favorite handling

Arnaud Vergnet 3 years ago
parent
commit
327488a470

+ 2
- 2
android/app/build.gradle View File

136
         applicationId 'fr.amicaleinsat.application'
136
         applicationId 'fr.amicaleinsat.application'
137
         minSdkVersion rootProject.ext.minSdkVersion
137
         minSdkVersion rootProject.ext.minSdkVersion
138
         targetSdkVersion rootProject.ext.targetSdkVersion
138
         targetSdkVersion rootProject.ext.targetSdkVersion
139
-        versionCode 32
140
-        versionName "3.1.4"
139
+        versionCode 34
140
+        versionName "4.0.1"
141
         missingDimensionStrategy 'react-native-camera', 'general'
141
         missingDimensionStrategy 'react-native-camera', 'general'
142
     }
142
     }
143
     splits {
143
     splits {

+ 8
- 6
src/components/Lists/PlanexGroups/GroupListAccordion.js View File

14
 
14
 
15
 type PropsType = {
15
 type PropsType = {
16
   item: PlanexGroupCategoryType,
16
   item: PlanexGroupCategoryType,
17
+  favorites: Array<PlanexGroupType>,
17
   onGroupPress: (PlanexGroupType) => void,
18
   onGroupPress: (PlanexGroupType) => void,
18
   onFavoritePress: (PlanexGroupType) => void,
19
   onFavoritePress: (PlanexGroupType) => void,
19
   currentSearchString: string,
20
   currentSearchString: string,
20
-  favoriteNumber: number,
21
   height: number,
21
   height: number,
22
   theme: CustomThemeType,
22
   theme: CustomThemeType,
23
 };
23
 };
24
 
24
 
25
 const LIST_ITEM_HEIGHT = 64;
25
 const LIST_ITEM_HEIGHT = 64;
26
+const REPLACE_REGEX = /_/g;
26
 
27
 
27
 class GroupListAccordion extends React.Component<PropsType> {
28
 class GroupListAccordion extends React.Component<PropsType> {
28
   shouldComponentUpdate(nextProps: PropsType): boolean {
29
   shouldComponentUpdate(nextProps: PropsType): boolean {
29
     const {props} = this;
30
     const {props} = this;
30
     return (
31
     return (
31
       nextProps.currentSearchString !== props.currentSearchString ||
32
       nextProps.currentSearchString !== props.currentSearchString ||
32
-      nextProps.favoriteNumber !== props.favoriteNumber ||
33
+      nextProps.favorites.length !== props.favorites.length ||
33
       nextProps.item.content.length !== props.item.content.length
34
       nextProps.item.content.length !== props.item.content.length
34
     );
35
     );
35
   }
36
   }
46
       <GroupListItem
47
       <GroupListItem
47
         height={LIST_ITEM_HEIGHT}
48
         height={LIST_ITEM_HEIGHT}
48
         item={item}
49
         item={item}
50
+        favorites={props.favorites}
49
         onPress={onPress}
51
         onPress={onPress}
50
         onStarPress={onStarPress}
52
         onStarPress={onStarPress}
51
       />
53
       />
80
     return (
82
     return (
81
       <View>
83
       <View>
82
         <AnimatedAccordion
84
         <AnimatedAccordion
83
-          title={item.name}
85
+          title={item.name.replace(REPLACE_REGEX, ' ')}
84
           style={{
86
           style={{
85
             height: props.height,
87
             height: props.height,
86
             justifyContent: 'center',
88
             justifyContent: 'center',
94
               />
96
               />
95
             ) : null
97
             ) : null
96
           }
98
           }
97
-          unmountWhenCollapsed // Only render list if expanded for increased performance
98
-          opened={props.item.id === 0 || props.currentSearchString.length > 0}>
99
+          unmountWhenCollapsed={item.id !== 0} // Only render list if expanded for increased performance
100
+          opened={props.currentSearchString.length > 0}>
99
           <FlatList
101
           <FlatList
100
             data={this.getData()}
102
             data={this.getData()}
101
-            extraData={props.currentSearchString}
103
+            extraData={props.currentSearchString + props.favorites.length}
102
             renderItem={this.getRenderItem}
104
             renderItem={this.getRenderItem}
103
             keyExtractor={this.keyExtractor}
105
             keyExtractor={this.keyExtractor}
104
             listKey={item.id.toString()}
106
             listKey={item.id.toString()}

+ 25
- 21
src/components/Lists/PlanexGroups/GroupListItem.js View File

10
   onPress: () => void,
10
   onPress: () => void,
11
   onStarPress: () => void,
11
   onStarPress: () => void,
12
   item: PlanexGroupType,
12
   item: PlanexGroupType,
13
+  favorites: Array<PlanexGroupType>,
13
   height: number,
14
   height: number,
14
 };
15
 };
15
 
16
 
16
-type StateType = {
17
-  isFav: boolean,
18
-};
17
+const REPLACE_REGEX = /_/g;
18
+
19
+class GroupListItem extends React.Component<PropsType> {
20
+  isFav: boolean;
19
 
21
 
20
-class GroupListItem extends React.Component<PropsType, StateType> {
21
   constructor(props: PropsType) {
22
   constructor(props: PropsType) {
22
     super(props);
23
     super(props);
23
-    this.state = {
24
-      isFav: props.item.isFav !== undefined && props.item.isFav,
25
-    };
24
+    this.isFav = this.isGroupInFavorites(props.favorites);
26
   }
25
   }
27
 
26
 
28
-  shouldComponentUpdate(prevProps: PropsType, prevState: StateType): boolean {
29
-    const {isFav} = this.state;
30
-    return prevState.isFav !== isFav;
27
+  shouldComponentUpdate(nextProps: PropsType): boolean {
28
+    const {favorites} = this.props;
29
+    const favChanged = favorites.length !== nextProps.favorites.length;
30
+    let newFavState = this.isFav;
31
+    if (favChanged) newFavState = this.isGroupInFavorites(nextProps.favorites);
32
+    const shouldUpdate = this.isFav !== newFavState;
33
+    this.isFav = newFavState;
34
+    return shouldUpdate;
31
   }
35
   }
32
 
36
 
33
-  onStarPress = () => {
34
-    const {props} = this;
35
-    this.setState((prevState: StateType): StateType => ({
36
-      isFav: !prevState.isFav,
37
-    }));
38
-    props.onStarPress();
39
-  };
37
+  isGroupInFavorites(favorites: Array<PlanexGroupType>): boolean {
38
+    const {item} = this.props;
39
+    for (let i = 0; i < favorites.length; i += 1) {
40
+      if (favorites[i].id === item.id) return true;
41
+    }
42
+    return false;
43
+  }
40
 
44
 
41
   render(): React.Node {
45
   render(): React.Node {
42
-    const {props, state} = this;
46
+    const {props} = this;
43
     const {colors} = props.theme;
47
     const {colors} = props.theme;
44
     return (
48
     return (
45
       <List.Item
49
       <List.Item
46
-        title={props.item.name}
50
+        title={props.item.name.replace(REPLACE_REGEX, ' ')}
47
         onPress={props.onPress}
51
         onPress={props.onPress}
48
         left={({size}: {size: number}): React.Node => (
52
         left={({size}: {size: number}): React.Node => (
49
           <List.Icon size={size} icon="chevron-right" />
53
           <List.Icon size={size} icon="chevron-right" />
52
           <IconButton
56
           <IconButton
53
             size={size}
57
             size={size}
54
             icon="star"
58
             icon="star"
55
-            onPress={this.onStarPress}
56
-            color={state.isFav ? colors.tetrisScore : color}
59
+            onPress={props.onStarPress}
60
+            color={this.isFav ? colors.tetrisScore : color}
57
           />
61
           />
58
         )}
62
         )}
59
         style={{
63
         style={{

+ 52
- 66
src/screens/Planex/GroupSelectionScreen.js View File

15
 export type PlanexGroupType = {
15
 export type PlanexGroupType = {
16
   name: string,
16
   name: string,
17
   id: number,
17
   id: number,
18
-  isFav: boolean,
19
 };
18
 };
20
 
19
 
21
 export type PlanexGroupCategoryType = {
20
 export type PlanexGroupCategoryType = {
43
 }
42
 }
44
 
43
 
45
 const GROUPS_URL = 'http://planex.insa-toulouse.fr/wsAdeGrp.php?projectId=1';
44
 const GROUPS_URL = 'http://planex.insa-toulouse.fr/wsAdeGrp.php?projectId=1';
46
-const REPLACE_REGEX = /_/g;
47
 
45
 
48
 /**
46
 /**
49
  * Class defining planex group selection screen.
47
  * Class defining planex group selection screen.
50
  */
48
  */
51
 class GroupSelectionScreen extends React.Component<PropsType, StateType> {
49
 class GroupSelectionScreen extends React.Component<PropsType, StateType> {
52
-  /**
53
-   * Removes the given group from the given array
54
-   *
55
-   * @param favorites The array containing favorites groups
56
-   * @param group The group to remove from the array
57
-   */
58
-  static removeGroupFromFavorites(
59
-    favorites: Array<PlanexGroupType>,
60
-    group: PlanexGroupType,
61
-  ) {
62
-    for (let i = 0; i < favorites.length; i += 1) {
63
-      if (group.id === favorites[i].id) {
64
-        favorites.splice(i, 1);
65
-        break;
66
-      }
67
-    }
68
-  }
69
-
70
-  /**
71
-   * Adds the given group to the given array
72
-   *
73
-   * @param favorites The array containing favorites groups
74
-   * @param group The group to add to the array
75
-   */
76
-  static addGroupToFavorites(
77
-    favorites: Array<PlanexGroupType>,
78
-    group: PlanexGroupType,
79
-  ) {
80
-    const favGroup = {...group};
81
-    favGroup.isFav = true;
82
-    favorites.push(favGroup);
83
-    favorites.sort(sortName);
84
-  }
85
-
86
   constructor(props: PropsType) {
50
   constructor(props: PropsType) {
87
     super(props);
51
     super(props);
88
     this.state = {
52
     this.state = {
130
    */
94
    */
131
   getRenderItem = ({item}: {item: PlanexGroupCategoryType}): React.Node => {
95
   getRenderItem = ({item}: {item: PlanexGroupCategoryType}): React.Node => {
132
     const {currentSearchString, favoriteGroups} = this.state;
96
     const {currentSearchString, favoriteGroups} = this.state;
133
-    if (this.shouldDisplayAccordion(item)) {
97
+    if (
98
+      this.shouldDisplayAccordion(item) ||
99
+      (item.id === 0 && item.content.length === 0)
100
+    ) {
134
       return (
101
       return (
135
         <GroupListAccordion
102
         <GroupListAccordion
136
           item={item}
103
           item={item}
104
+          favorites={[...favoriteGroups]}
137
           onGroupPress={this.onListItemPress}
105
           onGroupPress={this.onListItemPress}
138
           onFavoritePress={this.onListFavoritePress}
106
           onFavoritePress={this.onListFavoritePress}
139
           currentSearchString={currentSearchString}
107
           currentSearchString={currentSearchString}
140
-          favoriteNumber={favoriteGroups.length}
141
           height={LIST_ITEM_HEIGHT}
108
           height={LIST_ITEM_HEIGHT}
142
         />
109
         />
143
       );
110
       );
146
   };
113
   };
147
 
114
 
148
   /**
115
   /**
149
-   * Replaces underscore by spaces and sets the favorite state of every group in the given category
150
-   *
151
-   * @param groups The groups to format
152
-   * @return {Array<PlanexGroupType>}
153
-   */
154
-  getFormattedGroups(groups: Array<PlanexGroupType>): Array<PlanexGroupType> {
155
-    return groups.map((group: PlanexGroupType): PlanexGroupType => {
156
-      const newGroup = {...group};
157
-      newGroup.name = group.name.replace(REPLACE_REGEX, ' ');
158
-      newGroup.isFav = this.isGroupInFavorites(group);
159
-      return newGroup;
160
-    });
161
-  }
162
-
163
-  /**
164
    * Creates the dataset to be used in the FlatList
116
    * Creates the dataset to be used in the FlatList
165
    *
117
    *
166
    * @param fetchedData
118
    * @param fetchedData
231
    * @param group The group to add/remove to favorites
183
    * @param group The group to add/remove to favorites
232
    */
184
    */
233
   updateGroupFavorites(group: PlanexGroupType) {
185
   updateGroupFavorites(group: PlanexGroupType) {
234
-    const {favoriteGroups} = this.state;
235
-    const newFavorites = [...favoriteGroups];
236
-    if (this.isGroupInFavorites(group))
237
-      GroupSelectionScreen.removeGroupFromFavorites(newFavorites, group);
238
-    else GroupSelectionScreen.addGroupToFavorites(newFavorites, group);
239
-    this.setState({favoriteGroups: newFavorites});
240
-    AsyncStorageManager.set(
241
-      AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
242
-      newFavorites,
243
-    );
186
+    if (this.isGroupInFavorites(group)) this.removeGroupFromFavorites(group);
187
+    else this.addGroupToFavorites(group);
244
   }
188
   }
245
 
189
 
246
   /**
190
   /**
276
     // eslint-disable-next-line flowtype/no-weak-types
220
     // eslint-disable-next-line flowtype/no-weak-types
277
     (Object.values(fetchedData): Array<any>).forEach(
221
     (Object.values(fetchedData): Array<any>).forEach(
278
       (category: PlanexGroupCategoryType) => {
222
       (category: PlanexGroupCategoryType) => {
279
-        const newCat = {...category};
280
-        newCat.content = this.getFormattedGroups(category.content);
281
-        data.push(newCat);
223
+        data.push(category);
282
       },
224
       },
283
     );
225
     );
284
     data.sort(sortName);
226
     data.sort(sortName);
290
     return data;
232
     return data;
291
   }
233
   }
292
 
234
 
235
+  /**
236
+   * Removes the given group from the favorites
237
+   *
238
+   * @param group The group to remove from the array
239
+   */
240
+  removeGroupFromFavorites(group: PlanexGroupType) {
241
+    this.setState((prevState: StateType): {
242
+      favoriteGroups: Array<PlanexGroupType>,
243
+    } => {
244
+      const {favoriteGroups} = prevState;
245
+      for (let i = 0; i < favoriteGroups.length; i += 1) {
246
+        if (group.id === favoriteGroups[i].id) {
247
+          favoriteGroups.splice(i, 1);
248
+          break;
249
+        }
250
+      }
251
+      AsyncStorageManager.set(
252
+        AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
253
+        favoriteGroups,
254
+      );
255
+      return {favoriteGroups};
256
+    });
257
+  }
258
+
259
+  /**
260
+   * Adds the given group to favorites
261
+   *
262
+   * @param group The group to add to the array
263
+   */
264
+  addGroupToFavorites(group: PlanexGroupType) {
265
+    this.setState((prevState: StateType): {
266
+      favoriteGroups: Array<PlanexGroupType>,
267
+    } => {
268
+      const {favoriteGroups} = prevState;
269
+      favoriteGroups.push(group);
270
+      favoriteGroups.sort(sortName);
271
+      AsyncStorageManager.set(
272
+        AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
273
+        favoriteGroups,
274
+      );
275
+      return {favoriteGroups};
276
+    });
277
+  }
278
+
293
   render(): React.Node {
279
   render(): React.Node {
294
     const {props, state} = this;
280
     const {props, state} = this;
295
     return (
281
     return (

Loading…
Cancel
Save