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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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. // Native optimizations https://reactnavigation.org/docs/react-native-screens
  41. // Crashes app when navigating away from webview on android 9+
  42. // enableScreens(true);
  43. LogBox.ignoreLogs([
  44. // collapsible headers cause this warning, just ignore as it is not an issue
  45. 'Non-serializable values were found in the navigation state',
  46. 'Cannot update a component from inside the function body of a different component',
  47. ]);
  48. type StateType = {
  49. isLoading: boolean;
  50. showIntro: boolean;
  51. showUpdate: boolean;
  52. showAprilFools: boolean;
  53. currentTheme: ReactNativePaper.Theme | undefined;
  54. };
  55. export default class App extends React.Component<{}, StateType> {
  56. navigatorRef: { current: null | NavigationContainerRef };
  57. defaultHomeRoute: string | null;
  58. defaultHomeData: { [key: string]: string };
  59. urlHandler: URLHandler;
  60. constructor(props: {}) {
  61. super(props);
  62. this.state = {
  63. isLoading: true,
  64. showIntro: true,
  65. showUpdate: true,
  66. showAprilFools: false,
  67. currentTheme: undefined,
  68. };
  69. initLocales();
  70. this.navigatorRef = React.createRef();
  71. this.defaultHomeRoute = null;
  72. this.defaultHomeData = {};
  73. this.urlHandler = new URLHandler(this.onInitialURLParsed, this.onDetectURL);
  74. this.urlHandler.listen();
  75. setSafeBounceHeight(Platform.OS === 'ios' ? 100 : 20);
  76. this.loadAssetsAsync();
  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() {
  171. Promise.all([
  172. AsyncStorageManager.getInstance().loadPreferences(),
  173. ConnectionManager.getInstance().recoverLogin(),
  174. ])
  175. .then(this.onLoadFinished)
  176. .catch(this.onLoadFinished);
  177. }
  178. /**
  179. * Renders the app based on loading state
  180. */
  181. render() {
  182. const { state } = this;
  183. if (state.isLoading) {
  184. return null;
  185. }
  186. if (state.showIntro || state.showUpdate || state.showAprilFools) {
  187. return (
  188. <CustomIntroSlider
  189. onDone={this.onIntroDone}
  190. isUpdate={state.showUpdate && !state.showIntro}
  191. isAprilFools={state.showAprilFools && !state.showIntro}
  192. />
  193. );
  194. }
  195. return (
  196. <PaperProvider theme={state.currentTheme}>
  197. <CollapsibleProvider>
  198. <OverflowMenuProvider>
  199. <View
  200. style={{
  201. backgroundColor: ThemeManager.getCurrentTheme().colors
  202. .background,
  203. ...GENERAL_STYLES.flex,
  204. }}
  205. >
  206. <SafeAreaView style={GENERAL_STYLES.flex}>
  207. <NavigationContainer
  208. theme={state.currentTheme}
  209. ref={this.navigatorRef}
  210. >
  211. <MainNavigator
  212. defaultHomeRoute={this.defaultHomeRoute}
  213. defaultHomeData={this.defaultHomeData}
  214. />
  215. </NavigationContainer>
  216. </SafeAreaView>
  217. </View>
  218. </OverflowMenuProvider>
  219. </CollapsibleProvider>
  220. </PaperProvider>
  221. );
  222. }
  223. }