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.

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<null, StateType> {
  54. navigatorRef: {current: null | NavigationContainerRef};
  55. defaultHomeRoute: string | null;
  56. defaultHomeData: {[key: string]: string};
  57. urlHandler: URLHandler;
  58. constructor() {
  59. super(null);
  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().finally(() => {
  75. this.onLoadFinished();
  76. });
  77. }
  78. /**
  79. * The app has been started by an url, and it has been parsed.
  80. * Set a new default start route based on the data parsed.
  81. *
  82. * @param parsedData The data parsed from the url
  83. */
  84. onInitialURLParsed = (parsedData: ParsedUrlDataType) => {
  85. this.defaultHomeRoute = parsedData.route;
  86. this.defaultHomeData = parsedData.data;
  87. };
  88. /**
  89. * An url has been opened and parsed while the app was active.
  90. * Redirect the user to the screen according to parsed data.
  91. *
  92. * @param parsedData The data parsed from the url
  93. */
  94. onDetectURL = (parsedData: ParsedUrlDataType) => {
  95. // Navigate to nested navigator and pass data to the index screen
  96. const nav = this.navigatorRef.current;
  97. if (nav != null) {
  98. nav.navigate('home', {
  99. screen: 'index',
  100. params: {nextScreen: parsedData.route, data: parsedData.data},
  101. });
  102. }
  103. };
  104. /**
  105. * Updates the current theme
  106. */
  107. onUpdateTheme = () => {
  108. this.setState({
  109. currentTheme: ThemeManager.getCurrentTheme(),
  110. });
  111. setupStatusBar();
  112. };
  113. /**
  114. * Callback when user ends the intro. Save in preferences to avoid showing back the introSlides
  115. */
  116. onIntroDone = () => {
  117. this.setState({
  118. showIntro: false,
  119. showUpdate: false,
  120. showAprilFools: false,
  121. });
  122. AsyncStorageManager.set(
  123. AsyncStorageManager.PREFERENCES.showIntro.key,
  124. false,
  125. );
  126. AsyncStorageManager.set(
  127. AsyncStorageManager.PREFERENCES.updateNumber.key,
  128. Update.number,
  129. );
  130. AsyncStorageManager.set(
  131. AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key,
  132. false,
  133. );
  134. };
  135. /**
  136. * Async loading is done, finish processing startup data
  137. */
  138. onLoadFinished() {
  139. // Only show intro if this is the first time starting the app
  140. ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
  141. // Status bar goes dark if set too fast on ios
  142. if (Platform.OS === 'ios') {
  143. setTimeout(setupStatusBar, 1000);
  144. } else {
  145. setupStatusBar();
  146. }
  147. this.setState({
  148. isLoading: false,
  149. currentTheme: ThemeManager.getCurrentTheme(),
  150. showIntro: AsyncStorageManager.getBool(
  151. AsyncStorageManager.PREFERENCES.showIntro.key,
  152. ),
  153. showUpdate:
  154. AsyncStorageManager.getNumber(
  155. AsyncStorageManager.PREFERENCES.updateNumber.key,
  156. ) !== Update.number,
  157. showAprilFools:
  158. AprilFoolsManager.getInstance().isAprilFoolsEnabled() &&
  159. AsyncStorageManager.getBool(
  160. AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key,
  161. ),
  162. });
  163. SplashScreen.hide();
  164. }
  165. /**
  166. * Loads every async data
  167. *
  168. * @returns {Promise<void>}
  169. */
  170. loadAssetsAsync = async () => {
  171. await AsyncStorageManager.getInstance().loadPreferences();
  172. await ConnectionManager.getInstance()
  173. .recoverLogin()
  174. .catch(() => {});
  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. }