Compare commits

..

No commits in common. "ff920b6ac6671cb1e79ba1d816fd4b539b894e43" and "f05a1dffb35d37e494707ecd9c72160f7111f8f9" have entirely different histories.

7 changed files with 167 additions and 206 deletions

View file

@ -418,11 +418,19 @@
}, },
"updateSlide0": { "updateSlide0": {
"title": "New in this update!", "title": "New in this update!",
"text": "Hello you! I'm here to help you around the app." "text": "Faster than ever and easier to use!\nThis update includes lots of changes to improve your experience.\nUse the brand new feedback button on the home screen to talk to the developer!"
}, },
"updateSlide1": { "updateSlide1": {
"title": "Contribute!", "title": "Improved Planex!",
"text": "Everyone is free to contribute to the project, from reporting bugs to implementing new features" "text": "You now have access to new controls, improved display, and you can also mark groups as favorites."
},
"updateSlide2": {
"title": "Scanotron 3000!",
"text": "Say hello to Scanotron 3000!\nAvailable from the Qr-Code button on the home screen, it will help you get information about clubs and events around the campus.\n(Useless right now but we have hope for next year)"
},
"updateSlide3": {
"title": "Amicale Account!",
"text": "You can now connect to your Amicale INSAT account from within the app! See all available clubs and more to come!\nClick on the login button from the home screen."
}, },
"aprilFoolsSlide": { "aprilFoolsSlide": {
"title": "New in this update!", "title": "New in this update!",

View file

@ -417,11 +417,19 @@
}, },
"updateSlide0": { "updateSlide0": {
"title": "Nouveau dans cette mise à jour !", "title": "Nouveau dans cette mise à jour !",
"text": "Coucou toi ! Je suis là pour t'aider trouver à utiliser l'appli." "text": "Plus rapide que jamais et plus simple à utiliser !\nCette mise à jour contient de nombreux changements pour améliorer votre expérience.\nUtilisez le tout nouveau bouton de Feedback pour parler directement au développeur!"
}, },
"updateSlide1": { "updateSlide1": {
"title": "Participe au projet !", "title": "Planex tout beau !",
"text": "Tout le monde peut participer, que ce soit pour trouver des bugs ou ajouter des nouvelles fonctionnalités." "text": "Vous avez maintenant accès à de nouveaux contrôles, un affichage amélioré, et vous pouvez marquer des groupes en favoris."
},
"updateSlide2": {
"title": "Scanotron 3000 !",
"text": "Dites bonjour à Scanotron 3000 !\nDisponible depuis le bouton Qr-Code sur le menu principal, il vous aidera à avoir des informations sur les clubs et les événements du campus.\n(Inutile tout de suite mais on verra l'année pro)"
},
"updateSlide3": {
"title": "Compte Amicale !",
"text": "Vous pouvez maintenant vous connecter à votre compte Amicale depuis l'appli ! Accédez à la liste des clubs et plus à venir !\nCliquez sur le bouton Se Connecter dans le menu principal."
}, },
"aprilFoolsSlide": { "aprilFoolsSlide": {
"title": "Nouveau dans cette mise à jour !", "title": "Nouveau dans cette mise à jour !",

View file

@ -1,41 +0,0 @@
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import * as Animatable from 'react-native-animatable';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
type PropsType = {
icon: string,
};
const styles = StyleSheet.create({
center: {
marginTop: 'auto',
marginBottom: 'auto',
marginRight: 'auto',
marginLeft: 'auto',
},
});
class IntroIcon extends React.Component<PropsType> {
shouldComponentUpdate(): boolean {
return false;
}
render(): React.Node {
const {icon} = this.props;
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;

View file

@ -1,46 +0,0 @@
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
const styles = StyleSheet.create({
center: {
marginTop: 'auto',
marginBottom: 'auto',
marginRight: 'auto',
marginLeft: 'auto',
},
});
class MascotIntroEnd extends React.Component<null> {
shouldComponentUpdate(): boolean {
return false;
}
render(): React.Node {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: '80%',
}}
emotion={MASCOT_STYLE.COOL}
animated
entryAnimation={{
animation: 'slideInDown',
duration: 2000,
}}
loopAnimation={{
animation: 'pulse',
duration: 2000,
iterationCount: 'infinite',
}}
/>
</View>
);
}
}
export default MascotIntroEnd;

View file

@ -1,76 +0,0 @@
// @flow
import * as React from 'react';
import {StyleSheet, View} from 'react-native';
import * as Animatable from 'react-native-animatable';
import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
const styles = StyleSheet.create({
center: {
marginTop: 'auto',
marginBottom: 'auto',
marginRight: 'auto',
marginLeft: 'auto',
},
});
class MascotIntroWelcome extends React.Component<null> {
shouldComponentUpdate(): boolean {
return false;
}
render(): React.Node {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: '80%',
}}
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={{
...styles.center,
transform: [{rotateZ: '70deg'}],
}}
name="undo"
color="#fff"
size={40}
/>
</Animatable.View>
</View>
);
}
}
export default MascotIntroWelcome;

View file

@ -2,6 +2,7 @@
import * as React from 'react'; import * as React from 'react';
import {Platform, StatusBar, StyleSheet, View} from 'react-native'; import {Platform, StatusBar, StyleSheet, View} from 'react-native';
import type {MaterialCommunityIconsGlyphs} from 'react-native-vector-icons/MaterialCommunityIcons';
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';
@ -11,9 +12,6 @@ import {Card} from 'react-native-paper';
import Update from '../../constants/Update'; import Update from '../../constants/Update';
import ThemeManager from '../../managers/ThemeManager'; import ThemeManager from '../../managers/ThemeManager';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot'; import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
import MascotIntroWelcome from '../Intro/MascotIntroWelcome';
import IntroIcon from '../Intro/IconIntro';
import MascotIntroEnd from '../Intro/MascotIntroEnd';
type PropsType = { type PropsType = {
onDone: () => void, onDone: () => void,
@ -25,12 +23,12 @@ type StateType = {
currentSlide: number, currentSlide: number,
}; };
export type IntroSlideType = { type IntroSlideType = {
key: string, key: string,
title: string, title: string,
text: string, text: string,
view: () => React.Node, view: () => React.Node,
mascotStyle?: number, mascotStyle: number,
colors: [string, string], colors: [string, string],
}; };
@ -90,14 +88,15 @@ 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: this.getWelcomeView,
mascotStyle: MASCOT_STYLE.NORMAL,
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: (): React.Node => CustomIntroSlider.getIconView('calendar-clock'),
mascotStyle: MASCOT_STYLE.INTELLO, mascotStyle: MASCOT_STYLE.INTELLO,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
@ -105,7 +104,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: (): React.Node => CustomIntroSlider.getIconView('calendar-star'),
mascotStyle: MASCOT_STYLE.HAPPY, mascotStyle: MASCOT_STYLE.HAPPY,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
@ -113,7 +112,8 @@ 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: (): React.Node =>
CustomIntroSlider.getIconView('view-dashboard-variant'),
mascotStyle: MASCOT_STYLE.CUTE, mascotStyle: MASCOT_STYLE.CUTE,
colors: ['#be1522', '#57080e'], colors: ['#be1522', '#57080e'],
}, },
@ -121,12 +121,22 @@ 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: (): React.Node => this.getEndView(),
mascotStyle: MASCOT_STYLE.COOL,
colors: ['#9c165b', '#3e042b'], colors: ['#9c165b', '#3e042b'],
}, },
]; ];
// $FlowFixMe
this.updateSlides = new Update().getUpdateSlides(); this.updateSlides = [];
for (let i = 0; i < Update.slidesNumber; i += 1) {
this.updateSlides.push({
key: i.toString(),
title: Update.getInstance().titleList[i],
text: Update.getInstance().descriptionList[i],
icon: Update.iconList[i],
colors: Update.colorsList[i],
});
}
this.aprilFoolsSlides = [ this.aprilFoolsSlides = [
{ {
@ -165,7 +175,7 @@ export default class CustomIntroSlider extends React.Component<
<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 useNativeDriver animation="fadeIn">
{item.mascotStyle != null ? ( {index !== 0 && index !== this.introSlides.length - 1 ? (
<Mascot <Mascot
style={{ style={{
marginLeft: 30, marginLeft: 30,
@ -234,6 +244,95 @@ export default class CustomIntroSlider extends React.Component<
); );
}; };
getEndView = (): React.Node => {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: '80%',
}}
emotion={MASCOT_STYLE.COOL}
animated
entryAnimation={{
animation: 'slideInDown',
duration: 2000,
}}
loopAnimation={{
animation: 'pulse',
duration: 2000,
iterationCount: 'infinite',
}}
/>
</View>
);
};
getWelcomeView = (): React.Node => {
return (
<View style={{flex: 1}}>
<Mascot
style={{
...styles.center,
height: '80%',
}}
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={{
...styles.center,
transform: [{rotateZ: '70deg'}],
}}
name="undo"
color="#fff"
size={40}
/>
</Animatable.View>
</View>
);
};
static getIconView(icon: MaterialCommunityIconsGlyphs): React.Node {
return (
<View style={{flex: 1}}>
<Animatable.View
useNativeDriver
style={styles.center}
animation="fadeIn">
<MaterialCommunityIcons name={icon} color="#fff" size={200} />
</Animatable.View>
</View>
);
}
static setStatusBarColor(color: string) { static setStatusBarColor(color: string) {
if (Platform.OS === 'android') StatusBar.setBackgroundColor(color, true); if (Platform.OS === 'android') StatusBar.setBackgroundColor(color, true);
} }

View file

@ -1,10 +1,6 @@
// @flow // @flow
import * as React from 'react';
import i18n from 'i18n-js'; import i18n from 'i18n-js';
import type {IntroSlideType} from '../components/Overrides/CustomIntroSlider';
import MascotIntroWelcome from '../components/Intro/MascotIntroWelcome';
import IntroIcon from '../components/Intro/IconIntro';
/** /**
* Singleton used to manage update slides. * Singleton used to manage update slides.
@ -19,33 +15,46 @@ import IntroIcon from '../components/Intro/IconIntro';
*/ */
export default class Update { export default class Update {
// Increment the number to show the update slide // Increment the number to show the update slide
static number = 7; static number = 6;
updateSlides: Array<IntroSlideType>; // Change the number of slides to display
static slidesNumber = 4;
// Change the icons to be displayed on the update slide
static iconList = ['star', 'clock', 'qrcode-scan', 'account'];
static colorsList = [
['#e01928', '#be1522'],
['#7c33ec', '#5e11d1'],
['#337aec', '#114ed1'],
['#e01928', '#be1522'],
];
static instance: Update | null = null;
titleList: Array<string>;
descriptionList: Array<string>;
/** /**
* Init translations * Init translations
*/ */
constructor() { constructor() {
this.updateSlides = [ this.titleList = [];
{ this.descriptionList = [];
key: '0', for (let i = 0; i < Update.slidesNumber; i += 1) {
title: i18n.t(`intro.updateSlide0.title`), this.titleList.push(i18n.t(`intro.updateSlide${i}.title`));
text: i18n.t(`intro.updateSlide0.text`), this.descriptionList.push(i18n.t(`intro.updateSlide${i}.text`));
view: (): React.Node => <MascotIntroWelcome />, }
colors: ['#be1522', '#57080e'],
},
{
key: '1',
title: i18n.t(`intro.updateSlide1.title`),
text: i18n.t(`intro.updateSlide1.text`),
view: (): React.Node => <IntroIcon icon="account-heart-outline" />,
colors: ['#9c165b', '#3e042b'],
},
];
} }
getUpdateSlides(): Array<IntroSlideType> { /**
return this.updateSlides; * Get this class instance or create one if none is found
*
* @returns {Update}
*/
static getInstance(): Update {
if (Update.instance == null) Update.instance = new Update();
return Update.instance;
} }
} }