Application Android et IOS pour l'amicale des élèves
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CustomIntroSlider.tsx 9.5KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. * Copyright (c) 2019 - 2020 Arnaud Vergnet.
  3. *
  4. * This file is part of Campus INSAT.
  5. *
  6. * Campus INSAT is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * Campus INSAT is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. import * as React from 'react';
  20. import {
  21. ListRenderItemInfo,
  22. Platform,
  23. StatusBar,
  24. StyleSheet,
  25. View,
  26. } from 'react-native';
  27. import MaterialCommunityIcons from 'react-native-vector-icons/MaterialCommunityIcons';
  28. import i18n from 'i18n-js';
  29. import AppIntroSlider from 'react-native-app-intro-slider';
  30. import LinearGradient from 'react-native-linear-gradient';
  31. import * as Animatable from 'react-native-animatable';
  32. import {Card} from 'react-native-paper';
  33. import Update from '../../constants/Update';
  34. import ThemeManager from '../../managers/ThemeManager';
  35. import Mascot, {MASCOT_STYLE} from '../Mascot/Mascot';
  36. import MascotIntroWelcome from '../Intro/MascotIntroWelcome';
  37. import IntroIcon from '../Intro/IconIntro';
  38. import MascotIntroEnd from '../Intro/MascotIntroEnd';
  39. type PropsType = {
  40. onDone: () => void;
  41. isUpdate: boolean;
  42. isAprilFools: boolean;
  43. };
  44. type StateType = {
  45. currentSlide: number;
  46. };
  47. export type IntroSlideType = {
  48. key: string;
  49. title: string;
  50. text: string;
  51. view: () => React.ReactNode;
  52. mascotStyle?: number;
  53. colors: [string, string];
  54. };
  55. const styles = StyleSheet.create({
  56. mainContent: {
  57. flex: 1,
  58. paddingBottom: 100,
  59. },
  60. text: {
  61. color: 'rgba(255, 255, 255, 0.8)',
  62. backgroundColor: 'transparent',
  63. textAlign: 'center',
  64. paddingHorizontal: 16,
  65. },
  66. title: {
  67. fontSize: 22,
  68. color: 'white',
  69. backgroundColor: 'transparent',
  70. textAlign: 'center',
  71. marginBottom: 16,
  72. },
  73. center: {
  74. marginTop: 'auto',
  75. marginBottom: 'auto',
  76. marginRight: 'auto',
  77. marginLeft: 'auto',
  78. },
  79. });
  80. /**
  81. * Class used to create intro slides
  82. */
  83. export default class CustomIntroSlider extends React.Component<
  84. PropsType,
  85. StateType
  86. > {
  87. sliderRef: {current: null | AppIntroSlider};
  88. introSlides: Array<IntroSlideType>;
  89. updateSlides: Array<IntroSlideType>;
  90. aprilFoolsSlides: Array<IntroSlideType>;
  91. currentSlides: Array<IntroSlideType>;
  92. /**
  93. * Generates intro slides
  94. */
  95. constructor(props: PropsType) {
  96. super(props);
  97. this.currentSlides = [];
  98. this.state = {
  99. currentSlide: 0,
  100. };
  101. this.sliderRef = React.createRef();
  102. this.introSlides = [
  103. {
  104. key: '0', // Mascot
  105. title: i18n.t('intro.slideMain.title'),
  106. text: i18n.t('intro.slideMain.text'),
  107. view: () => <MascotIntroWelcome />,
  108. colors: ['#be1522', '#57080e'],
  109. },
  110. {
  111. key: '1',
  112. title: i18n.t('intro.slidePlanex.title'),
  113. text: i18n.t('intro.slidePlanex.text'),
  114. view: () => <IntroIcon icon="calendar-clock" />,
  115. mascotStyle: MASCOT_STYLE.INTELLO,
  116. colors: ['#be1522', '#57080e'],
  117. },
  118. {
  119. key: '2',
  120. title: i18n.t('intro.slideEvents.title'),
  121. text: i18n.t('intro.slideEvents.text'),
  122. view: () => <IntroIcon icon="calendar-star" />,
  123. mascotStyle: MASCOT_STYLE.HAPPY,
  124. colors: ['#be1522', '#57080e'],
  125. },
  126. {
  127. key: '3',
  128. title: i18n.t('intro.slideServices.title'),
  129. text: i18n.t('intro.slideServices.text'),
  130. view: () => <IntroIcon icon="view-dashboard-variant" />,
  131. mascotStyle: MASCOT_STYLE.CUTE,
  132. colors: ['#be1522', '#57080e'],
  133. },
  134. {
  135. key: '4',
  136. title: i18n.t('intro.slideDone.title'),
  137. text: i18n.t('intro.slideDone.text'),
  138. view: () => <MascotIntroEnd />,
  139. colors: ['#9c165b', '#3e042b'],
  140. },
  141. ];
  142. this.updateSlides = new Update().getUpdateSlides();
  143. this.aprilFoolsSlides = [
  144. {
  145. key: '1',
  146. title: i18n.t('intro.aprilFoolsSlide.title'),
  147. text: i18n.t('intro.aprilFoolsSlide.text'),
  148. view: () => <View />,
  149. mascotStyle: MASCOT_STYLE.NORMAL,
  150. colors: ['#e01928', '#be1522'],
  151. },
  152. ];
  153. }
  154. /**
  155. * Render item to be used for the intro introSlides
  156. *
  157. * @param data
  158. */
  159. getIntroRenderItem = (
  160. data:
  161. | (ListRenderItemInfo<IntroSlideType> & {
  162. dimensions: {width: number; height: number};
  163. })
  164. | ListRenderItemInfo<IntroSlideType>,
  165. ) => {
  166. const item = data.item;
  167. const {state} = this;
  168. const index = parseInt(item.key, 10);
  169. return (
  170. <LinearGradient
  171. style={[styles.mainContent]}
  172. colors={item.colors}
  173. start={{x: 0, y: 0.1}}
  174. end={{x: 0.1, y: 1}}>
  175. {state.currentSlide === index ? (
  176. <View style={{height: '100%', flex: 1}}>
  177. <View style={{flex: 1}}>{item.view()}</View>
  178. <Animatable.View useNativeDriver animation="fadeIn">
  179. {item.mascotStyle != null ? (
  180. <Mascot
  181. style={{
  182. marginLeft: 30,
  183. marginBottom: 0,
  184. width: 100,
  185. marginTop: -30,
  186. }}
  187. emotion={item.mascotStyle}
  188. animated
  189. entryAnimation={{
  190. animation: 'slideInLeft',
  191. duration: 500,
  192. }}
  193. loopAnimation={{
  194. animation: 'pulse',
  195. iterationCount: 'infinite',
  196. duration: 2000,
  197. }}
  198. />
  199. ) : null}
  200. <View
  201. style={{
  202. marginLeft: 50,
  203. width: 0,
  204. height: 0,
  205. borderLeftWidth: 20,
  206. borderRightWidth: 0,
  207. borderBottomWidth: 20,
  208. borderStyle: 'solid',
  209. backgroundColor: 'transparent',
  210. borderLeftColor: 'transparent',
  211. borderRightColor: 'transparent',
  212. borderBottomColor: 'rgba(0,0,0,0.60)',
  213. }}
  214. />
  215. <Card
  216. style={{
  217. backgroundColor: 'rgba(0,0,0,0.38)',
  218. marginHorizontal: 20,
  219. borderColor: 'rgba(0,0,0,0.60)',
  220. borderWidth: 4,
  221. borderRadius: 10,
  222. elevation: 0,
  223. }}>
  224. <Card.Content>
  225. <Animatable.Text
  226. useNativeDriver
  227. animation="fadeIn"
  228. delay={100}
  229. style={styles.title}>
  230. {item.title}
  231. </Animatable.Text>
  232. <Animatable.Text
  233. useNativeDriver
  234. animation="fadeIn"
  235. delay={200}
  236. style={styles.text}>
  237. {item.text}
  238. </Animatable.Text>
  239. </Card.Content>
  240. </Card>
  241. </Animatable.View>
  242. </View>
  243. ) : null}
  244. </LinearGradient>
  245. );
  246. };
  247. static setStatusBarColor(color: string) {
  248. if (Platform.OS === 'android') {
  249. StatusBar.setBackgroundColor(color, true);
  250. }
  251. }
  252. onSlideChange = (index: number) => {
  253. CustomIntroSlider.setStatusBarColor(this.currentSlides[index].colors[0]);
  254. this.setState({currentSlide: index});
  255. };
  256. onSkip = () => {
  257. CustomIntroSlider.setStatusBarColor(
  258. this.currentSlides[this.currentSlides.length - 1].colors[0],
  259. );
  260. if (this.sliderRef.current != null) {
  261. this.sliderRef.current.goToSlide(this.currentSlides.length - 1);
  262. }
  263. };
  264. onDone = () => {
  265. const {props} = this;
  266. CustomIntroSlider.setStatusBarColor(
  267. ThemeManager.getCurrentTheme().colors.surface,
  268. );
  269. props.onDone();
  270. };
  271. getRenderNextButton = () => {
  272. return (
  273. <Animatable.View
  274. useNativeDriver
  275. animation="fadeIn"
  276. style={{
  277. borderRadius: 25,
  278. padding: 5,
  279. backgroundColor: 'rgba(0,0,0,0.2)',
  280. }}>
  281. <MaterialCommunityIcons name="arrow-right" color="#fff" size={40} />
  282. </Animatable.View>
  283. );
  284. };
  285. getRenderDoneButton = () => {
  286. return (
  287. <Animatable.View
  288. useNativeDriver
  289. animation="bounceIn"
  290. style={{
  291. borderRadius: 25,
  292. padding: 5,
  293. backgroundColor: 'rgb(190,21,34)',
  294. }}>
  295. <MaterialCommunityIcons name="check" color="#fff" size={40} />
  296. </Animatable.View>
  297. );
  298. };
  299. render() {
  300. const {props, state} = this;
  301. this.currentSlides = this.introSlides;
  302. if (props.isUpdate) {
  303. this.currentSlides = this.updateSlides;
  304. } else if (props.isAprilFools) {
  305. this.currentSlides = this.aprilFoolsSlides;
  306. }
  307. CustomIntroSlider.setStatusBarColor(this.currentSlides[0].colors[0]);
  308. return (
  309. <AppIntroSlider
  310. ref={this.sliderRef}
  311. data={this.currentSlides}
  312. extraData={state.currentSlide}
  313. renderItem={this.getIntroRenderItem}
  314. renderNextButton={this.getRenderNextButton}
  315. renderDoneButton={this.getRenderDoneButton}
  316. onDone={this.onDone}
  317. onSlideChange={this.onSlideChange}
  318. onSkip={this.onSkip}
  319. />
  320. );
  321. }
  322. }