Update component overrides and intro slides to use TypeScript

This commit is contained in:
Arnaud Vergnet 2020-09-22 14:26:44 +02:00
parent 18f8c64302
commit acc4f8cdcc
14 changed files with 370 additions and 420 deletions

17
package-lock.json generated
View file

@ -2608,6 +2608,17 @@
"@types/react": "*" "@types/react": "*"
} }
}, },
"@types/react-native-calendars": {
"version": "1.20.10",
"resolved": "https://registry.npmjs.org/@types/react-native-calendars/-/react-native-calendars-1.20.10.tgz",
"integrity": "sha512-bmWlkFa/6SNF98aM9rjKMGUOSDb15VBsfxBW5oo/iJ5tm5THf+eAGlxH72hGZFqJpr93plBs+ctkRVHQA7fx1w==",
"dev": true,
"requires": {
"@types/react": "*",
"@types/react-native": "*",
"@types/xdate": "*"
}
},
"@types/react-native-vector-icons": { "@types/react-native-vector-icons": {
"version": "6.4.6", "version": "6.4.6",
"resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.6.tgz", "resolved": "https://registry.npmjs.org/@types/react-native-vector-icons/-/react-native-vector-icons-6.4.6.tgz",
@ -2632,6 +2643,12 @@
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz",
"integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==" "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw=="
}, },
"@types/xdate": {
"version": "0.8.31",
"resolved": "https://registry.npmjs.org/@types/xdate/-/xdate-0.8.31.tgz",
"integrity": "sha512-iZYRKKK8UZXoepNh2kwK6TPITMj/dwdv0NzNi9DFMt2foGkU7h+ncaCpGsdD2fp/CXMs9dxPAzV9uddFy7c4QA==",
"dev": true
},
"@types/yargs": { "@types/yargs": {
"version": "15.0.5", "version": "15.0.5",
"resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz",

View file

@ -67,9 +67,10 @@
"@babel/runtime": "^7.11.0", "@babel/runtime": "^7.11.0",
"@react-native-community/eslint-config": "^1.1.0", "@react-native-community/eslint-config": "^1.1.0",
"@types/i18n-js": "^3.0.3", "@types/i18n-js": "^3.0.3",
"@types/react-native-vector-icons": "^6.4.6",
"@types/jest": "^25.2.3", "@types/jest": "^25.2.3",
"@types/react-native": "^0.63.2", "@types/react-native": "^0.63.2",
"@types/react-native-calendars": "^1.20.10",
"@types/react-native-vector-icons": "^6.4.6",
"@types/react-test-renderer": "^16.9.2", "@types/react-test-renderer": "^16.9.2",
"@typescript-eslint/eslint-plugin": "^2.27.0", "@typescript-eslint/eslint-plugin": "^2.27.0",
"@typescript-eslint/parser": "^2.27.0", "@typescript-eslint/parser": "^2.27.0",

View file

@ -17,15 +17,13 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {StyleSheet, View} from 'react-native'; import {StyleSheet, View} from 'react-native';
import * as Animatable from 'react-native-animatable'; import * as Animatable from 'react-native-animatable';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
type PropsType = { type PropsType = {
icon: string, icon: string;
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
@ -37,24 +35,14 @@ const styles = StyleSheet.create({
}, },
}); });
class IntroIcon extends React.Component<PropsType> { function IntroIcon(props: PropsType) {
shouldComponentUpdate(): boolean { return (
return false; <View style={{flex: 1}}>
} <Animatable.View useNativeDriver style={styles.center} animation="fadeIn">
<MaterialCommunityIcons name={props.icon} color="#fff" size={200} />
render(): React.Node { </Animatable.View>
const {icon} = this.props; </View>
return ( );
<View style={{flex: 1}}>
<Animatable.View
useNativeDriver
style={styles.center}
animation="fadeIn">
<MaterialCommunityIcons name={icon} color="#fff" size={200} />
</Animatable.View>
</View>
);
}
} }
export default IntroIcon; export default IntroIcon;

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {StyleSheet, View} from 'react-native'; import {StyleSheet, View} from 'react-native';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot'; import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
@ -32,34 +30,28 @@ const styles = StyleSheet.create({
}, },
}); });
class MascotIntroEnd extends React.Component<null> { function MascotIntroEnd() {
shouldComponentUpdate(): boolean { return (
return false; <View style={{flex: 1}}>
} <Mascot
style={{
render(): React.Node { ...styles.center,
return ( width: '80%',
<View style={{flex: 1}}> }}
<Mascot emotion={MASCOT_STYLE.COOL}
style={{ animated
...styles.center, entryAnimation={{
width: '80%', animation: 'slideInDown',
}} duration: 2000,
emotion={MASCOT_STYLE.COOL} }}
animated loopAnimation={{
entryAnimation={{ animation: 'pulse',
animation: 'slideInDown', duration: 2000,
duration: 2000, iterationCount: 'infinite',
}} }}
loopAnimation={{ />
animation: 'pulse', </View>
duration: 2000, );
iterationCount: 'infinite',
}}
/>
</View>
);
}
} }
export default MascotIntroEnd; export default MascotIntroEnd;

View file

@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {StyleSheet, View} from 'react-native'; import {StyleSheet, View} from 'react-native';
import * as Animatable from 'react-native-animatable'; import * as Animatable from 'react-native-animatable';
@ -34,62 +32,56 @@ const styles = StyleSheet.create({
}, },
}); });
class MascotIntroWelcome extends React.Component<null> { function MascotIntroWelcome() {
shouldComponentUpdate(): boolean { return (
return false; <View style={{flex: 1}}>
} <Mascot
style={{
render(): React.Node { ...styles.center,
return ( width: '80%',
<View style={{flex: 1}}> }}
<Mascot emotion={MASCOT_STYLE.NORMAL}
animated
entryAnimation={{
animation: 'bounceIn',
duration: 2000,
}}
/>
<Animatable.Text
useNativeDriver
animation="fadeInUp"
duration={500}
style={{
color: '#fff',
textAlign: 'center',
fontSize: 25,
}}>
PABLO
</Animatable.Text>
<Animatable.View
useNativeDriver
animation="fadeInUp"
duration={500}
delay={200}
style={{
position: 'absolute',
bottom: 30,
right: '20%',
width: 50,
height: 50,
}}>
<MaterialCommunityIcons
style={{ style={{
...styles.center, ...styles.center,
width: '80%', transform: [{rotateZ: '70deg'}],
}}
emotion={MASCOT_STYLE.NORMAL}
animated
entryAnimation={{
animation: 'bounceIn',
duration: 2000,
}} }}
name="undo"
color="#fff"
size={40}
/> />
<Animatable.Text </Animatable.View>
useNativeDriver </View>
animation="fadeInUp" );
duration={500}
style={{
color: '#fff',
textAlign: 'center',
fontSize: 25,
}}>
PABLO
</Animatable.Text>
<Animatable.View
useNativeDriver
animation="fadeInUp"
duration={500}
delay={200}
style={{
position: 'absolute',
bottom: 30,
right: '20%',
width: 50,
height: 50,
}}>
<MaterialCommunityIcons
style={{
...styles.center,
transform: [{rotateZ: '70deg'}],
}}
name="undo"
color="#fff"
size={40}
/>
</Animatable.View>
</View>
);
}
} }
export default MascotIntroWelcome; export default MascotIntroWelcome;

View file

@ -1,82 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {View} from 'react-native';
import {withTheme} from 'react-native-paper';
import {Agenda} from 'react-native-calendars';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomThemeType,
onRef: (ref: Agenda) => void,
};
/**
* Abstraction layer for Agenda component, using custom configuration
*/
class CustomAgenda extends React.Component<PropsType> {
getAgenda(): React.Node {
const {props} = this;
return (
<Agenda
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
ref={props.onRef}
theme={{
backgroundColor: props.theme.colors.agendaBackgroundColor,
calendarBackground: props.theme.colors.background,
textSectionTitleColor: props.theme.colors.agendaDayTextColor,
selectedDayBackgroundColor: props.theme.colors.primary,
selectedDayTextColor: '#ffffff',
todayTextColor: props.theme.colors.primary,
dayTextColor: props.theme.colors.text,
textDisabledColor: props.theme.colors.agendaDayTextColor,
dotColor: props.theme.colors.primary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: props.theme.colors.primary,
indicatorColor: props.theme.colors.primary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: props.theme.colors.agendaDayTextColor,
agendaDayNumColor: props.theme.colors.agendaDayTextColor,
agendaTodayColor: props.theme.colors.primary,
agendaKnobColor: props.theme.colors.primary,
}}
/>
);
}
render(): React.Node {
const {props} = this;
// Completely recreate the component on theme change to force theme reload
if (props.theme.dark)
return <View style={{flex: 1}}>{this.getAgenda()}</View>;
return this.getAgenda();
}
}
export default withTheme(CustomAgenda);

View file

@ -0,0 +1,75 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import {View} from 'react-native';
import {useTheme} from 'react-native-paper';
import {Agenda, AgendaProps} from 'react-native-calendars';
type PropsType = {
onRef: (ref: Agenda<any>) => void;
} & AgendaProps<any>;
/**
* Abstraction layer for Agenda component, using custom configuration
*/
function CustomAgenda(props: PropsType) {
const theme = useTheme();
function getAgenda() {
return (
<Agenda
{...props}
ref={props.onRef}
theme={{
backgroundColor: theme.colors.agendaBackgroundColor,
calendarBackground: theme.colors.background,
textSectionTitleColor: theme.colors.agendaDayTextColor,
selectedDayBackgroundColor: theme.colors.primary,
selectedDayTextColor: '#ffffff',
todayTextColor: theme.colors.primary,
dayTextColor: theme.colors.text,
textDisabledColor: theme.colors.agendaDayTextColor,
dotColor: theme.colors.primary,
selectedDotColor: '#ffffff',
arrowColor: 'orange',
monthTextColor: theme.colors.primary,
indicatorColor: theme.colors.primary,
textDayFontWeight: '300',
textMonthFontWeight: 'bold',
textDayHeaderFontWeight: '300',
textDayFontSize: 16,
textMonthFontSize: 16,
textDayHeaderFontSize: 16,
agendaDayTextColor: theme.colors.agendaDayTextColor,
agendaDayNumColor: theme.colors.agendaDayTextColor,
agendaTodayColor: theme.colors.primary,
agendaKnobColor: theme.colors.primary,
}}
/>
);
}
// Completely recreate the component on theme change to force theme reload
if (theme.dark) {
return <View style={{flex: 1}}>{getAgenda()}</View>;
}
return getAgenda();
}
export default CustomAgenda;

View file

@ -1,77 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
/* eslint-disable flowtype/require-parameter-type */
// @flow
import * as React from 'react';
import {Text, withTheme} from 'react-native-paper';
import HTML from 'react-native-render-html';
import {Linking} from 'react-native';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomThemeType,
html: string,
};
/**
* Abstraction layer for Agenda component, using custom configuration
*/
class CustomHTML extends React.Component<PropsType> {
openWebLink = (event: {...}, link: string) => {
Linking.openURL(link);
};
getBasicText = (
htmlAttribs,
children,
convertedCSSStyles,
passProps,
): React.Node => {
// eslint-disable-next-line react/jsx-props-no-spreading
return <Text {...passProps}>{children}</Text>;
};
getListBullet = (): React.Node => {
return <Text>- </Text>;
};
render(): React.Node {
const {props} = this;
// Surround description with p to allow text styling if the description is not html
return (
<HTML
html={`<p>${props.html}</p>`}
renderers={{
p: this.getBasicText,
li: this.getBasicText,
}}
listsPrefixesRenderers={{
ul: this.getListBullet,
}}
ignoredTags={['img']}
ignoredStyles={['color', 'background-color']}
onLinkPress={this.openWebLink}
/>
);
}
}
export default withTheme(CustomHTML);

View file

@ -0,0 +1,68 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import {Text} from 'react-native-paper';
import HTML from 'react-native-render-html';
import {GestureResponderEvent, Linking} from 'react-native';
type PropsType = {
html: string;
};
/**
* Abstraction layer for Agenda component, using custom configuration
*/
function CustomHTML(props: PropsType) {
const openWebLink = (event: GestureResponderEvent, link: string) => {
Linking.openURL(link);
};
const getBasicText = (
htmlAttribs: any,
children: any,
convertedCSSStyles: any,
passProps: any,
) => {
return <Text {...passProps}>{children}</Text>;
};
const getListBullet = () => {
return <Text>- </Text>;
};
// Surround description with p to allow text styling if the description is not html
return (
<HTML
html={`<p>${props.html}</p>`}
renderers={{
p: getBasicText,
li: getBasicText,
}}
listsPrefixesRenderers={{
ul: getListBullet,
}}
ignoredTags={['img']}
ignoredStyles={['color', 'background-color']}
onLinkPress={openWebLink}
/>
);
}
export default CustomHTML;

View file

@ -17,39 +17,31 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import {HeaderButton, HeaderButtons} from 'react-navigation-header-buttons'; import {
import {withTheme} from 'react-native-paper'; HeaderButton,
import type {CustomThemeType} from '../../managers/ThemeManager'; HeaderButtonProps,
HeaderButtons,
HeaderButtonsProps,
} from 'react-navigation-header-buttons';
import {useTheme} from 'react-native-paper';
const MaterialHeaderButton = (props: { const MaterialHeaderButton = (props: HeaderButtonProps) => {
theme: CustomThemeType, const theme = useTheme();
color: string,
}): React.Node => {
const {color, theme} = props;
return ( return (
// $FlowFixMe
<HeaderButton <HeaderButton
// eslint-disable-next-line react/jsx-props-no-spreading
{...props} {...props}
IconComponent={MaterialCommunityIcons} IconComponent={MaterialCommunityIcons}
iconSize={26} iconSize={26}
color={color != null ? color : theme.colors.text} color={props.color ? props.color : theme.colors.text}
/> />
); );
}; };
const MaterialHeaderButtons = (props: {...}): React.Node => { const MaterialHeaderButtons = (props: HeaderButtonsProps) => {
return ( return (
// $FlowFixMe <HeaderButtons {...props} HeaderButtonComponent={MaterialHeaderButton} />
<HeaderButtons
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
HeaderButtonComponent={withTheme(MaterialHeaderButton)}
/>
); );
}; };

View file

@ -17,10 +17,14 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {Platform, StatusBar, StyleSheet, View} from 'react-native'; import {
ListRenderItemInfo,
Platform,
StatusBar,
StyleSheet,
View,
} from 'react-native';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons'; import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import AppIntroSlider from 'react-native-app-intro-slider'; import AppIntroSlider from 'react-native-app-intro-slider';
@ -35,26 +39,27 @@ import IntroIcon from '../Intro/IconIntro';
import MascotIntroEnd from '../Intro/MascotIntroEnd'; import MascotIntroEnd from '../Intro/MascotIntroEnd';
type PropsType = { type PropsType = {
onDone: () => void, onDone: () => void;
isUpdate: boolean, isUpdate: boolean;
isAprilFools: boolean, isAprilFools: boolean;
}; };
type StateType = { type StateType = {
currentSlide: number, currentSlide: number;
}; };
export type IntroSlideType = { export type IntroSlideType = {
key: string, key: string;
title: string, title: string;
text: string, text: string;
view: () => React.Node, view: () => React.ReactNode;
mascotStyle?: number, mascotStyle?: number;
colors: [string, string], colors: [string, string];
}; };
const styles = StyleSheet.create({ const styles = StyleSheet.create({
mainContent: { mainContent: {
flex: 1,
paddingBottom: 100, paddingBottom: 100,
}, },
text: { text: {
@ -83,7 +88,7 @@ const styles = StyleSheet.create({
*/ */
export default class CustomIntroSlider extends React.Component< export default class CustomIntroSlider extends React.Component<
PropsType, PropsType,
StateType, StateType
> { > {
sliderRef: {current: null | AppIntroSlider}; sliderRef: {current: null | AppIntroSlider};
@ -98,8 +103,9 @@ export default class CustomIntroSlider extends React.Component<
/** /**
* Generates intro slides * Generates intro slides
*/ */
constructor() { constructor(props: PropsType) {
super(); super(props);
this.currentSlides = [];
this.state = { this.state = {
currentSlide: 0, currentSlide: 0,
}; };
@ -109,14 +115,14 @@ export default class CustomIntroSlider extends React.Component<
key: '0', // Mascot key: '0', // Mascot
title: i18n.t('intro.slideMain.title'), title: i18n.t('intro.slideMain.title'),
text: i18n.t('intro.slideMain.text'), text: i18n.t('intro.slideMain.text'),
view: (): React.Node => <MascotIntroWelcome />, view: () => <MascotIntroWelcome />,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
{ {
key: '1', key: '1',
title: i18n.t('intro.slidePlanex.title'), title: i18n.t('intro.slidePlanex.title'),
text: i18n.t('intro.slidePlanex.text'), text: i18n.t('intro.slidePlanex.text'),
view: (): React.Node => <IntroIcon icon="calendar-clock" />, view: () => <IntroIcon icon="calendar-clock" />,
mascotStyle: MASCOT_STYLE.INTELLO, mascotStyle: MASCOT_STYLE.INTELLO,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
@ -124,7 +130,7 @@ export default class CustomIntroSlider extends React.Component<
key: '2', key: '2',
title: i18n.t('intro.slideEvents.title'), title: i18n.t('intro.slideEvents.title'),
text: i18n.t('intro.slideEvents.text'), text: i18n.t('intro.slideEvents.text'),
view: (): React.Node => <IntroIcon icon="calendar-star" />, view: () => <IntroIcon icon="calendar-star" />,
mascotStyle: MASCOT_STYLE.HAPPY, mascotStyle: MASCOT_STYLE.HAPPY,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
@ -132,7 +138,7 @@ export default class CustomIntroSlider extends React.Component<
key: '3', key: '3',
title: i18n.t('intro.slideServices.title'), title: i18n.t('intro.slideServices.title'),
text: i18n.t('intro.slideServices.text'), text: i18n.t('intro.slideServices.text'),
view: (): React.Node => <IntroIcon icon="view-dashboard-variant" />, view: () => <IntroIcon icon="view-dashboard-variant" />,
mascotStyle: MASCOT_STYLE.CUTE, mascotStyle: MASCOT_STYLE.CUTE,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
@ -140,7 +146,7 @@ export default class CustomIntroSlider extends React.Component<
key: '4', key: '4',
title: i18n.t('intro.slideDone.title'), title: i18n.t('intro.slideDone.title'),
text: i18n.t('intro.slideDone.text'), text: i18n.t('intro.slideDone.text'),
view: (): React.Node => <MascotIntroEnd />, view: () => <MascotIntroEnd />,
colors: ['#9c165b', '#3e042b'], colors: ['#9c165b', '#3e042b'],
}, },
]; ];
@ -152,7 +158,7 @@ export default class CustomIntroSlider extends React.Component<
key: '1', key: '1',
title: i18n.t('intro.aprilFoolsSlide.title'), title: i18n.t('intro.aprilFoolsSlide.title'),
text: i18n.t('intro.aprilFoolsSlide.text'), text: i18n.t('intro.aprilFoolsSlide.text'),
view: (): React.Node => <View />, view: () => <View />,
mascotStyle: MASCOT_STYLE.NORMAL, mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#e01928', '#be1522'], colors: ['#e01928', '#be1522'],
}, },
@ -162,21 +168,21 @@ export default class CustomIntroSlider extends React.Component<
/** /**
* Render item to be used for the intro introSlides * Render item to be used for the intro introSlides
* *
* @param item The item to be displayed * @param data
* @param dimensions Dimensions of the item
*/ */
getIntroRenderItem = ({ getIntroRenderItem = (
item, data:
dimensions, | (ListRenderItemInfo<IntroSlideType> & {
}: { dimensions: {width: number; height: number};
item: IntroSlideType, })
dimensions: {width: number, height: number}, | ListRenderItemInfo<IntroSlideType>,
}): React.Node => { ) => {
const item = data.item;
const {state} = this; const {state} = this;
const index = parseInt(item.key, 10); const index = parseInt(item.key, 10);
return ( return (
<LinearGradient <LinearGradient
style={[styles.mainContent, dimensions]} style={[styles.mainContent]}
colors={item.colors} colors={item.colors}
start={{x: 0, y: 0.1}} start={{x: 0, y: 0.1}}
end={{x: 0.1, y: 1}}> end={{x: 0.1, y: 1}}>
@ -254,7 +260,9 @@ export default class CustomIntroSlider extends React.Component<
}; };
static setStatusBarColor(color: string) { static setStatusBarColor(color: string) {
if (Platform.OS === 'android') StatusBar.setBackgroundColor(color, true); if (Platform.OS === 'android') {
StatusBar.setBackgroundColor(color, true);
}
} }
onSlideChange = (index: number) => { onSlideChange = (index: number) => {
@ -266,8 +274,9 @@ export default class CustomIntroSlider extends React.Component<
CustomIntroSlider.setStatusBarColor( CustomIntroSlider.setStatusBarColor(
this.currentSlides[this.currentSlides.length - 1].colors[0], this.currentSlides[this.currentSlides.length - 1].colors[0],
); );
if (this.sliderRef.current != null) if (this.sliderRef.current != null) {
this.sliderRef.current.goToSlide(this.currentSlides.length - 1); this.sliderRef.current.goToSlide(this.currentSlides.length - 1);
}
}; };
onDone = () => { onDone = () => {
@ -278,7 +287,7 @@ export default class CustomIntroSlider extends React.Component<
props.onDone(); props.onDone();
}; };
getRenderNextButton = (): React.Node => { getRenderNextButton = () => {
return ( return (
<Animatable.View <Animatable.View
useNativeDriver useNativeDriver
@ -293,7 +302,7 @@ export default class CustomIntroSlider extends React.Component<
); );
}; };
getRenderDoneButton = (): React.Node => { getRenderDoneButton = () => {
return ( return (
<Animatable.View <Animatable.View
useNativeDriver useNativeDriver
@ -308,11 +317,14 @@ export default class CustomIntroSlider extends React.Component<
); );
}; };
render(): React.Node { render() {
const {props, state} = this; const {props, state} = this;
this.currentSlides = this.introSlides; this.currentSlides = this.introSlides;
if (props.isUpdate) this.currentSlides = this.updateSlides; if (props.isUpdate) {
else if (props.isAprilFools) this.currentSlides = this.aprilFoolsSlides; this.currentSlides = this.updateSlides;
} else if (props.isAprilFools) {
this.currentSlides = this.aprilFoolsSlides;
}
CustomIntroSlider.setStatusBarColor(this.currentSlides[0].colors[0]); CustomIntroSlider.setStatusBarColor(this.currentSlides[0].colors[0]);
return ( return (
<AppIntroSlider <AppIntroSlider

View file

@ -17,14 +17,11 @@
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/ */
// @flow
import * as React from 'react'; import * as React from 'react';
import {withTheme} from 'react-native-paper'; import {useTheme} from 'react-native-paper';
import {Modalize} from 'react-native-modalize'; import {Modalize} from 'react-native-modalize';
import {View} from 'react-native-animatable'; import {View} from 'react-native-animatable';
import CustomTabBar from '../Tabbar/CustomTabBar'; import CustomTabBar from '../Tabbar/CustomTabBar';
import type {CustomThemeType} from '../../managers/ThemeManager';
/** /**
* Abstraction layer for Modalize component, using custom configuration * Abstraction layer for Modalize component, using custom configuration
@ -33,11 +30,11 @@ import type {CustomThemeType} from '../../managers/ThemeManager';
* @return {*} * @return {*}
*/ */
function CustomModal(props: { function CustomModal(props: {
theme: CustomThemeType, onRef: (re: Modalize) => void;
onRef: (re: Modalize) => void, children?: React.ReactNode;
children?: React.Node, }) {
}): React.Node { const theme = useTheme();
const {theme, onRef, children} = props; const {onRef, children} = props;
return ( return (
<Modalize <Modalize
ref={onRef} ref={onRef}
@ -55,6 +52,4 @@ function CustomModal(props: {
); );
} }
CustomModal.defaultProps = {children: null}; export default CustomModal;
export default withTheme(CustomModal);

View file

@ -1,84 +0,0 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
// @flow
import * as React from 'react';
import {Text, withTheme} from 'react-native-paper';
import {View} from 'react-native-animatable';
import Slider, {SliderProps} from '@react-native-community/slider';
import type {CustomThemeType} from '../../managers/ThemeManager';
type PropsType = {
theme: CustomThemeType,
valueSuffix?: string,
...SliderProps,
};
type StateType = {
currentValue: number,
};
/**
* Abstraction layer for Modalize component, using custom configuration
*
* @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref.
* @return {*}
*/
class CustomSlider extends React.Component<PropsType, StateType> {
static defaultProps = {
valueSuffix: '',
};
constructor(props: PropsType) {
super(props);
this.state = {
currentValue: props.value,
};
}
onValueChange = (value: number) => {
const {props} = this;
this.setState({currentValue: value});
if (props.onValueChange != null) props.onValueChange(value);
};
render(): React.Node {
const {props, state} = this;
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<Text
style={{
marginHorizontal: 10,
marginTop: 'auto',
marginBottom: 'auto',
}}>
{state.currentValue}min
</Text>
<Slider
// eslint-disable-next-line react/jsx-props-no-spreading
{...props}
onValueChange={this.onValueChange}
/>
</View>
);
}
}
export default withTheme(CustomSlider);

View file

@ -0,0 +1,61 @@
/*
* Copyright (c) 2019 - 2020 Arnaud Vergnet.
*
* This file is part of Campus INSAT.
*
* Campus INSAT is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Campus INSAT is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
*/
import * as React from 'react';
import {Text} from 'react-native-paper';
import {View} from 'react-native-animatable';
import Slider, {SliderProps} from '@react-native-community/slider';
import {useState} from 'react';
type PropsType = {
valueSuffix?: string;
} & SliderProps;
/**
* Abstraction layer for Modalize component, using custom configuration
*
* @param props Props to pass to the element. Must specify an onRef prop to get an Modalize ref.
* @return {*}
*/
function CustomSlider(props: PropsType) {
const [currentValue, setCurrentValue] = useState(props.value);
const onValueChange = (value: number) => {
setCurrentValue(value);
if (props.onValueChange) {
props.onValueChange(value);
}
};
return (
<View style={{flex: 1, flexDirection: 'row'}}>
<Text
style={{
marginHorizontal: 10,
marginTop: 'auto',
marginBottom: 'auto',
}}>
{currentValue}min
</Text>
<Slider {...props} ref={undefined} onValueChange={onValueChange} />
</View>
);
}
export default CustomSlider;