Application Android et IOS pour l'amicale des élèves https://play.google.com/store/apps/details?id=fr.amicaleinsat.application
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.js 8.7KB

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