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.

App.js 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  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. // @flow
  20. import * as React from 'react';
  21. import {LogBox, Platform, SafeAreaView, View} from 'react-native';
  22. import {NavigationContainer} from '@react-navigation/native';
  23. import {Provider as PaperProvider} from 'react-native-paper';
  24. import {setSafeBounceHeight} from 'react-navigation-collapsible';
  25. import SplashScreen from 'react-native-splash-screen';
  26. import {OverflowMenuProvider} from 'react-navigation-header-buttons';
  27. import AsyncStorageManager from './src/managers/AsyncStorageManager';
  28. import CustomIntroSlider from './src/components/Overrides/CustomIntroSlider';
  29. import type {CustomThemeType} from './src/managers/ThemeManager';
  30. import ThemeManager from './src/managers/ThemeManager';
  31. import MainNavigator from './src/navigation/MainNavigator';
  32. import AprilFoolsManager from './src/managers/AprilFoolsManager';
  33. import Update from './src/constants/Update';
  34. import ConnectionManager from './src/managers/ConnectionManager';
  35. import type {ParsedUrlDataType} from './src/utils/URLHandler';
  36. import URLHandler from './src/utils/URLHandler';
  37. import {setupStatusBar} from './src/utils/Utils';
  38. import initLocales from './src/utils/Locales';
  39. // Native optimizations https://reactnavigation.org/docs/react-native-screens
  40. // Crashes app when navigating away from webview on android 9+
  41. // enableScreens(true);
  42. LogBox.ignoreLogs([
  43. // collapsible headers cause this warning, just ignore as it is not an issue
  44. 'Non-serializable values were found in the navigation state',
  45. 'Cannot update a component from inside the function body of a different component',
  46. ]);
  47. type StateType = {
  48. isLoading: boolean,
  49. showIntro: boolean,
  50. showUpdate: boolean,
  51. showAprilFools: boolean,
  52. currentTheme: CustomThemeType | null,
  53. };
  54. export default class App extends React.Component<null, StateType> {
  55. navigatorRef: {current: null | NavigationContainer};
  56. defaultHomeRoute: string | null;
  57. defaultHomeData: {[key: string]: string};
  58. urlHandler: URLHandler;
  59. constructor() {
  60. super();
  61. this.state = {
  62. isLoading: true,
  63. showIntro: true,
  64. showUpdate: true,
  65. showAprilFools: false,
  66. currentTheme: null,
  67. };
  68. initLocales();
  69. this.navigatorRef = React.createRef();
  70. this.defaultHomeRoute = null;
  71. this.defaultHomeData = {};
  72. this.urlHandler = new URLHandler(this.onInitialURLParsed, this.onDetectURL);
  73. this.urlHandler.listen();
  74. setSafeBounceHeight(Platform.OS === 'ios' ? 100 : 20);
  75. this.loadAssetsAsync().finally(() => {
  76. this.onLoadFinished();
  77. });
  78. }
  79. /**
  80. * The app has been started by an url, and it has been parsed.
  81. * Set a new default start route based on the data parsed.
  82. *
  83. * @param parsedData The data parsed from the url
  84. */
  85. onInitialURLParsed = (parsedData: ParsedUrlDataType) => {
  86. this.defaultHomeRoute = parsedData.route;
  87. this.defaultHomeData = parsedData.data;
  88. };
  89. /**
  90. * An url has been opened and parsed while the app was active.
  91. * Redirect the user to the screen according to parsed data.
  92. *
  93. * @param parsedData The data parsed from the url
  94. */
  95. onDetectURL = (parsedData: ParsedUrlDataType) => {
  96. // Navigate to nested navigator and pass data to the index screen
  97. const nav = this.navigatorRef.current;
  98. if (nav != null) {
  99. nav.navigate('home', {
  100. screen: 'index',
  101. params: {nextScreen: parsedData.route, data: parsedData.data},
  102. });
  103. }
  104. };
  105. /**
  106. * Updates the current theme
  107. */
  108. onUpdateTheme = () => {
  109. this.setState({
  110. currentTheme: ThemeManager.getCurrentTheme(),
  111. });
  112. setupStatusBar();
  113. };
  114. /**
  115. * Callback when user ends the intro. Save in preferences to avoid showing back the introSlides
  116. */
  117. onIntroDone = () => {
  118. this.setState({
  119. showIntro: false,
  120. showUpdate: false,
  121. showAprilFools: false,
  122. });
  123. AsyncStorageManager.set(
  124. AsyncStorageManager.PREFERENCES.showIntro.key,
  125. false,
  126. );
  127. AsyncStorageManager.set(
  128. AsyncStorageManager.PREFERENCES.updateNumber.key,
  129. Update.number,
  130. );
  131. AsyncStorageManager.set(
  132. AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key,
  133. false,
  134. );
  135. };
  136. /**
  137. * Async loading is done, finish processing startup data
  138. */
  139. onLoadFinished() {
  140. // Only show intro if this is the first time starting the app
  141. ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
  142. // Status bar goes dark if set too fast on ios
  143. if (Platform.OS === 'ios') setTimeout(setupStatusBar, 1000);
  144. else setupStatusBar();
  145. this.setState({
  146. isLoading: false,
  147. currentTheme: ThemeManager.getCurrentTheme(),
  148. showIntro: AsyncStorageManager.getBool(
  149. AsyncStorageManager.PREFERENCES.showIntro.key,
  150. ),
  151. showUpdate:
  152. AsyncStorageManager.getNumber(
  153. AsyncStorageManager.PREFERENCES.updateNumber.key,
  154. ) !== Update.number,
  155. showAprilFools:
  156. AprilFoolsManager.getInstance().isAprilFoolsEnabled() &&
  157. AsyncStorageManager.getBool(
  158. AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key,
  159. ),
  160. });
  161. SplashScreen.hide();
  162. }
  163. /**
  164. * Loads every async data
  165. *
  166. * @returns {Promise<void>}
  167. */
  168. loadAssetsAsync = async () => {
  169. await AsyncStorageManager.getInstance().loadPreferences();
  170. await ConnectionManager.getInstance()
  171. .recoverLogin()
  172. .catch(() => {});
  173. };
  174. /**
  175. * Renders the app based on loading state
  176. */
  177. render(): React.Node {
  178. const {state} = this;
  179. if (state.isLoading) {
  180. return null;
  181. }
  182. if (state.showIntro || state.showUpdate || state.showAprilFools) {
  183. return (
  184. <CustomIntroSlider
  185. onDone={this.onIntroDone}
  186. isUpdate={state.showUpdate && !state.showIntro}
  187. isAprilFools={state.showAprilFools && !state.showIntro}
  188. />
  189. );
  190. }
  191. return (
  192. <PaperProvider theme={state.currentTheme}>
  193. <OverflowMenuProvider>
  194. <View
  195. style={{
  196. backgroundColor: ThemeManager.getCurrentTheme().colors.background,
  197. flex: 1,
  198. }}>
  199. <SafeAreaView style={{flex: 1}}>
  200. <NavigationContainer
  201. theme={state.currentTheme}
  202. ref={this.navigatorRef}>
  203. <MainNavigator
  204. defaultHomeRoute={this.defaultHomeRoute}
  205. defaultHomeData={this.defaultHomeData}
  206. />
  207. </NavigationContainer>
  208. </SafeAreaView>
  209. </View>
  210. </OverflowMenuProvider>
  211. </PaperProvider>
  212. );
  213. }
  214. }