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": {
"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": {
"title": "Contribute!",
"text": "Everyone is free to contribute to the project, from reporting bugs to implementing new features"
"title": "Improved Planex!",
"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": {
"title": "New in this update!",

View file

@ -417,11 +417,19 @@
},
"updateSlide0": {
"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": {
"title": "Participe au projet !",
"text": "Tout le monde peut participer, que ce soit pour trouver des bugs ou ajouter des nouvelles fonctionnalités."
"title": "Planex tout beau !",
"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": {
"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 {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 i18n from 'i18n-js';
import AppIntroSlider from 'react-native-app-intro-slider';
@ -11,9 +12,6 @@ import {Card} from 'react-native-paper';
import Update from '../../constants/Update';
import ThemeManager from '../../managers/ThemeManager';
import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
import MascotIntroWelcome from '../Intro/MascotIntroWelcome';
import IntroIcon from '../Intro/IconIntro';
import MascotIntroEnd from '../Intro/MascotIntroEnd';
type PropsType = {
onDone: () => void,
@ -25,12 +23,12 @@ type StateType = {
currentSlide: number,
};
export type IntroSlideType = {
type IntroSlideType = {
key: string,
title: string,
text: string,
view: () => React.Node,
mascotStyle?: number,
mascotStyle: number,
colors: [string, string],
};
@ -90,14 +88,15 @@ export default class CustomIntroSlider extends React.Component<
key: '0', // Mascot
title: i18n.t('intro.slideMain.title'),
text: i18n.t('intro.slideMain.text'),
view: (): React.Node => <MascotIntroWelcome />,
view: this.getWelcomeView,
mascotStyle: MASCOT_STYLE.NORMAL,
colors: ['#be1522', '#57080e'],
},
{
key: '1',
title: i18n.t('intro.slidePlanex.title'),
text: i18n.t('intro.slidePlanex.text'),
view: (): React.Node => <IntroIcon icon="calendar-clock" />,
view: (): React.Node => CustomIntroSlider.getIconView('calendar-clock'),
mascotStyle: MASCOT_STYLE.INTELLO,
colors: ['#be1522', '#57080e'],
},
@ -105,7 +104,7 @@ export default class CustomIntroSlider extends React.Component<
key: '2',
title: i18n.t('intro.slideEvents.title'),
text: i18n.t('intro.slideEvents.text'),
view: (): React.Node => <IntroIcon icon="calendar-star" />,
view: (): React.Node => CustomIntroSlider.getIconView('calendar-star'),
mascotStyle: MASCOT_STYLE.HAPPY,
colors: ['#be1522', '#57080e'],
},
@ -113,7 +112,8 @@ export default class CustomIntroSlider extends React.Component<
key: '3',
title: i18n.t('intro.slideServices.title'),
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,
colors: ['#be1522', '#57080e'],
},
@ -121,12 +121,22 @@ export default class CustomIntroSlider extends React.Component<
key: '4',
title: i18n.t('intro.slideDone.title'),
text: i18n.t('intro.slideDone.text'),
view: (): React.Node => <MascotIntroEnd />,
view: (): React.Node => this.getEndView(),
mascotStyle: MASCOT_STYLE.COOL,
colors: ['#9c165b', '#3e042b'],
},
];
this.updateSlides = new Update().getUpdateSlides();
// $FlowFixMe
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 = [
{
@ -165,7 +175,7 @@ export default class CustomIntroSlider extends React.Component<
<View style={{height: '100%', flex: 1}}>
<View style={{flex: 1}}>{item.view()}</View>
<Animatable.View useNativeDriver animation="fadeIn">
{item.mascotStyle != null ? (
{index !== 0 && index !== this.introSlides.length - 1 ? (
<Mascot
style={{
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) {
if (Platform.OS === 'android') StatusBar.setBackgroundColor(color, true);
}

View file

@ -1,10 +1,6 @@
// @flow
import * as React from 'react';
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.
@ -19,33 +15,46 @@ import IntroIcon from '../components/Intro/IconIntro';
*/
export default class Update {
// 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
*/
constructor() {
this.updateSlides = [
{
key: '0',
title: i18n.t(`intro.updateSlide0.title`),
text: i18n.t(`intro.updateSlide0.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'],
},
];
this.titleList = [];
this.descriptionList = [];
for (let i = 0; i < Update.slidesNumber; i += 1) {
this.titleList.push(i18n.t(`intro.updateSlide${i}.title`));
this.descriptionList.push(i18n.t(`intro.updateSlide${i}.text`));
}
}
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;
}
}