Browse Source

Update App.tsx and related files to use TypeScript

Arnaud Vergnet 1 year ago
parent
commit
375fc8b971
4 changed files with 334 additions and 341 deletions
  1. 15
    14
      App.tsx
  2. 21
    20
      src/managers/AsyncStorageManager.ts
  3. 0
    307
      src/managers/ThemeManager.js
  4. 298
    0
      src/managers/ThemeManager.ts

App.js → App.tsx View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import * as React from 'react';
23 21
 import {LogBox, Platform, SafeAreaView, View} from 'react-native';
24 22
 import {NavigationContainer} from '@react-navigation/native';
@@ -28,7 +26,6 @@ import SplashScreen from 'react-native-splash-screen';
28 26
 import {OverflowMenuProvider} from 'react-navigation-header-buttons';
29 27
 import AsyncStorageManager from './src/managers/AsyncStorageManager';
30 28
 import CustomIntroSlider from './src/components/Overrides/CustomIntroSlider';
31
-import type {CustomThemeType} from './src/managers/ThemeManager';
32 29
 import ThemeManager from './src/managers/ThemeManager';
33 30
 import MainNavigator from './src/navigation/MainNavigator';
34 31
 import AprilFoolsManager from './src/managers/AprilFoolsManager';
@@ -38,6 +35,7 @@ import type {ParsedUrlDataType} from './src/utils/URLHandler';
38 35
 import URLHandler from './src/utils/URLHandler';
39 36
 import {setupStatusBar} from './src/utils/Utils';
40 37
 import initLocales from './src/utils/Locales';
38
+import {NavigationContainerRef} from '@react-navigation/core';
41 39
 
42 40
 // Native optimizations https://reactnavigation.org/docs/react-native-screens
43 41
 // Crashes app when navigating away from webview on android 9+
@@ -50,15 +48,15 @@ LogBox.ignoreLogs([
50 48
 ]);
51 49
 
52 50
 type StateType = {
53
-  isLoading: boolean,
54
-  showIntro: boolean,
55
-  showUpdate: boolean,
56
-  showAprilFools: boolean,
57
-  currentTheme: CustomThemeType | null,
51
+  isLoading: boolean;
52
+  showIntro: boolean;
53
+  showUpdate: boolean;
54
+  showAprilFools: boolean;
55
+  currentTheme: ReactNativePaper.Theme | undefined;
58 56
 };
59 57
 
60 58
 export default class App extends React.Component<null, StateType> {
61
-  navigatorRef: {current: null | NavigationContainer};
59
+  navigatorRef: {current: null | NavigationContainerRef};
62 60
 
63 61
   defaultHomeRoute: string | null;
64 62
 
@@ -67,13 +65,13 @@ export default class App extends React.Component<null, StateType> {
67 65
   urlHandler: URLHandler;
68 66
 
69 67
   constructor() {
70
-    super();
68
+    super(null);
71 69
     this.state = {
72 70
       isLoading: true,
73 71
       showIntro: true,
74 72
       showUpdate: true,
75 73
       showAprilFools: false,
76
-      currentTheme: null,
74
+      currentTheme: undefined,
77 75
     };
78 76
     initLocales();
79 77
     this.navigatorRef = React.createRef();
@@ -155,8 +153,11 @@ export default class App extends React.Component<null, StateType> {
155 153
     // Only show intro if this is the first time starting the app
156 154
     ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
157 155
     // Status bar goes dark if set too fast on ios
158
-    if (Platform.OS === 'ios') setTimeout(setupStatusBar, 1000);
159
-    else setupStatusBar();
156
+    if (Platform.OS === 'ios') {
157
+      setTimeout(setupStatusBar, 1000);
158
+    } else {
159
+      setupStatusBar();
160
+    }
160 161
 
161 162
     this.setState({
162 163
       isLoading: false,
@@ -192,7 +193,7 @@ export default class App extends React.Component<null, StateType> {
192 193
   /**
193 194
    * Renders the app based on loading state
194 195
    */
195
-  render(): React.Node {
196
+  render() {
196 197
     const {state} = this;
197 198
     if (state.isLoading) {
198 199
       return null;

src/managers/AsyncStorageManager.js → src/managers/AsyncStorageManager.ts View File

@@ -17,8 +17,6 @@
17 17
  * along with Campus INSAT.  If not, see <https://www.gnu.org/licenses/>.
18 18
  */
19 19
 
20
-// @flow
21
-
22 20
 import AsyncStorage from '@react-native-community/async-storage';
23 21
 import {SERVICES_KEY} from './ServicesManager';
24 22
 
@@ -31,7 +29,7 @@ import {SERVICES_KEY} from './ServicesManager';
31 29
 export default class AsyncStorageManager {
32 30
   static instance: AsyncStorageManager | null = null;
33 31
 
34
-  static PREFERENCES = {
32
+  static PREFERENCES: {[key: string]: {key: string; default: string}} = {
35 33
     debugUnlocked: {
36 34
       key: 'debugUnlocked',
37 35
       default: '0',
@@ -132,10 +130,10 @@ export default class AsyncStorageManager {
132 130
     },
133 131
   };
134 132
 
135
-  #currentPreferences: {[key: string]: string};
133
+  private currentPreferences: {[key: string]: string};
136 134
 
137 135
   constructor() {
138
-    this.#currentPreferences = {};
136
+    this.currentPreferences = {};
139 137
   }
140 138
 
141 139
   /**
@@ -143,8 +141,9 @@ export default class AsyncStorageManager {
143 141
    * @returns {AsyncStorageManager}
144 142
    */
145 143
   static getInstance(): AsyncStorageManager {
146
-    if (AsyncStorageManager.instance == null)
144
+    if (AsyncStorageManager.instance == null) {
147 145
       AsyncStorageManager.instance = new AsyncStorageManager();
146
+    }
148 147
     return AsyncStorageManager.instance;
149 148
   }
150 149
 
@@ -156,8 +155,7 @@ export default class AsyncStorageManager {
156 155
    */
157 156
   static set(
158 157
     key: string,
159
-    // eslint-disable-next-line flowtype/no-weak-types
160
-    value: number | string | boolean | {...} | Array<any>,
158
+    value: number | string | boolean | object | Array<any>,
161 159
   ) {
162 160
     AsyncStorageManager.getInstance().setPreference(key, value);
163 161
   }
@@ -200,8 +198,7 @@ export default class AsyncStorageManager {
200 198
    * @param key
201 199
    * @returns {{...}}
202 200
    */
203
-  // eslint-disable-next-line flowtype/no-weak-types
204
-  static getObject(key: string): any {
201
+  static getObject(key: string): object | Array<any> {
205 202
     return JSON.parse(AsyncStorageManager.getString(key));
206 203
   }
207 204
 
@@ -212,7 +209,7 @@ export default class AsyncStorageManager {
212 209
    * @return {Promise<void>}
213 210
    */
214 211
   async loadPreferences() {
215
-    const prefKeys = [];
212
+    const prefKeys: Array<string> = [];
216 213
     // Get all available keys
217 214
     Object.keys(AsyncStorageManager.PREFERENCES).forEach((key: string) => {
218 215
       prefKeys.push(key);
@@ -223,8 +220,10 @@ export default class AsyncStorageManager {
223 220
     resultArray.forEach((item: [string, string | null]) => {
224 221
       const key = item[0];
225 222
       let val = item[1];
226
-      if (val === null) val = AsyncStorageManager.PREFERENCES[key].default;
227
-      this.#currentPreferences[key] = val;
223
+      if (val === null) {
224
+        val = AsyncStorageManager.PREFERENCES[key].default;
225
+      }
226
+      this.currentPreferences[key] = val;
228 227
     });
229 228
   }
230 229
 
@@ -237,16 +236,18 @@ export default class AsyncStorageManager {
237 236
    */
238 237
   setPreference(
239 238
     key: string,
240
-    // eslint-disable-next-line flowtype/no-weak-types
241
-    value: number | string | boolean | {...} | Array<any>,
239
+    value: number | string | boolean | object | Array<any>,
242 240
   ) {
243 241
     if (AsyncStorageManager.PREFERENCES[key] != null) {
244 242
       let convertedValue;
245
-      if (typeof value === 'string') convertedValue = value;
246
-      else if (typeof value === 'boolean' || typeof value === 'number')
243
+      if (typeof value === 'string') {
244
+        convertedValue = value;
245
+      } else if (typeof value === 'boolean' || typeof value === 'number') {
247 246
         convertedValue = value.toString();
248
-      else convertedValue = JSON.stringify(value);
249
-      this.#currentPreferences[key] = convertedValue;
247
+      } else {
248
+        convertedValue = JSON.stringify(value);
249
+      }
250
+      this.currentPreferences[key] = convertedValue;
250 251
       AsyncStorage.setItem(key, convertedValue);
251 252
     }
252 253
   }
@@ -259,6 +260,6 @@ export default class AsyncStorageManager {
259 260
    * @returns {string|null}
260 261
    */
261 262
   getPreference(key: string): string | null {
262
-    return this.#currentPreferences[key];
263
+    return this.currentPreferences[key];
263 264
   }
264 265
 }

+ 0
- 307
src/managers/ThemeManager.js View File

@@ -1,307 +0,0 @@
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
-
20
-// @flow
21
-
22
-import {DarkTheme, DefaultTheme} from 'react-native-paper';
23
-import {Appearance} from 'react-native-appearance';
24
-import AsyncStorageManager from './AsyncStorageManager';
25
-import AprilFoolsManager from './AprilFoolsManager';
26
-
27
-const colorScheme = Appearance.getColorScheme();
28
-
29
-export type CustomThemeType = {
30
-  ...DefaultTheme,
31
-  colors: {
32
-    primary: string,
33
-    accent: string,
34
-    tabIcon: string,
35
-    card: string,
36
-    dividerBackground: string,
37
-    ripple: string,
38
-    textDisabled: string,
39
-    icon: string,
40
-    subtitle: string,
41
-    success: string,
42
-    warning: string,
43
-    danger: string,
44
-
45
-    // Calendar/Agenda
46
-    agendaBackgroundColor: string,
47
-    agendaDayTextColor: string,
48
-
49
-    // PROXIWASH
50
-    proxiwashFinishedColor: string,
51
-    proxiwashReadyColor: string,
52
-    proxiwashRunningColor: string,
53
-    proxiwashRunningNotStartedColor: string,
54
-    proxiwashRunningBgColor: string,
55
-    proxiwashBrokenColor: string,
56
-    proxiwashErrorColor: string,
57
-    proxiwashUnknownColor: string,
58
-
59
-    // Screens
60
-    planningColor: string,
61
-    proximoColor: string,
62
-    proxiwashColor: string,
63
-    menuColor: string,
64
-    tutorinsaColor: string,
65
-
66
-    // Tetris
67
-    tetrisBackground: string,
68
-    tetrisBorder: string,
69
-    tetrisScore: string,
70
-    tetrisI: string,
71
-    tetrisO: string,
72
-    tetrisT: string,
73
-    tetrisS: string,
74
-    tetrisZ: string,
75
-    tetrisJ: string,
76
-    tetrisL: string,
77
-
78
-    gameGold: string,
79
-    gameSilver: string,
80
-    gameBronze: string,
81
-
82
-    // Mascot Popup
83
-    mascotMessageArrow: string,
84
-  },
85
-};
86
-
87
-/**
88
- * Singleton class used to manage themes
89
- */
90
-export default class ThemeManager {
91
-  static instance: ThemeManager | null = null;
92
-
93
-  updateThemeCallback: null | (() => void);
94
-
95
-  constructor() {
96
-    this.updateThemeCallback = null;
97
-  }
98
-
99
-  /**
100
-   * Gets the light theme
101
-   *
102
-   * @return {CustomThemeType} Object containing theme variables
103
-   * */
104
-  static getWhiteTheme(): CustomThemeType {
105
-    return {
106
-      ...DefaultTheme,
107
-      colors: {
108
-        ...DefaultTheme.colors,
109
-        primary: '#be1522',
110
-        accent: '#be1522',
111
-        tabIcon: '#929292',
112
-        card: '#fff',
113
-        dividerBackground: '#e2e2e2',
114
-        ripple: 'rgba(0,0,0,0.2)',
115
-        textDisabled: '#c1c1c1',
116
-        icon: '#5d5d5d',
117
-        subtitle: '#707070',
118
-        success: '#5cb85c',
119
-        warning: '#f0ad4e',
120
-        danger: '#d9534f',
121
-        cc: 'dst',
122
-
123
-        // Calendar/Agenda
124
-        agendaBackgroundColor: '#f3f3f4',
125
-        agendaDayTextColor: '#636363',
126
-
127
-        // PROXIWASH
128
-        proxiwashFinishedColor: '#a5dc9d',
129
-        proxiwashReadyColor: 'transparent',
130
-        proxiwashRunningColor: '#a0ceff',
131
-        proxiwashRunningNotStartedColor: '#c9e0ff',
132
-        proxiwashRunningBgColor: '#c7e3ff',
133
-        proxiwashBrokenColor: '#ffa8a2',
134
-        proxiwashErrorColor: '#ffa8a2',
135
-        proxiwashUnknownColor: '#b6b6b6',
136
-
137
-        // Screens
138
-        planningColor: '#d9b10a',
139
-        proximoColor: '#ec5904',
140
-        proxiwashColor: '#1fa5ee',
141
-        menuColor: '#e91314',
142
-        tutorinsaColor: '#f93943',
143
-
144
-        // Tetris
145
-        tetrisBackground: '#f0f0f0',
146
-        tetrisScore: '#e2bd33',
147
-        tetrisI: '#3cd9e6',
148
-        tetrisO: '#ffdd00',
149
-        tetrisT: '#a716e5',
150
-        tetrisS: '#09c528',
151
-        tetrisZ: '#ff0009',
152
-        tetrisJ: '#2a67e3',
153
-        tetrisL: '#da742d',
154
-
155
-        gameGold: '#ffd610',
156
-        gameSilver: '#7b7b7b',
157
-        gameBronze: '#a15218',
158
-
159
-        // Mascot Popup
160
-        mascotMessageArrow: '#dedede',
161
-      },
162
-    };
163
-  }
164
-
165
-  /**
166
-   * Gets the dark theme
167
-   *
168
-   * @return {CustomThemeType} Object containing theme variables
169
-   * */
170
-  static getDarkTheme(): CustomThemeType {
171
-    return {
172
-      ...DarkTheme,
173
-      colors: {
174
-        ...DarkTheme.colors,
175
-        primary: '#be1522',
176
-        accent: '#be1522',
177
-        tabBackground: '#181818',
178
-        tabIcon: '#6d6d6d',
179
-        card: 'rgb(18,18,18)',
180
-        dividerBackground: '#222222',
181
-        ripple: 'rgba(255,255,255,0.2)',
182
-        textDisabled: '#5b5b5b',
183
-        icon: '#b3b3b3',
184
-        subtitle: '#aaaaaa',
185
-        success: '#5cb85c',
186
-        warning: '#f0ad4e',
187
-        danger: '#d9534f',
188
-
189
-        // Calendar/Agenda
190
-        agendaBackgroundColor: '#171717',
191
-        agendaDayTextColor: '#6d6d6d',
192
-
193
-        // PROXIWASH
194
-        proxiwashFinishedColor: '#31682c',
195
-        proxiwashReadyColor: 'transparent',
196
-        proxiwashRunningColor: '#213c79',
197
-        proxiwashRunningNotStartedColor: '#1e263e',
198
-        proxiwashRunningBgColor: '#1a2033',
199
-        proxiwashBrokenColor: '#7e2e2f',
200
-        proxiwashErrorColor: '#7e2e2f',
201
-        proxiwashUnknownColor: '#535353',
202
-
203
-        // Screens
204
-        planningColor: '#d99e09',
205
-        proximoColor: '#ec5904',
206
-        proxiwashColor: '#1fa5ee',
207
-        menuColor: '#b81213',
208
-        tutorinsaColor: '#f93943',
209
-
210
-        // Tetris
211
-        tetrisBackground: '#181818',
212
-        tetrisScore: '#e2d707',
213
-        tetrisI: '#30b3be',
214
-        tetrisO: '#c1a700',
215
-        tetrisT: '#9114c7',
216
-        tetrisS: '#08a121',
217
-        tetrisZ: '#b50008',
218
-        tetrisJ: '#0f37b9',
219
-        tetrisL: '#b96226',
220
-
221
-        gameGold: '#ffd610',
222
-        gameSilver: '#7b7b7b',
223
-        gameBronze: '#a15218',
224
-
225
-        // Mascot Popup
226
-        mascotMessageArrow: '#323232',
227
-      },
228
-    };
229
-  }
230
-
231
-  /**
232
-   * Get this class instance or create one if none is found
233
-   *
234
-   * @returns {ThemeManager}
235
-   */
236
-  static getInstance(): ThemeManager {
237
-    if (ThemeManager.instance == null)
238
-      ThemeManager.instance = new ThemeManager();
239
-    return ThemeManager.instance;
240
-  }
241
-
242
-  /**
243
-   * Gets night mode status.
244
-   * If Follow System Preferences is enabled, will first use system theme.
245
-   * If disabled or not available, will use value stored din preferences
246
-   *
247
-   * @returns {boolean} Night mode state
248
-   */
249
-  static getNightMode(): boolean {
250
-    return (
251
-      (AsyncStorageManager.getBool(
252
-        AsyncStorageManager.PREFERENCES.nightMode.key,
253
-      ) &&
254
-        (!AsyncStorageManager.getBool(
255
-          AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
256
-        ) ||
257
-          colorScheme === 'no-preference')) ||
258
-      (AsyncStorageManager.getBool(
259
-        AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
260
-      ) &&
261
-        colorScheme === 'dark')
262
-    );
263
-  }
264
-
265
-  /**
266
-   * Get the current theme based on night mode and events
267
-   *
268
-   * @returns {CustomThemeType} The current theme
269
-   */
270
-  static getCurrentTheme(): CustomThemeType {
271
-    if (AprilFoolsManager.getInstance().isAprilFoolsEnabled())
272
-      return AprilFoolsManager.getAprilFoolsTheme(ThemeManager.getWhiteTheme());
273
-    return ThemeManager.getBaseTheme();
274
-  }
275
-
276
-  /**
277
-   * Get the theme based on night mode
278
-   *
279
-   * @return {CustomThemeType} The theme
280
-   */
281
-  static getBaseTheme(): CustomThemeType {
282
-    if (ThemeManager.getNightMode()) return ThemeManager.getDarkTheme();
283
-    return ThemeManager.getWhiteTheme();
284
-  }
285
-
286
-  /**
287
-   * Sets the function to be called when the theme is changed (allows for general reload of the app)
288
-   *
289
-   * @param callback Function to call after theme change
290
-   */
291
-  setUpdateThemeCallback(callback: () => void) {
292
-    this.updateThemeCallback = callback;
293
-  }
294
-
295
-  /**
296
-   * Set night mode and save it to preferences
297
-   *
298
-   * @param isNightMode True to enable night mode, false to disable
299
-   */
300
-  setNightMode(isNightMode: boolean) {
301
-    AsyncStorageManager.set(
302
-      AsyncStorageManager.PREFERENCES.nightMode.key,
303
-      isNightMode,
304
-    );
305
-    if (this.updateThemeCallback != null) this.updateThemeCallback();
306
-  }
307
-}

+ 298
- 0
src/managers/ThemeManager.ts View File

@@ -0,0 +1,298 @@
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
+
20
+import {DarkTheme, DefaultTheme} from 'react-native-paper';
21
+import {Appearance} from 'react-native-appearance';
22
+import AsyncStorageManager from './AsyncStorageManager';
23
+import AprilFoolsManager from './AprilFoolsManager';
24
+
25
+const colorScheme = Appearance.getColorScheme();
26
+
27
+declare global {
28
+  namespace ReactNativePaper {
29
+    interface ThemeColors {
30
+      primary: string;
31
+      accent: string;
32
+      border: string;
33
+      tabIcon: string;
34
+      card: string;
35
+      dividerBackground: string;
36
+      ripple: string;
37
+      textDisabled: string;
38
+      icon: string;
39
+      subtitle: string;
40
+      success: string;
41
+      warning: string;
42
+      danger: string;
43
+
44
+      // Calendar/Agenda
45
+      agendaBackgroundColor: string;
46
+      agendaDayTextColor: string;
47
+
48
+      // PROXIWASH
49
+      proxiwashFinishedColor: string;
50
+      proxiwashReadyColor: string;
51
+      proxiwashRunningColor: string;
52
+      proxiwashRunningNotStartedColor: string;
53
+      proxiwashRunningBgColor: string;
54
+      proxiwashBrokenColor: string;
55
+      proxiwashErrorColor: string;
56
+      proxiwashUnknownColor: string;
57
+
58
+      // Screens
59
+      planningColor: string;
60
+      proximoColor: string;
61
+      proxiwashColor: string;
62
+      menuColor: string;
63
+      tutorinsaColor: string;
64
+
65
+      // Tetris
66
+      tetrisBackground: string;
67
+      tetrisScore: string;
68
+      tetrisI: string;
69
+      tetrisO: string;
70
+      tetrisT: string;
71
+      tetrisS: string;
72
+      tetrisZ: string;
73
+      tetrisJ: string;
74
+      tetrisL: string;
75
+
76
+      gameGold: string;
77
+      gameSilver: string;
78
+      gameBronze: string;
79
+
80
+      // Mascot Popup
81
+      mascotMessageArrow: string;
82
+    }
83
+  }
84
+}
85
+
86
+const CustomWhiteTheme: ReactNativePaper.Theme = {
87
+  ...DefaultTheme,
88
+  colors: {
89
+    ...DefaultTheme.colors,
90
+    primary: '#be1522',
91
+    accent: '#be1522',
92
+    border: '#e2e2e2',
93
+    tabIcon: '#929292',
94
+    card: '#fff',
95
+    dividerBackground: '#e2e2e2',
96
+    ripple: 'rgba(0,0,0,0.2)',
97
+    textDisabled: '#c1c1c1',
98
+    icon: '#5d5d5d',
99
+    subtitle: '#707070',
100
+    success: '#5cb85c',
101
+    warning: '#f0ad4e',
102
+    danger: '#d9534f',
103
+
104
+    // Calendar/Agenda
105
+    agendaBackgroundColor: '#f3f3f4',
106
+    agendaDayTextColor: '#636363',
107
+
108
+    // PROXIWASH
109
+    proxiwashFinishedColor: '#a5dc9d',
110
+    proxiwashReadyColor: 'transparent',
111
+    proxiwashRunningColor: '#a0ceff',
112
+    proxiwashRunningNotStartedColor: '#c9e0ff',
113
+    proxiwashRunningBgColor: '#c7e3ff',
114
+    proxiwashBrokenColor: '#ffa8a2',
115
+    proxiwashErrorColor: '#ffa8a2',
116
+    proxiwashUnknownColor: '#b6b6b6',
117
+
118
+    // Screens
119
+    planningColor: '#d9b10a',
120
+    proximoColor: '#ec5904',
121
+    proxiwashColor: '#1fa5ee',
122
+    menuColor: '#e91314',
123
+    tutorinsaColor: '#f93943',
124
+
125
+    // Tetris
126
+    tetrisBackground: '#f0f0f0',
127
+    tetrisScore: '#e2bd33',
128
+    tetrisI: '#3cd9e6',
129
+    tetrisO: '#ffdd00',
130
+    tetrisT: '#a716e5',
131
+    tetrisS: '#09c528',
132
+    tetrisZ: '#ff0009',
133
+    tetrisJ: '#2a67e3',
134
+    tetrisL: '#da742d',
135
+
136
+    gameGold: '#ffd610',
137
+    gameSilver: '#7b7b7b',
138
+    gameBronze: '#a15218',
139
+
140
+    // Mascot Popup
141
+    mascotMessageArrow: '#dedede',
142
+  },
143
+};
144
+
145
+const CustomDarkTheme: ReactNativePaper.Theme = {
146
+  ...DarkTheme,
147
+  colors: {
148
+    ...DarkTheme.colors,
149
+    primary: '#be1522',
150
+    accent: '#be1522',
151
+    border: '#222222',
152
+    tabIcon: '#6d6d6d',
153
+    card: 'rgb(18,18,18)',
154
+    dividerBackground: '#222222',
155
+    ripple: 'rgba(255,255,255,0.2)',
156
+    textDisabled: '#5b5b5b',
157
+    icon: '#b3b3b3',
158
+    subtitle: '#aaaaaa',
159
+    success: '#5cb85c',
160
+    warning: '#f0ad4e',
161
+    danger: '#d9534f',
162
+
163
+    // Calendar/Agenda
164
+    agendaBackgroundColor: '#171717',
165
+    agendaDayTextColor: '#6d6d6d',
166
+
167
+    // PROXIWASH
168
+    proxiwashFinishedColor: '#31682c',
169
+    proxiwashReadyColor: 'transparent',
170
+    proxiwashRunningColor: '#213c79',
171
+    proxiwashRunningNotStartedColor: '#1e263e',
172
+    proxiwashRunningBgColor: '#1a2033',
173
+    proxiwashBrokenColor: '#7e2e2f',
174
+    proxiwashErrorColor: '#7e2e2f',
175
+    proxiwashUnknownColor: '#535353',
176
+
177
+    // Screens
178
+    planningColor: '#d99e09',
179
+    proximoColor: '#ec5904',
180
+    proxiwashColor: '#1fa5ee',
181
+    menuColor: '#b81213',
182
+    tutorinsaColor: '#f93943',
183
+
184
+    // Tetris
185
+    tetrisBackground: '#181818',
186
+    tetrisScore: '#e2d707',
187
+    tetrisI: '#30b3be',
188
+    tetrisO: '#c1a700',
189
+    tetrisT: '#9114c7',
190
+    tetrisS: '#08a121',
191
+    tetrisZ: '#b50008',
192
+    tetrisJ: '#0f37b9',
193
+    tetrisL: '#b96226',
194
+
195
+    gameGold: '#ffd610',
196
+    gameSilver: '#7b7b7b',
197
+    gameBronze: '#a15218',
198
+
199
+    // Mascot Popup
200
+    mascotMessageArrow: '#323232',
201
+  },
202
+};
203
+
204
+/**
205
+ * Singleton class used to manage themes
206
+ */
207
+export default class ThemeManager {
208
+  static instance: ThemeManager | null = null;
209
+
210
+  updateThemeCallback: null | (() => void);
211
+
212
+  constructor() {
213
+    this.updateThemeCallback = null;
214
+  }
215
+
216
+  /**
217
+   * Get this class instance or create one if none is found
218
+   *
219
+   * @returns {ThemeManager}
220
+   */
221
+  static getInstance(): ThemeManager {
222
+    if (ThemeManager.instance == null) {
223
+      ThemeManager.instance = new ThemeManager();
224
+    }
225
+    return ThemeManager.instance;
226
+  }
227
+
228
+  /**
229
+   * Gets night mode status.
230
+   * If Follow System Preferences is enabled, will first use system theme.
231
+   * If disabled or not available, will use value stored din preferences
232
+   *
233
+   * @returns {boolean} Night mode state
234
+   */
235
+  static getNightMode(): boolean {
236
+    return (
237
+      (AsyncStorageManager.getBool(
238
+        AsyncStorageManager.PREFERENCES.nightMode.key,
239
+      ) &&
240
+        (!AsyncStorageManager.getBool(
241
+          AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
242
+        ) ||
243
+          colorScheme === 'no-preference')) ||
244
+      (AsyncStorageManager.getBool(
245
+        AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
246
+      ) &&
247
+        colorScheme === 'dark')
248
+    );
249
+  }
250
+
251
+  /**
252
+   * Get the current theme based on night mode and events
253
+   *
254
+   * @returns {ReactNativePaper.Theme} The current theme
255
+   */
256
+  static getCurrentTheme(): ReactNativePaper.Theme {
257
+    if (AprilFoolsManager.getInstance().isAprilFoolsEnabled()) {
258
+      return AprilFoolsManager.getAprilFoolsTheme(CustomWhiteTheme);
259
+    }
260
+    return ThemeManager.getBaseTheme();
261
+  }
262
+
263
+  /**
264
+   * Get the theme based on night mode
265
+   *
266
+   * @return {ReactNativePaper.Theme} The theme
267
+   */
268
+  static getBaseTheme(): ReactNativePaper.Theme {
269
+    if (ThemeManager.getNightMode()) {
270
+      return CustomDarkTheme;
271
+    }
272
+    return CustomWhiteTheme;
273
+  }
274
+
275
+  /**
276
+   * Sets the function to be called when the theme is changed (allows for general reload of the app)
277
+   *
278
+   * @param callback Function to call after theme change
279
+   */
280
+  setUpdateThemeCallback(callback: () => void) {
281
+    this.updateThemeCallback = callback;
282
+  }
283
+
284
+  /**
285
+   * Set night mode and save it to preferences
286
+   *
287
+   * @param isNightMode True to enable night mode, false to disable
288
+   */
289
+  setNightMode(isNightMode: boolean) {
290
+    AsyncStorageManager.set(
291
+      AsyncStorageManager.PREFERENCES.nightMode.key,
292
+      isNightMode,
293
+    );
294
+    if (this.updateThemeCallback != null) {
295
+      this.updateThemeCallback();
296
+    }
297
+  }
298
+}

Loading…
Cancel
Save