Compare commits
No commits in common. "a3ce3a76c391fe4669e211b034c80e3ddddcc6c3" and "f0de0599dd4b0773c5a30d47a2b5a8e73708f203" have entirely different histories.
a3ce3a76c3
...
f0de0599dd
28 changed files with 237 additions and 258 deletions
4
App.js
4
App.js
|
|
@ -165,9 +165,7 @@ export default class App extends React.Component<null, StateType> {
|
||||||
*/
|
*/
|
||||||
loadAssetsAsync = async () => {
|
loadAssetsAsync = async () => {
|
||||||
await AsyncStorageManager.getInstance().loadPreferences();
|
await AsyncStorageManager.getInstance().loadPreferences();
|
||||||
await ConnectionManager.getInstance()
|
await ConnectionManager.getInstance().recoverLogin();
|
||||||
.recoverLogin()
|
|
||||||
.catch(() => {});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,6 @@ import {FlatList, StyleSheet} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
|
import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
|
||||||
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import type {
|
|
||||||
CardTitleIconPropsType,
|
|
||||||
ListIconPropsType,
|
|
||||||
} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
teams: Array<VoteTeamType>,
|
teams: Array<VoteTeamType>,
|
||||||
|
|
@ -82,10 +78,10 @@ class VoteResults extends React.Component<PropsType> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={item.name}
|
title={item.name}
|
||||||
description={`${item.votes} ${i18n.t('screens.vote.results.votes')}`}
|
description={`${item.votes} ${i18n.t('screens.vote.results.votes')}`}
|
||||||
left={(iconProps: ListIconPropsType): React.Node =>
|
left={({size}: {size: number}): React.Node =>
|
||||||
isWinner ? (
|
isWinner ? (
|
||||||
<List.Icon
|
<List.Icon
|
||||||
style={iconProps.style}
|
size={size}
|
||||||
icon={isDraw ? 'trophy-outline' : 'trophy'}
|
icon={isDraw ? 'trophy-outline' : 'trophy'}
|
||||||
color={props.theme.colors.primary}
|
color={props.theme.colors.primary}
|
||||||
/>
|
/>
|
||||||
|
|
@ -115,8 +111,8 @@ class VoteResults extends React.Component<PropsType> {
|
||||||
subtitle={`${i18n.t('screens.vote.results.subtitle')} ${
|
subtitle={`${i18n.t('screens.vote.results.subtitle')} ${
|
||||||
props.dateEnd
|
props.dateEnd
|
||||||
}`}
|
}`}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon size={iconProps.size} icon="podium-gold" />
|
<Avatar.Icon size={size} icon="podium-gold" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ import ConnectionManager from '../../../managers/ConnectionManager';
|
||||||
import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog';
|
import LoadingConfirmDialog from '../../Dialogs/LoadingConfirmDialog';
|
||||||
import ErrorDialog from '../../Dialogs/ErrorDialog';
|
import ErrorDialog from '../../Dialogs/ErrorDialog';
|
||||||
import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
|
import type {VoteTeamType} from '../../../screens/Amicale/VoteScreen';
|
||||||
import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
teams: Array<VoteTeamType>,
|
teams: Array<VoteTeamType>,
|
||||||
|
|
@ -100,8 +99,8 @@ export default class VoteSelect extends React.PureComponent<
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.vote.select.title')}
|
title={i18n.t('screens.vote.select.title')}
|
||||||
subtitle={i18n.t('screens.vote.select.subtitle')}
|
subtitle={i18n.t('screens.vote.select.subtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon size={iconProps.size} icon="alert-decagram" />
|
<Avatar.Icon size={size} icon="alert-decagram" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ import * as React from 'react';
|
||||||
import {Avatar, Card, Paragraph} from 'react-native-paper';
|
import {Avatar, Card, Paragraph} from 'react-native-paper';
|
||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
startDate: string,
|
startDate: string,
|
||||||
|
|
@ -31,8 +30,8 @@ export default class VoteTease extends React.Component<PropsType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.vote.tease.title')}
|
title={i18n.t('screens.vote.tease.title')}
|
||||||
subtitle={i18n.t('screens.vote.tease.subtitle')}
|
subtitle={i18n.t('screens.vote.tease.subtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon size={iconProps.size} icon="vote" />
|
<Avatar.Icon size={size} icon="vote" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,15 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Avatar, Card, Paragraph, withTheme} from 'react-native-paper';
|
import {
|
||||||
|
ActivityIndicator,
|
||||||
|
Card,
|
||||||
|
Paragraph,
|
||||||
|
withTheme,
|
||||||
|
} from 'react-native-paper';
|
||||||
import {StyleSheet} from 'react-native';
|
import {StyleSheet} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
startDate: string | null,
|
startDate: string | null,
|
||||||
|
|
@ -41,8 +45,8 @@ class VoteWait extends React.Component<PropsType> {
|
||||||
: i18n.t('screens.vote.wait.titleEnded')
|
: i18n.t('screens.vote.wait.titleEnded')
|
||||||
}
|
}
|
||||||
subtitle={i18n.t('screens.vote.wait.subtitle')}
|
subtitle={i18n.t('screens.vote.wait.subtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon size={iconProps.size} icon="progress-check" />
|
<ActivityIndicator size={size} />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import {List, withTheme} from 'react-native-paper';
|
||||||
import Collapsible from 'react-native-collapsible';
|
import Collapsible from 'react-native-collapsible';
|
||||||
import * as Animatable from 'react-native-animatable';
|
import * as Animatable from 'react-native-animatable';
|
||||||
import type {CustomThemeType} from '../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../managers/ThemeManager';
|
||||||
import type {ListIconPropsType} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
theme: CustomThemeType,
|
theme: CustomThemeType,
|
||||||
|
|
@ -92,13 +91,14 @@ class AnimatedAccordion extends React.Component<PropsType, StateType> {
|
||||||
subtitle={props.subtitle}
|
subtitle={props.subtitle}
|
||||||
titleStyle={state.expanded ? {color: colors.primary} : null}
|
titleStyle={state.expanded ? {color: colors.primary} : null}
|
||||||
onPress={this.toggleAccordion}
|
onPress={this.toggleAccordion}
|
||||||
right={(iconProps: ListIconPropsType): React.Node => (
|
right={({size}: {size: number}): React.Node => (
|
||||||
<AnimatedListIcon
|
<AnimatedListIcon
|
||||||
ref={this.chevronRef}
|
ref={this.chevronRef}
|
||||||
style={iconProps.style}
|
size={size}
|
||||||
icon={this.chevronIcon}
|
icon={this.chevronIcon}
|
||||||
color={state.expanded ? colors.primary : iconProps.color}
|
color={state.expanded ? colors.primary : null}
|
||||||
useNativeDriver
|
useNativeDriver
|
||||||
|
style={{rotate: '0deg'}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
left={props.left}
|
left={props.left}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import {View} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import {StackNavigationProp} from '@react-navigation/stack';
|
import {StackNavigationProp} from '@react-navigation/stack';
|
||||||
import type {CustomThemeType} from '../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../managers/ThemeManager';
|
||||||
import type {ListIconPropsType} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
navigation: StackNavigationProp,
|
navigation: StackNavigationProp,
|
||||||
|
|
@ -20,27 +19,19 @@ class ActionsDashBoardItem extends React.Component<PropsType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): React.Node {
|
render(): React.Node {
|
||||||
const {navigation} = this.props;
|
const {props} = this;
|
||||||
return (
|
return (
|
||||||
<View>
|
<View>
|
||||||
<List.Item
|
<List.Item
|
||||||
title={i18n.t('screens.feedback.homeButtonTitle')}
|
title={i18n.t('screens.feedback.homeButtonTitle')}
|
||||||
description={i18n.t('screens.feedback.homeButtonSubtitle')}
|
description={i18n.t('screens.feedback.homeButtonSubtitle')}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} icon="comment-quote" />
|
||||||
color={props.color}
|
|
||||||
style={props.style}
|
|
||||||
icon="comment-quote"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
right={(props: ListIconPropsType): React.Node => (
|
right={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} icon="chevron-right" />
|
||||||
color={props.color}
|
|
||||||
style={props.style}
|
|
||||||
icon="chevron-right"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
onPress={(): void => navigation.navigate('feedback')}
|
onPress={(): void => props.navigation.navigate('feedback')}
|
||||||
style={{
|
style={{
|
||||||
paddingTop: 0,
|
paddingTop: 0,
|
||||||
paddingBottom: 0,
|
paddingBottom: 0,
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import {
|
||||||
import {StyleSheet, View} from 'react-native';
|
import {StyleSheet, View} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import type {CustomThemeType} from '../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../managers/ThemeManager';
|
||||||
import type {CardTitleIconPropsType} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
eventNumber: number,
|
eventNumber: number,
|
||||||
|
|
@ -77,11 +76,11 @@ class EventDashBoardItem extends React.Component<PropsType> {
|
||||||
titleStyle={{color: textColor}}
|
titleStyle={{color: textColor}}
|
||||||
subtitle={subtitle}
|
subtitle={subtitle}
|
||||||
subtitleStyle={{color: textColor}}
|
subtitleStyle={{color: textColor}}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={(): React.Node => (
|
||||||
<Avatar.Icon
|
<Avatar.Icon
|
||||||
icon="calendar-range"
|
icon="calendar-range"
|
||||||
color={iconColor}
|
color={iconColor}
|
||||||
size={iconProps.size}
|
size={60}
|
||||||
style={styles.avatar}
|
style={styles.avatar}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import i18n from 'i18n-js';
|
||||||
import AnimatedAccordion from '../../Animations/AnimatedAccordion';
|
import AnimatedAccordion from '../../Animations/AnimatedAccordion';
|
||||||
import {isItemInCategoryFilter} from '../../../utils/Search';
|
import {isItemInCategoryFilter} from '../../../utils/Search';
|
||||||
import type {ClubCategoryType} from '../../../screens/Amicale/Clubs/ClubListScreen';
|
import type {ClubCategoryType} from '../../../screens/Amicale/Clubs/ClubListScreen';
|
||||||
import type {ListIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
categories: Array<ClubCategoryType>,
|
categories: Array<ClubCategoryType>,
|
||||||
|
|
@ -75,8 +74,8 @@ class ClubListHeader extends React.Component<PropsType> {
|
||||||
<Card style={styles.card}>
|
<Card style={styles.card}>
|
||||||
<AnimatedAccordion
|
<AnimatedAccordion
|
||||||
title={i18n.t('screens.clubs.categories')}
|
title={i18n.t('screens.clubs.categories')}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon color={props.color} style={props.style} icon="star" />
|
<List.Icon size={size} icon="star" />
|
||||||
)}
|
)}
|
||||||
opened>
|
opened>
|
||||||
<Text style={styles.text}>
|
<Text style={styles.text}>
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@ import {Image} from 'react-native';
|
||||||
import {List, withTheme} from 'react-native-paper';
|
import {List, withTheme} from 'react-native-paper';
|
||||||
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import type {ServiceItemType} from '../../../managers/ServicesManager';
|
import type {ServiceItemType} from '../../../managers/ServicesManager';
|
||||||
import type {ListIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
item: ServiceItemType,
|
item: ServiceItemType,
|
||||||
|
|
@ -22,36 +21,36 @@ class DashboardEditItem extends React.Component<PropsType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
render(): React.Node {
|
render(): React.Node {
|
||||||
const {item, onPress, height, isActive, theme} = this.props;
|
const {props} = this;
|
||||||
return (
|
return (
|
||||||
<List.Item
|
<List.Item
|
||||||
title={item.title}
|
title={props.item.title}
|
||||||
description={item.subtitle}
|
description={props.item.subtitle}
|
||||||
onPress={isActive ? null : onPress}
|
onPress={props.isActive ? null : props.onPress}
|
||||||
left={(): React.Node => (
|
left={(): React.Node => (
|
||||||
<Image
|
<Image
|
||||||
source={{uri: item.image}}
|
source={{uri: props.item.image}}
|
||||||
style={{
|
style={{
|
||||||
width: 40,
|
width: 40,
|
||||||
height: 40,
|
height: 40,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
right={(props: ListIconPropsType): React.Node =>
|
right={({size}: {size: number}): React.Node =>
|
||||||
isActive ? (
|
props.isActive ? (
|
||||||
<List.Icon
|
<List.Icon
|
||||||
style={props.style}
|
size={size}
|
||||||
icon="check"
|
icon="check"
|
||||||
color={theme.colors.success}
|
color={props.theme.colors.success}
|
||||||
/>
|
/>
|
||||||
) : null
|
) : null
|
||||||
}
|
}
|
||||||
style={{
|
style={{
|
||||||
height,
|
height: props.height,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
paddingLeft: 30,
|
paddingLeft: 30,
|
||||||
backgroundColor: isActive
|
backgroundColor: props.isActive
|
||||||
? theme.colors.proxiwashFinishedColor
|
? props.theme.colors.proxiwashFinishedColor
|
||||||
: 'transparent',
|
: 'transparent',
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import type {
|
||||||
PlanexGroupCategoryType,
|
PlanexGroupCategoryType,
|
||||||
} from '../../../screens/Planex/GroupSelectionScreen';
|
} from '../../../screens/Planex/GroupSelectionScreen';
|
||||||
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import type {ListIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
item: PlanexGroupCategoryType,
|
item: PlanexGroupCategoryType,
|
||||||
|
|
@ -88,10 +87,10 @@ class GroupListAccordion extends React.Component<PropsType> {
|
||||||
height: props.height,
|
height: props.height,
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
}}
|
}}
|
||||||
left={(iconProps: ListIconPropsType): React.Node =>
|
left={({size}: {size: number}): React.Node =>
|
||||||
item.id === 0 ? (
|
item.id === 0 ? (
|
||||||
<List.Icon
|
<List.Icon
|
||||||
style={iconProps.style}
|
size={size}
|
||||||
icon="star"
|
icon="star"
|
||||||
color={props.theme.colors.tetrisScore}
|
color={props.theme.colors.tetrisScore}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,10 @@
|
||||||
// @flow
|
// @flow
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {List, TouchableRipple, withTheme} from 'react-native-paper';
|
import {IconButton, List, withTheme} from 'react-native-paper';
|
||||||
import * as Animatable from 'react-native-animatable';
|
import * as Animatable from 'react-native-animatable';
|
||||||
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
|
|
||||||
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import type {PlanexGroupType} from '../../../screens/Planex/GroupSelectionScreen';
|
import type {PlanexGroupType} from '../../../screens/Planex/GroupSelectionScreen';
|
||||||
import type {ListIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
theme: CustomThemeType,
|
theme: CustomThemeType,
|
||||||
|
|
@ -22,7 +20,7 @@ const REPLACE_REGEX = /_/g;
|
||||||
class GroupListItem extends React.Component<PropsType> {
|
class GroupListItem extends React.Component<PropsType> {
|
||||||
isFav: boolean;
|
isFav: boolean;
|
||||||
|
|
||||||
starRef: null | Animatable.View;
|
starRef = {current: null | IconButton};
|
||||||
|
|
||||||
constructor(props: PropsType) {
|
constructor(props: PropsType) {
|
||||||
super(props);
|
super(props);
|
||||||
|
|
@ -39,16 +37,6 @@ class GroupListItem extends React.Component<PropsType> {
|
||||||
return shouldUpdate;
|
return shouldUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
onStarPress = () => {
|
|
||||||
const {props} = this;
|
|
||||||
const ref = this.starRef;
|
|
||||||
if (ref != null) {
|
|
||||||
if (this.isFav) ref.rubberBand();
|
|
||||||
else ref.swing();
|
|
||||||
}
|
|
||||||
props.onStarPress();
|
|
||||||
};
|
|
||||||
|
|
||||||
isGroupInFavorites(favorites: Array<PlanexGroupType>): boolean {
|
isGroupInFavorites(favorites: Array<PlanexGroupType>): boolean {
|
||||||
const {item} = this.props;
|
const {item} = this.props;
|
||||||
for (let i = 0; i < favorites.length; i += 1) {
|
for (let i = 0; i < favorites.length; i += 1) {
|
||||||
|
|
@ -57,6 +45,15 @@ class GroupListItem extends React.Component<PropsType> {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onStarPress = () => {
|
||||||
|
const {props} = this;
|
||||||
|
if (this.starRef.current != null) {
|
||||||
|
if (this.isFav) this.starRef.current.rubberBand();
|
||||||
|
else this.starRef.current.swing();
|
||||||
|
}
|
||||||
|
props.onStarPress();
|
||||||
|
};
|
||||||
|
|
||||||
render(): React.Node {
|
render(): React.Node {
|
||||||
const {props} = this;
|
const {props} = this;
|
||||||
const {colors} = props.theme;
|
const {colors} = props.theme;
|
||||||
|
|
@ -64,34 +61,17 @@ class GroupListItem extends React.Component<PropsType> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={props.item.name.replace(REPLACE_REGEX, ' ')}
|
title={props.item.name.replace(REPLACE_REGEX, ' ')}
|
||||||
onPress={props.onPress}
|
onPress={props.onPress}
|
||||||
left={(iconProps: ListIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} icon="chevron-right" />
|
||||||
color={iconProps.color}
|
|
||||||
style={iconProps.style}
|
|
||||||
icon="chevron-right"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
right={(iconProps: ListIconPropsType): React.Node => (
|
right={({size, color}: {size: number, color: string}): React.Node => (
|
||||||
<Animatable.View
|
<Animatable.View ref={this.starRef} useNativeDriver>
|
||||||
ref={(ref: Animatable.View) => {
|
<IconButton
|
||||||
this.starRef = ref;
|
size={size}
|
||||||
}}
|
icon="star"
|
||||||
useNativeDriver>
|
|
||||||
<TouchableRipple
|
|
||||||
onPress={this.onStarPress}
|
onPress={this.onStarPress}
|
||||||
style={{
|
color={this.isFav ? colors.tetrisScore : color}
|
||||||
marginRight: 10,
|
/>
|
||||||
marginLeft: 'auto',
|
|
||||||
marginTop: 'auto',
|
|
||||||
marginBottom: 'auto',
|
|
||||||
}}>
|
|
||||||
<MaterialCommunityIcons
|
|
||||||
size={30}
|
|
||||||
style={{padding: 10}}
|
|
||||||
name="star"
|
|
||||||
color={this.isFav ? colors.tetrisScore : iconProps.color}
|
|
||||||
/>
|
|
||||||
</TouchableRipple>
|
|
||||||
</Animatable.View>
|
</Animatable.View>
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -174,7 +174,7 @@ export default class CustomIntroSlider extends React.Component<
|
||||||
{state.currentSlide === index ? (
|
{state.currentSlide === index ? (
|
||||||
<View style={{height: '100%', flex: 1}}>
|
<View style={{height: '100%', flex: 1}}>
|
||||||
<View style={{flex: 1}}>{item.view()}</View>
|
<View style={{flex: 1}}>{item.view()}</View>
|
||||||
<Animatable.View useNativeDriver animation="fadeIn">
|
<Animatable.View animation="fadeIn">
|
||||||
{index !== 0 && index !== this.introSlides.length - 1 ? (
|
{index !== 0 && index !== this.introSlides.length - 1 ? (
|
||||||
<Mascot
|
<Mascot
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -218,18 +218,15 @@ export default class CustomIntroSlider extends React.Component<
|
||||||
borderColor: 'rgba(0,0,0,0.60)',
|
borderColor: 'rgba(0,0,0,0.60)',
|
||||||
borderWidth: 4,
|
borderWidth: 4,
|
||||||
borderRadius: 10,
|
borderRadius: 10,
|
||||||
elevation: 0,
|
|
||||||
}}>
|
}}>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
<Animatable.Text
|
<Animatable.Text
|
||||||
useNativeDriver
|
|
||||||
animation="fadeIn"
|
animation="fadeIn"
|
||||||
delay={100}
|
delay={100}
|
||||||
style={styles.title}>
|
style={styles.title}>
|
||||||
{item.title}
|
{item.title}
|
||||||
</Animatable.Text>
|
</Animatable.Text>
|
||||||
<Animatable.Text
|
<Animatable.Text
|
||||||
useNativeDriver
|
|
||||||
animation="fadeIn"
|
animation="fadeIn"
|
||||||
delay={200}
|
delay={200}
|
||||||
style={styles.text}>
|
style={styles.text}>
|
||||||
|
|
@ -323,10 +320,7 @@ export default class CustomIntroSlider extends React.Component<
|
||||||
static getIconView(icon: MaterialCommunityIconsGlyphs): React.Node {
|
static getIconView(icon: MaterialCommunityIconsGlyphs): React.Node {
|
||||||
return (
|
return (
|
||||||
<View style={{flex: 1}}>
|
<View style={{flex: 1}}>
|
||||||
<Animatable.View
|
<Animatable.View style={styles.center} animation="fadeIn">
|
||||||
useNativeDriver
|
|
||||||
style={styles.center}
|
|
||||||
animation="fadeIn">
|
|
||||||
<MaterialCommunityIcons name={icon} color="#fff" size={200} />
|
<MaterialCommunityIcons name={icon} color="#fff" size={200} />
|
||||||
</Animatable.View>
|
</Animatable.View>
|
||||||
</View>
|
</View>
|
||||||
|
|
@ -361,7 +355,6 @@ export default class CustomIntroSlider extends React.Component<
|
||||||
getRenderNextButton = (): React.Node => {
|
getRenderNextButton = (): React.Node => {
|
||||||
return (
|
return (
|
||||||
<Animatable.View
|
<Animatable.View
|
||||||
useNativeDriver
|
|
||||||
animation="fadeIn"
|
animation="fadeIn"
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
|
|
@ -376,7 +369,6 @@ export default class CustomIntroSlider extends React.Component<
|
||||||
getRenderDoneButton = (): React.Node => {
|
getRenderDoneButton = (): React.Node => {
|
||||||
return (
|
return (
|
||||||
<Animatable.View
|
<Animatable.View
|
||||||
useNativeDriver
|
|
||||||
animation="bounceIn"
|
animation="bounceIn"
|
||||||
style={{
|
style={{
|
||||||
borderRadius: 25,
|
borderRadius: 25,
|
||||||
|
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
// @flow
|
|
||||||
|
|
||||||
import type {ViewStyleProp} from 'react-native/Libraries/StyleSheet/StyleSheet';
|
|
||||||
|
|
||||||
export type ListIconPropsType = {
|
|
||||||
color: string,
|
|
||||||
style: ViewStyleProp,
|
|
||||||
};
|
|
||||||
|
|
||||||
export type CardTitleIconPropsType = {
|
|
||||||
size: number,
|
|
||||||
};
|
|
||||||
|
|
@ -8,10 +8,6 @@ import {StackNavigationProp} from '@react-navigation/stack';
|
||||||
import packageJson from '../../../package.json';
|
import packageJson from '../../../package.json';
|
||||||
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
|
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
|
||||||
import APP_LOGO from '../../../assets/android.icon.png';
|
import APP_LOGO from '../../../assets/android.icon.png';
|
||||||
import type {
|
|
||||||
CardTitleIconPropsType,
|
|
||||||
ListIconPropsType,
|
|
||||||
} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type ListItemType = {
|
type ListItemType = {
|
||||||
onPressCallback: () => void,
|
onPressCallback: () => void,
|
||||||
|
|
@ -221,9 +217,9 @@ class AboutScreen extends React.Component<PropsType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title="Campus"
|
title="Campus"
|
||||||
subtitle={packageJson.version}
|
subtitle={packageJson.version}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Image
|
<Avatar.Image
|
||||||
size={iconProps.size}
|
size={size}
|
||||||
source={APP_LOGO}
|
source={APP_LOGO}
|
||||||
style={{backgroundColor: 'transparent'}}
|
style={{backgroundColor: 'transparent'}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -250,8 +246,8 @@ class AboutScreen extends React.Component<PropsType> {
|
||||||
<Card style={{marginBottom: 10}}>
|
<Card style={{marginBottom: 10}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.about.team')}
|
title={i18n.t('screens.about.team')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size, color}: {size: number, color: string}): React.Node => (
|
||||||
<Avatar.Icon size={iconProps.size} icon="account-multiple" />
|
<Avatar.Icon size={size} color={color} icon="account-multiple" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
@ -300,10 +296,14 @@ class AboutScreen extends React.Component<PropsType> {
|
||||||
* @param props
|
* @param props
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
static getChevronIcon(props: ListIconPropsType): React.Node {
|
static getChevronIcon({
|
||||||
return (
|
size,
|
||||||
<List.Icon color={props.color} style={props.style} icon="chevron-right" />
|
color,
|
||||||
);
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node {
|
||||||
|
return <List.Icon size={size} color={color} icon="chevron-right" />;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -313,10 +313,11 @@ class AboutScreen extends React.Component<PropsType> {
|
||||||
* @param props
|
* @param props
|
||||||
* @return {*}
|
* @return {*}
|
||||||
*/
|
*/
|
||||||
static getItemIcon(item: ListItemType, props: ListIconPropsType): React.Node {
|
static getItemIcon(
|
||||||
return (
|
item: ListItemType,
|
||||||
<List.Icon color={props.color} style={props.style} icon={item.icon} />
|
{size, color}: {size: number, color: string},
|
||||||
);
|
): React.Node {
|
||||||
|
return <List.Icon size={size} color={color} icon={item.icon} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -325,7 +326,7 @@ class AboutScreen extends React.Component<PropsType> {
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
getCardItem = ({item}: {item: ListItemType}): React.Node => {
|
getCardItem = ({item}: {item: ListItemType}): React.Node => {
|
||||||
const getItemIcon = (props: ListIconPropsType): React.Node =>
|
const getItemIcon = (props: {size: number, color: string}): React.Node =>
|
||||||
AboutScreen.getItemIcon(item, props);
|
AboutScreen.getItemIcon(item, props);
|
||||||
if (item.showChevron) {
|
if (item.showChevron) {
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,11 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {FlatList, Image, Linking, View} from 'react-native';
|
import {FlatList, Image, Linking, View} from 'react-native';
|
||||||
import {Card, List, Text, withTheme, Avatar} from 'react-native-paper';
|
import {Card, List, Text, withTheme} from 'react-native-paper';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import type {MaterialCommunityIconsGlyphs} from 'react-native-vector-icons/MaterialCommunityIcons';
|
import type {MaterialCommunityIconsGlyphs} from 'react-native-vector-icons/MaterialCommunityIcons';
|
||||||
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
|
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
|
||||||
import AMICALE_LOGO from '../../../assets/amicale.png';
|
import AMICALE_LOGO from '../../../assets/amicale.png';
|
||||||
import type {
|
|
||||||
CardTitleIconPropsType,
|
|
||||||
ListIconPropsType,
|
|
||||||
} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type DatasetItemType = {
|
type DatasetItemType = {
|
||||||
name: string,
|
name: string,
|
||||||
|
|
@ -78,12 +74,14 @@ class AmicaleContactScreen extends React.Component<null> {
|
||||||
|
|
||||||
keyExtractor = (item: DatasetItemType): string => item.email;
|
keyExtractor = (item: DatasetItemType): string => item.email;
|
||||||
|
|
||||||
getChevronIcon = (iconProps: ListIconPropsType): React.Node => (
|
getChevronIcon = ({
|
||||||
<List.Icon
|
size,
|
||||||
color={iconProps.color}
|
color,
|
||||||
style={iconProps.style}
|
}: {
|
||||||
icon="chevron-right"
|
size: number,
|
||||||
/>
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="chevron-right" />
|
||||||
);
|
);
|
||||||
|
|
||||||
getRenderItem = ({item}: {item: DatasetItemType}): React.Node => {
|
getRenderItem = ({item}: {item: DatasetItemType}): React.Node => {
|
||||||
|
|
@ -94,12 +92,8 @@ class AmicaleContactScreen extends React.Component<null> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={item.name}
|
title={item.name}
|
||||||
description={item.email}
|
description={item.email}
|
||||||
left={(iconProps: ListIconPropsType): React.Node => (
|
left={({size, color}: {size: number, color: string}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} color={color} icon={item.icon} />
|
||||||
color={iconProps.color}
|
|
||||||
style={iconProps.style}
|
|
||||||
icon={item.icon}
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
right={this.getChevronIcon}
|
right={this.getChevronIcon}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
|
|
@ -129,8 +123,14 @@ class AmicaleContactScreen extends React.Component<null> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.amicaleAbout.title')}
|
title={i18n.t('screens.amicaleAbout.title')}
|
||||||
subtitle={i18n.t('screens.amicaleAbout.subtitle')}
|
subtitle={i18n.t('screens.amicaleAbout.subtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="information" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="information" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,11 @@
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Image, View} from 'react-native';
|
import {Image, View} from 'react-native';
|
||||||
import {Card, Avatar, Text, withTheme} from 'react-native-paper';
|
import {Card, List, Text, withTheme} from 'react-native-paper';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import Autolink from 'react-native-autolink';
|
import Autolink from 'react-native-autolink';
|
||||||
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
||||||
import AMICALE_ICON from '../../../../assets/amicale.png';
|
import AMICALE_ICON from '../../../../assets/amicale.png';
|
||||||
import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
const CONTACT_LINK = 'clubs@amicale-insat.fr';
|
const CONTACT_LINK = 'clubs@amicale-insat.fr';
|
||||||
|
|
||||||
|
|
@ -36,8 +35,8 @@ class ClubAboutScreen extends React.Component<null> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.clubs.about.title')}
|
title={i18n.t('screens.clubs.about.title')}
|
||||||
subtitle={i18n.t('screens.clubs.about.subtitle')}
|
subtitle={i18n.t('screens.clubs.about.subtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon size={iconProps.size} icon="information" />
|
<List.Icon size={size} icon="information" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,6 @@ import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import {ERROR_TYPE} from '../../../utils/WebData';
|
import {ERROR_TYPE} from '../../../utils/WebData';
|
||||||
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
||||||
import type {ApiGenericDataType} from '../../../utils/WebData';
|
import type {ApiGenericDataType} from '../../../utils/WebData';
|
||||||
import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
navigation: StackNavigationProp,
|
navigation: StackNavigationProp,
|
||||||
|
|
@ -134,9 +133,9 @@ class ClubDisplayScreen extends React.Component<PropsType> {
|
||||||
? i18n.t('screens.clubs.managersSubtitle')
|
? i18n.t('screens.clubs.managersSubtitle')
|
||||||
: i18n.t('screens.clubs.managersUnavailable')
|
: i18n.t('screens.clubs.managersUnavailable')
|
||||||
}
|
}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon
|
<Avatar.Icon
|
||||||
size={iconProps.size}
|
size={size}
|
||||||
style={{backgroundColor: 'transparent'}}
|
style={{backgroundColor: 'transparent'}}
|
||||||
color={
|
color={
|
||||||
hasManagers
|
hasManagers
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,9 @@ export type RentedDeviceType = {
|
||||||
const LIST_ITEM_HEIGHT = 64;
|
const LIST_ITEM_HEIGHT = 64;
|
||||||
|
|
||||||
class EquipmentListScreen extends React.Component<PropsType, StateType> {
|
class EquipmentListScreen extends React.Component<PropsType, StateType> {
|
||||||
userRents: null | Array<RentedDeviceType>;
|
data: Array<DeviceType>;
|
||||||
|
|
||||||
|
userRents: Array<RentedDeviceType>;
|
||||||
|
|
||||||
authRef: {current: null | AuthenticatedScreen};
|
authRef: {current: null | AuthenticatedScreen};
|
||||||
|
|
||||||
|
|
@ -77,13 +79,11 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> {
|
||||||
|
|
||||||
getUserDeviceRentDates(item: DeviceType): [number, number] | null {
|
getUserDeviceRentDates(item: DeviceType): [number, number] | null {
|
||||||
let dates = null;
|
let dates = null;
|
||||||
if (this.userRents != null) {
|
this.userRents.forEach((device: RentedDeviceType) => {
|
||||||
this.userRents.forEach((device: RentedDeviceType) => {
|
if (item.id === device.device_id) {
|
||||||
if (item.id === device.device_id) {
|
dates = [device.begin, device.end];
|
||||||
dates = [device.begin, device.end];
|
}
|
||||||
}
|
});
|
||||||
});
|
|
||||||
}
|
|
||||||
return dates;
|
return dates;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -123,14 +123,20 @@ class EquipmentListScreen extends React.Component<PropsType, StateType> {
|
||||||
* @returns {*}
|
* @returns {*}
|
||||||
*/
|
*/
|
||||||
getScreen = (data: Array<ApiGenericDataType | null>): React.Node => {
|
getScreen = (data: Array<ApiGenericDataType | null>): React.Node => {
|
||||||
const [allDevices, userRents] = data;
|
if (data[0] != null) {
|
||||||
if (userRents != null) this.userRents = userRents.locations;
|
const fetchedData = data[0];
|
||||||
|
if (fetchedData != null) this.data = fetchedData.devices;
|
||||||
|
}
|
||||||
|
if (data[1] != null) {
|
||||||
|
const fetchedData = data[1];
|
||||||
|
if (fetchedData != null) this.userRents = fetchedData.locations;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<CollapsibleFlatList
|
<CollapsibleFlatList
|
||||||
keyExtractor={this.keyExtractor}
|
keyExtractor={this.keyExtractor}
|
||||||
renderItem={this.getRenderItem}
|
renderItem={this.getRenderItem}
|
||||||
ListHeaderComponent={this.getListHeader()}
|
ListHeaderComponent={this.getListHeader()}
|
||||||
data={allDevices != null ? allDevices.devices : null}
|
data={this.data}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,7 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> {
|
||||||
end: getRelativeDateString(end),
|
end: getRelativeDateString(end),
|
||||||
});
|
});
|
||||||
else
|
else
|
||||||
subHeadingText = i18n.t('screens.equipment.bookingDay', {
|
i18n.t('screens.equipment.bookingDay', {
|
||||||
date: getRelativeDateString(start),
|
date: getRelativeDateString(start),
|
||||||
});
|
});
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
|
|
@ -408,7 +408,6 @@ class EquipmentRentScreen extends React.Component<PropsType, StateType> {
|
||||||
/>
|
/>
|
||||||
<Animatable.View
|
<Animatable.View
|
||||||
ref={this.bookRef}
|
ref={this.bookRef}
|
||||||
useNativeDriver
|
|
||||||
style={{
|
style={{
|
||||||
position: 'absolute',
|
position: 'absolute',
|
||||||
bottom: 0,
|
bottom: 0,
|
||||||
|
|
|
||||||
|
|
@ -25,10 +25,6 @@ import Mascot, {MASCOT_STYLE} from '../../components/Mascot/Mascot';
|
||||||
import ServicesManager, {SERVICES_KEY} from '../../managers/ServicesManager';
|
import ServicesManager, {SERVICES_KEY} from '../../managers/ServicesManager';
|
||||||
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
|
import CollapsibleFlatList from '../../components/Collapsible/CollapsibleFlatList';
|
||||||
import type {ServiceItemType} from '../../managers/ServicesManager';
|
import type {ServiceItemType} from '../../managers/ServicesManager';
|
||||||
import type {
|
|
||||||
CardTitleIconPropsType,
|
|
||||||
ListIconPropsType,
|
|
||||||
} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
navigation: StackNavigationProp,
|
navigation: StackNavigationProp,
|
||||||
|
|
@ -233,11 +229,11 @@ class ProfileScreen extends React.Component<PropsType, StateType> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={title}
|
title={title}
|
||||||
description={subtitle}
|
description={subtitle}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon
|
||||||
style={props.style}
|
size={size}
|
||||||
icon={icon}
|
icon={icon}
|
||||||
color={field != null ? props.color : theme.colors.textDisabled}
|
color={field != null ? null : theme.colors.textDisabled}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -256,9 +252,9 @@ class ProfileScreen extends React.Component<PropsType, StateType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={`${this.data.first_name} ${this.data.last_name}`}
|
title={`${this.data.first_name} ${this.data.last_name}`}
|
||||||
subtitle={this.data.email}
|
subtitle={this.data.email}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon
|
<Avatar.Icon
|
||||||
size={iconProps.size}
|
size={size}
|
||||||
icon="account"
|
icon="account"
|
||||||
color={theme.colors.primary}
|
color={theme.colors.primary}
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
|
|
@ -309,9 +305,9 @@ class ProfileScreen extends React.Component<PropsType, StateType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.profile.clubs')}
|
title={i18n.t('screens.profile.clubs')}
|
||||||
subtitle={i18n.t('screens.profile.clubsSubtitle')}
|
subtitle={i18n.t('screens.profile.clubsSubtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon
|
<Avatar.Icon
|
||||||
size={iconProps.size}
|
size={size}
|
||||||
icon="account-group"
|
icon="account-group"
|
||||||
color={theme.colors.primary}
|
color={theme.colors.primary}
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
|
|
@ -338,9 +334,9 @@ class ProfileScreen extends React.Component<PropsType, StateType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.profile.membership')}
|
title={i18n.t('screens.profile.membership')}
|
||||||
subtitle={i18n.t('screens.profile.membershipSubtitle')}
|
subtitle={i18n.t('screens.profile.membershipSubtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<Avatar.Icon
|
<Avatar.Icon
|
||||||
size={iconProps.size}
|
size={size}
|
||||||
icon="credit-card"
|
icon="credit-card"
|
||||||
color={theme.colors.primary}
|
color={theme.colors.primary}
|
||||||
style={styles.icon}
|
style={styles.icon}
|
||||||
|
|
@ -370,9 +366,9 @@ class ProfileScreen extends React.Component<PropsType, StateType> {
|
||||||
? i18n.t('screens.profile.membershipPayed')
|
? i18n.t('screens.profile.membershipPayed')
|
||||||
: i18n.t('screens.profile.membershipNotPayed')
|
: i18n.t('screens.profile.membershipNotPayed')
|
||||||
}
|
}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon
|
||||||
style={props.style}
|
size={size}
|
||||||
color={state ? theme.colors.success : theme.colors.danger}
|
color={state ? theme.colors.success : theme.colors.danger}
|
||||||
icon={state ? 'check' : 'close'}
|
icon={state ? 'check' : 'close'}
|
||||||
/>
|
/>
|
||||||
|
|
@ -393,17 +389,13 @@ class ProfileScreen extends React.Component<PropsType, StateType> {
|
||||||
this.openClubDetailsScreen(item.id);
|
this.openClubDetailsScreen(item.id);
|
||||||
};
|
};
|
||||||
let description = i18n.t('screens.profile.isMember');
|
let description = i18n.t('screens.profile.isMember');
|
||||||
let icon = (props: ListIconPropsType): React.Node => (
|
let icon = ({size, color}: {size: number, color: string}): React.Node => (
|
||||||
<List.Icon color={props.color} style={props.style} icon="chevron-right" />
|
<List.Icon size={size} color={color} icon="chevron-right" />
|
||||||
);
|
);
|
||||||
if (item.is_manager) {
|
if (item.is_manager) {
|
||||||
description = i18n.t('screens.profile.isManager');
|
description = i18n.t('screens.profile.isManager');
|
||||||
icon = (props: ListIconPropsType): React.Node => (
|
icon = ({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} icon="star" color={theme.colors.primary} />
|
||||||
style={props.style}
|
|
||||||
icon="star"
|
|
||||||
color={theme.colors.primary}
|
|
||||||
/>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
|
|
|
||||||
|
|
@ -84,7 +84,6 @@ class GameStartScreen extends React.Component<PropsType> {
|
||||||
const animDuration = 2 * (2000 - size * 30);
|
const animDuration = 2 * (2000 - size * 30);
|
||||||
return (
|
return (
|
||||||
<Animatable.View
|
<Animatable.View
|
||||||
useNativeDriver
|
|
||||||
animation="fadeInDownBig"
|
animation="fadeInDownBig"
|
||||||
delay={animDelay}
|
delay={animDelay}
|
||||||
duration={animDuration}
|
duration={animDuration}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ import i18n from 'i18n-js';
|
||||||
import {Linking} from 'react-native';
|
import {Linking} from 'react-native';
|
||||||
import type {CustomThemeType} from '../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../managers/ThemeManager';
|
||||||
import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView';
|
||||||
import type {CardTitleIconPropsType} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
theme: CustomThemeType,
|
theme: CustomThemeType,
|
||||||
|
|
@ -92,8 +91,14 @@ class FeedbackScreen extends React.Component<PropsType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.feedback.bugs')}
|
title={i18n.t('screens.feedback.bugs')}
|
||||||
subtitle={i18n.t('screens.feedback.bugsSubtitle')}
|
subtitle={i18n.t('screens.feedback.bugsSubtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="bug" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: number,
|
||||||
|
}): React.Node => (
|
||||||
|
<Avatar.Icon size={size} color={color} icon="bug" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
@ -109,8 +114,14 @@ class FeedbackScreen extends React.Component<PropsType> {
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.feedback.title')}
|
title={i18n.t('screens.feedback.title')}
|
||||||
subtitle={i18n.t('screens.feedback.feedbackSubtitle')}
|
subtitle={i18n.t('screens.feedback.feedbackSubtitle')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="comment" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: number,
|
||||||
|
}): React.Node => (
|
||||||
|
<Avatar.Icon size={size} color={color} icon="comment" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,6 @@ import ThemeManager from '../../../managers/ThemeManager';
|
||||||
import AsyncStorageManager from '../../../managers/AsyncStorageManager';
|
import AsyncStorageManager from '../../../managers/AsyncStorageManager';
|
||||||
import CustomSlider from '../../../components/Overrides/CustomSlider';
|
import CustomSlider from '../../../components/Overrides/CustomSlider';
|
||||||
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
||||||
import type {ListIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
type PropsType = {
|
type PropsType = {
|
||||||
navigation: StackNavigationProp,
|
navigation: StackNavigationProp,
|
||||||
|
|
@ -172,8 +171,8 @@ class SettingsScreen extends React.Component<PropsType, StateType> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={title}
|
title={title}
|
||||||
description={subtitle}
|
description={subtitle}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size, color}: {size: number, color: number}): React.Node => (
|
||||||
<List.Icon color={props.color} style={props.style} icon={icon} />
|
<List.Icon size={size} color={color} icon={icon} />
|
||||||
)}
|
)}
|
||||||
right={(): React.Node => (
|
right={(): React.Node => (
|
||||||
<Switch value={state} onValueChange={onPressCallback} />
|
<Switch value={state} onValueChange={onPressCallback} />
|
||||||
|
|
@ -197,15 +196,11 @@ class SettingsScreen extends React.Component<PropsType, StateType> {
|
||||||
onPress={() => {
|
onPress={() => {
|
||||||
navigation.navigate(route);
|
navigation.navigate(route);
|
||||||
}}
|
}}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size, color}: {size: number, color: number}): React.Node => (
|
||||||
<List.Icon color={props.color} style={props.style} icon={icon} />
|
<List.Icon size={size} color={color} icon={icon} />
|
||||||
)}
|
)}
|
||||||
right={(props: ListIconPropsType): React.Node => (
|
right={({size, color}: {size: number, color: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} color={color} icon="chevron-right" />
|
||||||
color={props.color}
|
|
||||||
style={props.style}
|
|
||||||
icon="chevron-right"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
onLongPress={onLongPress}
|
onLongPress={onLongPress}
|
||||||
/>
|
/>
|
||||||
|
|
@ -254,12 +249,14 @@ class SettingsScreen extends React.Component<PropsType, StateType> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={i18n.t('screens.settings.startScreen')}
|
title={i18n.t('screens.settings.startScreen')}
|
||||||
description={i18n.t('screens.settings.startScreenSub')}
|
description={i18n.t('screens.settings.startScreenSub')}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({
|
||||||
<List.Icon
|
size,
|
||||||
color={props.color}
|
color,
|
||||||
style={props.style}
|
}: {
|
||||||
icon="power"
|
size: number,
|
||||||
/>
|
color: number,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="power" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{this.getStartScreenPicker()}
|
{this.getStartScreenPicker()}
|
||||||
|
|
@ -277,12 +274,14 @@ class SettingsScreen extends React.Component<PropsType, StateType> {
|
||||||
<List.Item
|
<List.Item
|
||||||
title={i18n.t('screens.settings.proxiwashNotifReminder')}
|
title={i18n.t('screens.settings.proxiwashNotifReminder')}
|
||||||
description={i18n.t('screens.settings.proxiwashNotifReminderSub')}
|
description={i18n.t('screens.settings.proxiwashNotifReminderSub')}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({
|
||||||
<List.Icon
|
size,
|
||||||
color={props.color}
|
color,
|
||||||
style={props.style}
|
}: {
|
||||||
icon="washing-machine"
|
size: number,
|
||||||
/>
|
color: number,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="washing-machine" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<View style={{marginLeft: 30}}>
|
<View style={{marginLeft: 30}}>
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Image, View} from 'react-native';
|
import {Image, View} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import {Card, Avatar, Paragraph, Text, Title} from 'react-native-paper';
|
import {Card, List, Paragraph, Text, Title} from 'react-native-paper';
|
||||||
import CustomTabBar from '../../components/Tabbar/CustomTabBar';
|
import CustomTabBar from '../../components/Tabbar/CustomTabBar';
|
||||||
import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../components/Collapsible/CollapsibleScrollView';
|
||||||
import type {CardTitleIconPropsType} from '../../constants/PaperStyles';
|
|
||||||
|
|
||||||
const LOGO = 'https://etud.insa-toulouse.fr/~amicale_app/images/Proxiwash.png';
|
const LOGO = 'https://etud.insa-toulouse.fr/~amicale_app/images/Proxiwash.png';
|
||||||
|
|
||||||
|
|
@ -36,8 +35,14 @@ export default class ProxiwashAboutScreen extends React.Component<null> {
|
||||||
<Card style={{margin: 5}}>
|
<Card style={{margin: 5}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.proxiwash.dryer')}
|
title={i18n.t('screens.proxiwash.dryer')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="tumble-dryer" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="tumble-dryer" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
@ -51,8 +56,14 @@ export default class ProxiwashAboutScreen extends React.Component<null> {
|
||||||
<Card style={{margin: 5}}>
|
<Card style={{margin: 5}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.proxiwash.washer')}
|
title={i18n.t('screens.proxiwash.washer')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="washing-machine" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="washing-machine" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
@ -66,8 +77,14 @@ export default class ProxiwashAboutScreen extends React.Component<null> {
|
||||||
<Card style={{margin: 5}}>
|
<Card style={{margin: 5}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.proxiwash.tariffs')}
|
title={i18n.t('screens.proxiwash.tariffs')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="circle-multiple" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="circle-multiple" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
@ -79,8 +96,14 @@ export default class ProxiwashAboutScreen extends React.Component<null> {
|
||||||
style={{margin: 5, marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20}}>
|
style={{margin: 5, marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.proxiwash.paymentMethods')}
|
title={i18n.t('screens.proxiwash.paymentMethods')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="cash" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="cash" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -3,10 +3,9 @@
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {Image, View} from 'react-native';
|
import {Image, View} from 'react-native';
|
||||||
import i18n from 'i18n-js';
|
import i18n from 'i18n-js';
|
||||||
import {Card, Avatar, Paragraph, Text} from 'react-native-paper';
|
import {Card, List, Paragraph, Text} from 'react-native-paper';
|
||||||
import CustomTabBar from '../../../components/Tabbar/CustomTabBar';
|
import CustomTabBar from '../../../components/Tabbar/CustomTabBar';
|
||||||
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
import CollapsibleScrollView from '../../../components/Collapsible/CollapsibleScrollView';
|
||||||
import type {CardTitleIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
const LOGO = 'https://etud.insa-toulouse.fr/~amicale_app/images/Proximo.png';
|
const LOGO = 'https://etud.insa-toulouse.fr/~amicale_app/images/Proximo.png';
|
||||||
|
|
||||||
|
|
@ -36,8 +35,14 @@ export default class ProximoAboutScreen extends React.Component<null> {
|
||||||
<Card style={{margin: 5}}>
|
<Card style={{margin: 5}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.proximo.openingHours')}
|
title={i18n.t('screens.proximo.openingHours')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="clock-outline" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="clock-outline" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
@ -48,8 +53,14 @@ export default class ProximoAboutScreen extends React.Component<null> {
|
||||||
style={{margin: 5, marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20}}>
|
style={{margin: 5, marginBottom: CustomTabBar.TAB_BAR_HEIGHT + 20}}>
|
||||||
<Card.Title
|
<Card.Title
|
||||||
title={i18n.t('screens.proximo.paymentMethods')}
|
title={i18n.t('screens.proximo.paymentMethods')}
|
||||||
left={(iconProps: CardTitleIconPropsType): React.Node => (
|
left={({
|
||||||
<Avatar.Icon size={iconProps.size} icon="cash" />
|
size,
|
||||||
|
color,
|
||||||
|
}: {
|
||||||
|
size: number,
|
||||||
|
color: string,
|
||||||
|
}): React.Node => (
|
||||||
|
<List.Icon size={size} color={color} icon="cash" />
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
<Card.Content>
|
<Card.Content>
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ import MaterialHeaderButtons, {
|
||||||
} from '../../../components/Overrides/CustomHeaderButton';
|
} from '../../../components/Overrides/CustomHeaderButton';
|
||||||
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
import type {CustomThemeType} from '../../../managers/ThemeManager';
|
||||||
import type {SectionListDataType} from '../../../components/Screens/WebSectionList';
|
import type {SectionListDataType} from '../../../components/Screens/WebSectionList';
|
||||||
import type {ListIconPropsType} from '../../../constants/PaperStyles';
|
|
||||||
|
|
||||||
const DATA_URL = 'https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json';
|
const DATA_URL = 'https://etud.insa-toulouse.fr/~proximo/data/stock-v2.json';
|
||||||
const LIST_ITEM_HEIGHT = 84;
|
const LIST_ITEM_HEIGHT = 84;
|
||||||
|
|
@ -200,19 +199,15 @@ class ProximoMainScreen extends React.Component<PropsType> {
|
||||||
title={item.type.name}
|
title={item.type.name}
|
||||||
description={subtitle}
|
description={subtitle}
|
||||||
onPress={onPress}
|
onPress={onPress}
|
||||||
left={(props: ListIconPropsType): React.Node => (
|
left={({size}: {size: number}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon
|
||||||
style={props.style}
|
size={size}
|
||||||
icon={item.type.icon}
|
icon={item.type.icon}
|
||||||
color={theme.colors.primary}
|
color={theme.colors.primary}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
right={(props: ListIconPropsType): React.Node => (
|
right={({size, color}: {size: number, color: string}): React.Node => (
|
||||||
<List.Icon
|
<List.Icon size={size} color={color} icon="chevron-right" />
|
||||||
color={props.color}
|
|
||||||
style={props.style}
|
|
||||||
icon="chevron-right"
|
|
||||||
/>
|
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
height: LIST_ITEM_HEIGHT,
|
height: LIST_ITEM_HEIGHT,
|
||||||
|
|
|
||||||
|
|
@ -118,7 +118,9 @@ class ServicesScreen extends React.Component<PropsType> {
|
||||||
title={item.title}
|
title={item.title}
|
||||||
subtitle={item.subtitle}
|
subtitle={item.subtitle}
|
||||||
left={(): React.Node => this.getListTitleImage(item.image)}
|
left={(): React.Node => this.getListTitleImage(item.image)}
|
||||||
right={(): React.Node => <List.Icon icon="chevron-right" />}
|
right={({size}: {size: number}): React.Node => (
|
||||||
|
<List.Icon size={size} icon="chevron-right" />
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
<CardList dataset={item.content} isHorizontal />
|
<CardList dataset={item.content} isHorizontal />
|
||||||
</View>
|
</View>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue