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.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  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 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. import GENERAL_STYLES from './src/constants/Styles';
  39. import CollapsibleProvider from './src/components/providers/CollapsibleProvider';
  40. import CacheProvider from './src/components/providers/CacheProvider';
  41. // Native optimizations https://reactnavigation.org/docs/react-native-screens
  42. // Crashes app when navigating away from webview on android 9+
  43. // enableScreens(true);
  44. LogBox.ignoreLogs([
  45. // collapsible headers cause this warning, just ignore as it is not an issue
  46. 'Non-serializable values were found in the navigation state',
  47. 'Cannot update a component from inside the function body of a different component',
  48. ]);
  49. type StateType = {
  50. isLoading: boolean;
  51. showIntro: boolean;
  52. showUpdate: boolean;
  53. showAprilFools: boolean;
  54. currentTheme: ReactNativePaper.Theme | undefined;
  55. };
  56. export default class App extends React.Component<{}, StateType> {
  57. navigatorRef: { current: null | NavigationContainerRef };
  58. defaultHomeRoute: string | null;
  59. defaultHomeData: { [key: string]: string };
  60. urlHandler: URLHandler;
  61. constructor(props: {}) {
  62. super(props);
  63. this.state = {
  64. isLoading: true,
  65. showIntro: true,
  66. showUpdate: true,
  67. showAprilFools: false,
  68. currentTheme: undefined,
  69. };
  70. initLocales();
  71. this.navigatorRef = React.createRef();
  72. this.defaultHomeRoute = null;
  73. this.defaultHomeData = {};
  74. this.urlHandler = new URLHandler(this.onInitialURLParsed, this.onDetectURL);
  75. this.urlHandler.listen();
  76. setSafeBounceHeight(Platform.OS === 'ios' ? 100 : 20);
  77. this.loadAssetsAsync();
  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') {
  144. setTimeout(setupStatusBar, 1000);
  145. } else {
  146. setupStatusBar();
  147. }
  148. this.setState({
  149. isLoading: false,
  150. currentTheme: ThemeManager.getCurrentTheme(),
  151. showIntro: AsyncStorageManager.getBool(
  152. AsyncStorageManager.PREFERENCES.showIntro.key
  153. ),
  154. showUpdate:
  155. AsyncStorageManager.getNumber(
  156. AsyncStorageManager.PREFERENCES.updateNumber.key
  157. ) !== Update.number,
  158. showAprilFools:
  159. AprilFoolsManager.getInstance().isAprilFoolsEnabled() &&
  160. AsyncStorageManager.getBool(
  161. AsyncStorageManager.PREFERENCES.showAprilFoolsStart.key
  162. ),
  163. });
  164. SplashScreen.hide();
  165. };
  166. /**
  167. * Loads every async data
  168. *
  169. * @returns {Promise<void>}
  170. */
  171. loadAssetsAsync() {
  172. Promise.all([
  173. AsyncStorageManager.getInstance().loadPreferences(),
  174. ConnectionManager.getInstance().recoverLogin(),
  175. ])
  176. .then(this.onLoadFinished)
  177. .catch(this.onLoadFinished);
  178. }
  179. /**
  180. * Renders the app based on loading state
  181. */
  182. render() {
  183. const { state } = this;
  184. if (state.isLoading) {
  185. return null;
  186. }
  187. if (state.showIntro || state.showUpdate || state.showAprilFools) {
  188. return (
  189. <CustomIntroSlider
  190. onDone={this.onIntroDone}
  191. isUpdate={state.showUpdate && !state.showIntro}
  192. isAprilFools={state.showAprilFools && !state.showIntro}
  193. />
  194. );
  195. }
  196. return (
  197. <PaperProvider theme={state.currentTheme}>
  198. <CollapsibleProvider>
  199. <CacheProvider>
  200. <OverflowMenuProvider>
  201. <View
  202. style={{
  203. backgroundColor: ThemeManager.getCurrentTheme().colors
  204. .background,
  205. ...GENERAL_STYLES.flex,
  206. }}
  207. >
  208. <SafeAreaView style={GENERAL_STYLES.flex}>
  209. <NavigationContainer
  210. theme={state.currentTheme}
  211. ref={this.navigatorRef}
  212. >
  213. <MainNavigator
  214. defaultHomeRoute={this.defaultHomeRoute}
  215. defaultHomeData={this.defaultHomeData}
  216. />
  217. </NavigationContainer>
  218. </SafeAreaView>
  219. </View>
  220. </OverflowMenuProvider>
  221. </CacheProvider>
  222. </CollapsibleProvider>
  223. </PaperProvider>
  224. );
  225. }
  226. }