forked from vergnet/application-amicale
Improve planex group favorite handling
This commit is contained in:
parent
eef6f75414
commit
327488a470
4 changed files with 87 additions and 95 deletions
|
@ -136,8 +136,8 @@ android {
|
||||||
applicationId 'fr.amicaleinsat.application'
|
applicationId 'fr.amicaleinsat.application'
|
||||||
minSdkVersion rootProject.ext.minSdkVersion
|
minSdkVersion rootProject.ext.minSdkVersion
|
||||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||||
versionCode 32
|
versionCode 34
|
||||||
versionName "3.1.4"
|
versionName "4.0.1"
|
||||||
missingDimensionStrategy 'react-native-camera', 'general'
|
missingDimensionStrategy 'react-native-camera', 'general'
|
||||||
}
|
}
|
||||||
splits {
|
splits {
|
||||||
|
|
|
@ -14,22 +14,23 @@ import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
item: PlanexGroupCategoryType,
|
item: PlanexGroupCategoryType,
|
||||||
|
favorites: Array<PlanexGroupType>,
|
||||||
onGroupPress: (PlanexGroupType) => void,
|
onGroupPress: (PlanexGroupType) => void,
|
||||||
onFavoritePress: (PlanexGroupType) => void,
|
onFavoritePress: (PlanexGroupType) => void,
|
||||||
currentSearchString: string,
|
currentSearchString: string,
|
||||||
favoriteNumber: number,
|
|
||||||
height: number,
|
height: number,
|
||||||
theme: CustomThemeType,
|
theme: CustomThemeType,
|
||||||
};
|
};
|
||||||
|
|
||||||
const LIST_ITEM_HEIGHT = 64;
|
const LIST_ITEM_HEIGHT = 64;
|
||||||
|
const REPLACE_REGEX = /_/g;
|
||||||
|
|
||||||
class GroupListAccordion extends React.Component<PropsType> {
|
class GroupListAccordion extends React.Component<PropsType> {
|
||||||
shouldComponentUpdate(nextProps: PropsType): boolean {
|
shouldComponentUpdate(nextProps: PropsType): boolean {
|
||||||
const {props} = this;
|
const {props} = this;
|
||||||
return (
|
return (
|
||||||
nextProps.currentSearchString !== props.currentSearchString ||
|
nextProps.currentSearchString !== props.currentSearchString ||
|
||||||
nextProps.favoriteNumber !== props.favoriteNumber ||
|
nextProps.favorites.length !== props.favorites.length ||
|
||||||
nextProps.item.content.length !== props.item.content.length
|
nextProps.item.content.length !== props.item.content.length
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -46,6 +47,7 @@ class GroupListAccordion extends React.Component<PropsType> {
|
||||||
<GroupListItem
|
<GroupListItem
|
||||||
height={LIST_ITEM_HEIGHT}
|
height={LIST_ITEM_HEIGHT}
|
||||||
item={item}
|
item={item}
|
||||||
|
favorites={props.favorites}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
onStarPress={onStarPress}
|
onStarPress={onStarPress}
|
||||||
/>
|
/>
|
||||||
|
@ -80,7 +82,7 @@ class GroupListAccordion extends React.Component<PropsType> {
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<AnimatedAccordion
|
<AnimatedAccordion
|
||||||
title={item.name}
|
title={item.name.replace(REPLACE_REGEX, ' ')}
|
||||||
style={{
|
style={{
|
||||||
height: props.height,
|
height: props.height,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
|
@ -94,11 +96,11 @@ class GroupListAccordion extends React.Component<PropsType> {
|
||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
unmountWhenCollapsed // Only render list if expanded for increased performance
|
unmountWhenCollapsed={item.id !== 0} // Only render list if expanded for increased performance
|
||||||
opened={props.item.id === 0 || props.currentSearchString.length > 0}>
|
opened={props.currentSearchString.length > 0}>
|
||||||
<FlatList
|
<FlatList
|
||||||
data={this.getData()}
|
data={this.getData()}
|
||||||
extraData={props.currentSearchString}
|
extraData={props.currentSearchString + props.favorites.length}
|
||||||
renderItem={this.getRenderItem}
|
renderItem={this.getRenderItem}
|
||||||
keyExtractor={this.keyExtractor}
|
keyExtractor={this.keyExtractor}
|
||||||
listKey={item.id.toString()}
|
listKey={item.id.toString()}
|
||||||
|
|
|
@ -10,40 +10,44 @@ type PropsType = {
|
||||||
onPress: () => void,
|
onPress: () => void,
|
||||||
onStarPress: () => void,
|
onStarPress: () => void,
|
||||||
item: PlanexGroupType,
|
item: PlanexGroupType,
|
||||||
|
favorites: Array<PlanexGroupType>,
|
||||||
height: number,
|
height: number,
|
||||||
};
|
};
|
||||||
|
|
||||||
type StateType = {
|
const REPLACE_REGEX = /_/g;
|
||||||
isFav: boolean,
|
|
||||||
};
|
class GroupListItem extends React.Component<PropsType> {
|
||||||
|
isFav: boolean;
|
||||||
|
|
||||||
class GroupListItem extends React.Component<PropsType, StateType> {
|
|
||||||
constructor(props: PropsType) {
|
constructor(props: PropsType) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.isFav = this.isGroupInFavorites(props.favorites);
|
||||||
isFav: props.item.isFav !== undefined && props.item.isFav,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate(prevProps: PropsType, prevState: StateType): boolean {
|
shouldComponentUpdate(nextProps: PropsType): boolean {
|
||||||
const {isFav} = this.state;
|
const {favorites} = this.props;
|
||||||
return prevState.isFav !== isFav;
|
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 = () => {
|
isGroupInFavorites(favorites: Array<PlanexGroupType>): boolean {
|
||||||
const {props} = this;
|
const {item} = this.props;
|
||||||
this.setState((prevState: StateType): StateType => ({
|
for (let i = 0; i < favorites.length; i += 1) {
|
||||||
isFav: !prevState.isFav,
|
if (favorites[i].id === item.id) return true;
|
||||||
}));
|
}
|
||||||
props.onStarPress();
|
return false;
|
||||||
};
|
}
|
||||||
|
|
||||||
render(): React.Node {
|
render(): React.Node {
|
||||||
const {props, state} = this;
|
const {props} = this;
|
||||||
const {colors} = props.theme;
|
const {colors} = props.theme;
|
||||||
return (
|
return (
|
||||||
<List.Item
|
<List.Item
|
||||||
title={props.item.name}
|
title={props.item.name.replace(REPLACE_REGEX, ' ')}
|
||||||
onPress={props.onPress}
|
onPress={props.onPress}
|
||||||
left={({size}: {size: number}): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon size={size} icon="chevron-right" />
|
<List.Icon size={size} icon="chevron-right" />
|
||||||
|
@ -52,8 +56,8 @@ class GroupListItem extends React.Component<PropsType, StateType> {
|
||||||
<IconButton
|
<IconButton
|
||||||
size={size}
|
size={size}
|
||||||
icon="star"
|
icon="star"
|
||||||
onPress={this.onStarPress}
|
onPress={props.onStarPress}
|
||||||
color={state.isFav ? colors.tetrisScore : color}
|
color={this.isFav ? colors.tetrisScore : color}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
@ -15,7 +15,6 @@ const LIST_ITEM_HEIGHT = 70;
|
||||||
export type PlanexGroupType = {
|
export type PlanexGroupType = {
|
||||||
name: string,
|
name: string,
|
||||||
id: number,
|
id: number,
|
||||||
isFav: boolean,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type PlanexGroupCategoryType = {
|
export type PlanexGroupCategoryType = {
|
||||||
|
@ -43,46 +42,11 @@ function sortName(
|
||||||
}
|
}
|
||||||
|
|
||||||
const GROUPS_URL = 'http://planex.insa-toulouse.fr/wsAdeGrp.php?projectId=1';
|
const GROUPS_URL = 'http://planex.insa-toulouse.fr/wsAdeGrp.php?projectId=1';
|
||||||
const REPLACE_REGEX = /_/g;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class defining planex group selection screen.
|
* Class defining planex group selection screen.
|
||||||
*/
|
*/
|
||||||
class GroupSelectionScreen extends React.Component<PropsType, StateType> {
|
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) {
|
constructor(props: PropsType) {
|
||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
|
@ -130,14 +94,17 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
|
||||||
*/
|
*/
|
||||||
getRenderItem = ({item}: {item: PlanexGroupCategoryType}): React.Node => {
|
getRenderItem = ({item}: {item: PlanexGroupCategoryType}): React.Node => {
|
||||||
const {currentSearchString, favoriteGroups} = this.state;
|
const {currentSearchString, favoriteGroups} = this.state;
|
||||||
if (this.shouldDisplayAccordion(item)) {
|
if (
|
||||||
|
this.shouldDisplayAccordion(item) ||
|
||||||
|
(item.id === 0 && item.content.length === 0)
|
||||||
|
) {
|
||||||
return (
|
return (
|
||||||
<GroupListAccordion
|
<GroupListAccordion
|
||||||
item={item}
|
item={item}
|
||||||
|
favorites={[...favoriteGroups]}
|
||||||
onGroupPress={this.onListItemPress}
|
onGroupPress={this.onListItemPress}
|
||||||
onFavoritePress={this.onListFavoritePress}
|
onFavoritePress={this.onListFavoritePress}
|
||||||
currentSearchString={currentSearchString}
|
currentSearchString={currentSearchString}
|
||||||
favoriteNumber={favoriteGroups.length}
|
|
||||||
height={LIST_ITEM_HEIGHT}
|
height={LIST_ITEM_HEIGHT}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -145,21 +112,6 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
|
||||||
return null;
|
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
|
* 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
|
* @param group The group to add/remove to favorites
|
||||||
*/
|
*/
|
||||||
updateGroupFavorites(group: PlanexGroupType) {
|
updateGroupFavorites(group: PlanexGroupType) {
|
||||||
const {favoriteGroups} = this.state;
|
if (this.isGroupInFavorites(group)) this.removeGroupFromFavorites(group);
|
||||||
const newFavorites = [...favoriteGroups];
|
else this.addGroupToFavorites(group);
|
||||||
if (this.isGroupInFavorites(group))
|
|
||||||
GroupSelectionScreen.removeGroupFromFavorites(newFavorites, group);
|
|
||||||
else GroupSelectionScreen.addGroupToFavorites(newFavorites, group);
|
|
||||||
this.setState({favoriteGroups: newFavorites});
|
|
||||||
AsyncStorageManager.set(
|
|
||||||
AsyncStorageManager.PREFERENCES.planexFavoriteGroups.key,
|
|
||||||
newFavorites,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -276,9 +220,7 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
|
||||||
// eslint-disable-next-line flowtype/no-weak-types
|
// eslint-disable-next-line flowtype/no-weak-types
|
||||||
(Object.values(fetchedData): Array<any>).forEach(
|
(Object.values(fetchedData): Array<any>).forEach(
|
||||||
(category: PlanexGroupCategoryType) => {
|
(category: PlanexGroupCategoryType) => {
|
||||||
const newCat = {...category};
|
data.push(category);
|
||||||
newCat.content = this.getFormattedGroups(category.content);
|
|
||||||
data.push(newCat);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
data.sort(sortName);
|
data.sort(sortName);
|
||||||
|
@ -290,6 +232,50 @@ class GroupSelectionScreen extends React.Component<PropsType, StateType> {
|
||||||
return data;
|
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 {
|
render(): React.Node {
|
||||||
const {props, state} = this;
|
const {props, state} = this;
|
||||||
return (
|
return (
|
||||||
|
|
Loading…
Reference in a new issue