Improve planex group favorite handling

This commit is contained in:
Arnaud Vergnet 2020-08-06 17:34:53 +02:00
parent eef6f75414
commit 327488a470
4 changed files with 87 additions and 95 deletions

View file

@ -136,8 +136,8 @@ android {
applicationId 'fr.amicaleinsat.application'
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 32
versionName "3.1.4"
versionCode 34
versionName "4.0.1"
missingDimensionStrategy 'react-native-camera', 'general'
}
splits {

View file

@ -14,22 +14,23 @@ import type {CustomThemeType} from '../../../managers/ThemeManager';
type PropsType = {
item: PlanexGroupCategoryType,
favorites: Array<PlanexGroupType>,
onGroupPress: (PlanexGroupType) => void,
onFavoritePress: (PlanexGroupType) => void,
currentSearchString: string,
favoriteNumber: number,
height: number,
theme: CustomThemeType,
};
const LIST_ITEM_HEIGHT = 64;
const REPLACE_REGEX = /_/g;
class GroupListAccordion extends React.Component<PropsType> {
shouldComponentUpdate(nextProps: PropsType): boolean {
const {props} = this;
return (
nextProps.currentSearchString !== props.currentSearchString ||
nextProps.favoriteNumber !== props.favoriteNumber ||
nextProps.favorites.length !== props.favorites.length ||
nextProps.item.content.length !== props.item.content.length
);
}
@ -46,6 +47,7 @@ class GroupListAccordion extends React.Component<PropsType> {
<GroupListItem
height={LIST_ITEM_HEIGHT}
item={item}
favorites={props.favorites}
onPress={onPress}
onStarPress={onStarPress}
/>
@ -80,7 +82,7 @@ class GroupListAccordion extends React.Component<PropsType> {
return (
<View>
<AnimatedAccordion
title={item.name}
title={item.name.replace(REPLACE_REGEX, ' ')}
style={{
height: props.height,
justifyContent: 'center',
@ -94,11 +96,11 @@ class GroupListAccordion extends React.Component<PropsType> {
/>
) : null
}
unmountWhenCollapsed // Only render list if expanded for increased performance
opened={props.item.id === 0 || props.currentSearchString.length > 0}>
unmountWhenCollapsed={item.id !== 0} // Only render list if expanded for increased performance
opened={props.currentSearchString.length > 0}>
<FlatList
data={this.getData()}
extraData={props.currentSearchString}
extraData={props.currentSearchString + props.favorites.length}
renderItem={this.getRenderItem}
keyExtractor={this.keyExtractor}
listKey={item.id.toString()}

View file

@ -10,40 +10,44 @@ type PropsType = {
onPress: () => void,
onStarPress: () => void,
item: PlanexGroupType,
favorites: Array<PlanexGroupType>,
height: number,
};
type StateType = {
isFav: boolean,
};
const REPLACE_REGEX = /_/g;
class GroupListItem extends React.Component<PropsType> {
isFav: boolean;
class GroupListItem extends React.Component<PropsType, StateType> {
constructor(props: PropsType) {
super(props);
this.state = {
isFav: props.item.isFav !== undefined && props.item.isFav,
};
this.isFav = this.isGroupInFavorites(props.favorites);
}
shouldComponentUpdate(prevProps: PropsType, prevState: StateType): boolean {
const {isFav} = this.state;
return prevState.isFav !== isFav;
shouldComponentUpdate(nextProps: PropsType): boolean {
const {favorites} = this.props;
const favChanged = favorites.length !== nextProps.favorites.length;
let newFavState = this.isFav;
if (favChanged) newFavState = this.isGroupInFavorites(nextProps.favorites);
const shouldUpdate = this.isFav !== newFavState;
this.isFav = newFavState;
return shouldUpdate;
}
onStarPress = () => {
const {props} = this;
this.setState((prevState: StateType): StateType => ({
isFav: !prevState.isFav,
}));
props.onStarPress();
};
isGroupInFavorites(favorites: Array<PlanexGroupType>): boolean {
const {item} = this.props;
for (let i = 0; i < favorites.length; i += 1) {
if (favorites[i].id === item.id) return true;
}
return false;
}
render(): React.Node {
const {props, state} = this;
const {props} = this;
const {colors} = props.theme;
return (
<List.Item
title={props.item.name}
title={props.item.name.replace(REPLACE_REGEX, ' ')}
onPress={props.onPress}
left={({size}: {size: number}): React.Node => (
<List.Icon size={size} icon="chevron-right" />
@ -52,8 +56,8 @@ class GroupListItem extends React.Component<PropsType, StateType> {
<IconButton
size={size}
icon="star"
onPress={this.onStarPress}
color={state.isFav ? colors.tetrisScore : color}
onPress={props.onStarPress}
color={this.isFav ? colors.tetrisScore : color}
/>
)}
style={{

View file

@ -15,7 +15,6 @@ const LIST_ITEM_HEIGHT = 70;
export type PlanexGroupType = {
name: string,
id: number,
isFav: boolean,
};
export type PlanexGroupCategoryType = {
@ -43,46 +42,11 @@ function sortName(
}
const GROUPS_URL = 'http://planex.insa-toulouse.fr/wsAdeGrp.php?projectId=1';
const REPLACE_REGEX = /_/g;
/**
* Class defining planex group selection screen.
*/
class GroupSelectionScreen extends React.Component<PropsType, StateType> {
/**
* Removes the given group from the given array
*
* @param favorites The array containing favorites groups
* @param group The group to remove from the array
*/
static removeGroupFromFavorites(
favorites: Array<PlanexGroupType>,
group: PlanexGroupType,
) {
for (let i = 0; i < favorites.length; i += 1) {
if (group.id === favorites[i].id) {
favorites.splice(i, 1);
break;
}
}
}
/**
* Adds the given group to the given array
*
* @param favorites The array containing favorites groups
* @param group The group to add to the array
*/
static addGroupToFavorites(
favorites: Array<PlanexGroupType>,
group: PlanexGroupType,
) {
const favGroup = {...group};
favGroup.isFav = true;
favorites.push(favGroup);
favorites.sort(sortName);
}
constructor(props: PropsType) {
super(props);
this.state = {
@ -130,14 +94,17 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
*/
getRenderItem = ({item}: {item: PlanexGroupCategoryType}): React.Node => {
const {currentSearchString, favoriteGroups} = this.state;
if (this.shouldDisplayAccordion(item)) {
if (
this.shouldDisplayAccordion(item) ||
(item.id === 0 && item.content.length === 0)
) {
return (
<GroupListAccordion
item={item}
favorites={[...favoriteGroups]}
onGroupPress={this.onListItemPress}
onFavoritePress={this.onListFavoritePress}
currentSearchString={currentSearchString}
favoriteNumber={favoriteGroups.length}
height={LIST_ITEM_HEIGHT}
/>
);
@ -145,21 +112,6 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
return null;
};
/**
* Replaces underscore by spaces and sets the favorite state of every group in the given category
*
* @param groups The groups to format
* @return {Array<PlanexGroupType>}
*/
getFormattedGroups(groups: Array<PlanexGroupType>): Array<PlanexGroupType> {
return groups.map((group: PlanexGroupType): PlanexGroupType => {
const newGroup = {...group};
newGroup.name = group.name.replace(REPLACE_REGEX, ' ');
newGroup.isFav = this.isGroupInFavorites(group);
return newGroup;
});
}
/**
* Creates the dataset to be used in the FlatList
*
@ -231,16 +183,8 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
* @param group The group to add/remove to favorites
*/
updateGroupFavorites(group: PlanexGroupType) {
const {favoriteGroups} = this.state;
const newFavorites = [...favoriteGroups];
if (this.isGroupInFavorites(group))
GroupSelectionScreen.removeGroupFromFavorites(newFavorites, group);
else GroupSelectionScreen.addGroupToFavorites(newFavorites, group);
this.setState({favoriteGroups: newFavorites});
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
newFavorites,
);
if (this.isGroupInFavorites(group)) this.removeGroupFromFavorites(group);
else this.addGroupToFavorites(group);
}
/**
@ -276,9 +220,7 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
// eslint-disable-next-line flowtype/no-weak-types
(Object.values(fetchedData): Array<any>).forEach(
(category: PlanexGroupCategoryType) => {
const newCat = {...category};
newCat.content = this.getFormattedGroups(category.content);
data.push(newCat);
data.push(category);
},
);
data.sort(sortName);
@ -290,6 +232,50 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
return data;
}
/**
* Removes the given group from the favorites
*
* @param group The group to remove from the array
*/
removeGroupFromFavorites(group: PlanexGroupType) {
this.setState((prevState: StateType): {
favoriteGroups: Array<PlanexGroupType>,
} => {
const {favoriteGroups} = prevState;
for (let i = 0; i < favoriteGroups.length; i += 1) {
if (group.id === favoriteGroups[i].id) {
favoriteGroups.splice(i, 1);
break;
}
}
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
favoriteGroups,
);
return {favoriteGroups};
});
}
/**
* Adds the given group to favorites
*
* @param group The group to add to the array
*/
addGroupToFavorites(group: PlanexGroupType) {
this.setState((prevState: StateType): {
favoriteGroups: Array<PlanexGroupType>,
} => {
const {favoriteGroups} = prevState;
favoriteGroups.push(group);
favoriteGroups.sort(sortName);
AsyncStorageManager.set(
AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
favoriteGroups,
);
return {favoriteGroups};
});
}
render(): React.Node {
const {props, state} = this;
return (