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.tsx 7.2KB

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