diff --git a/App.js b/App.tsx
similarity index 93%
rename from App.js
rename to App.tsx
index 467779b..8c32968 100644
--- a/App.js
+++ b/App.tsx
@@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import * as React from 'react';
import {LogBox, Platform, SafeAreaView, View} from 'react-native';
import {NavigationContainer} from '@react-navigation/native';
@@ -28,7 +26,6 @@ import SplashScreen from 'react-native-splash-screen';
import {OverflowMenuProvider} from 'react-navigation-header-buttons';
import AsyncStorageManager from './src/managers/AsyncStorageManager';
import CustomIntroSlider from './src/components/Overrides/CustomIntroSlider';
-import type {CustomThemeType} from './src/managers/ThemeManager';
import ThemeManager from './src/managers/ThemeManager';
import MainNavigator from './src/navigation/MainNavigator';
import AprilFoolsManager from './src/managers/AprilFoolsManager';
@@ -38,6 +35,7 @@ import type {ParsedUrlDataType} from './src/utils/URLHandler';
import URLHandler from './src/utils/URLHandler';
import {setupStatusBar} from './src/utils/Utils';
import initLocales from './src/utils/Locales';
+import {NavigationContainerRef} from '@react-navigation/core';
// Native optimizations https://reactnavigation.org/docs/react-native-screens
// Crashes app when navigating away from webview on android 9+
@@ -50,15 +48,15 @@ LogBox.ignoreLogs([
]);
type StateType = {
- isLoading: boolean,
- showIntro: boolean,
- showUpdate: boolean,
- showAprilFools: boolean,
- currentTheme: CustomThemeType | null,
+ isLoading: boolean;
+ showIntro: boolean;
+ showUpdate: boolean;
+ showAprilFools: boolean;
+ currentTheme: ReactNativePaper.Theme | undefined;
};
export default class App extends React.Component {
- navigatorRef: {current: null | NavigationContainer};
+ navigatorRef: {current: null | NavigationContainerRef};
defaultHomeRoute: string | null;
@@ -67,13 +65,13 @@ export default class App extends React.Component {
urlHandler: URLHandler;
constructor() {
- super();
+ super(null);
this.state = {
isLoading: true,
showIntro: true,
showUpdate: true,
showAprilFools: false,
- currentTheme: null,
+ currentTheme: undefined,
};
initLocales();
this.navigatorRef = React.createRef();
@@ -155,8 +153,11 @@ export default class App extends React.Component {
// Only show intro if this is the first time starting the app
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
// Status bar goes dark if set too fast on ios
- if (Platform.OS === 'ios') setTimeout(setupStatusBar, 1000);
- else setupStatusBar();
+ if (Platform.OS === 'ios') {
+ setTimeout(setupStatusBar, 1000);
+ } else {
+ setupStatusBar();
+ }
this.setState({
isLoading: false,
@@ -192,7 +193,7 @@ export default class App extends React.Component {
/**
* Renders the app based on loading state
*/
- render(): React.Node {
+ render() {
const {state} = this;
if (state.isLoading) {
return null;
diff --git a/src/managers/AsyncStorageManager.js b/src/managers/AsyncStorageManager.ts
similarity index 86%
rename from src/managers/AsyncStorageManager.js
rename to src/managers/AsyncStorageManager.ts
index 5b5b5ca..483d0c8 100644
--- a/src/managers/AsyncStorageManager.js
+++ b/src/managers/AsyncStorageManager.ts
@@ -17,8 +17,6 @@
* along with Campus INSAT. If not, see .
*/
-// @flow
-
import AsyncStorage from '@react-native-community/async-storage';
import {SERVICES_KEY} from './ServicesManager';
@@ -31,7 +29,7 @@ import {SERVICES_KEY} from './ServicesManager';
export default class AsyncStorageManager {
static instance: AsyncStorageManager | null = null;
- static PREFERENCES = {
+ static PREFERENCES: {[key: string]: {key: string; default: string}} = {
debugUnlocked: {
key: 'debugUnlocked',
default: '0',
@@ -132,10 +130,10 @@ export default class AsyncStorageManager {
},
};
- #currentPreferences: {[key: string]: string};
+ private currentPreferences: {[key: string]: string};
constructor() {
- this.#currentPreferences = {};
+ this.currentPreferences = {};
}
/**
@@ -143,8 +141,9 @@ export default class AsyncStorageManager {
* @returns {AsyncStorageManager}
*/
static getInstance(): AsyncStorageManager {
- if (AsyncStorageManager.instance == null)
+ if (AsyncStorageManager.instance == null) {
AsyncStorageManager.instance = new AsyncStorageManager();
+ }
return AsyncStorageManager.instance;
}
@@ -156,8 +155,7 @@ export default class AsyncStorageManager {
*/
static set(
key: string,
- // eslint-disable-next-line flowtype/no-weak-types
- value: number | string | boolean | {...} | Array,
+ value: number | string | boolean | object | Array,
) {
AsyncStorageManager.getInstance().setPreference(key, value);
}
@@ -200,8 +198,7 @@ export default class AsyncStorageManager {
* @param key
* @returns {{...}}
*/
- // eslint-disable-next-line flowtype/no-weak-types
- static getObject(key: string): any {
+ static getObject(key: string): object | Array {
return JSON.parse(AsyncStorageManager.getString(key));
}
@@ -212,7 +209,7 @@ export default class AsyncStorageManager {
* @return {Promise}
*/
async loadPreferences() {
- const prefKeys = [];
+ const prefKeys: Array = [];
// Get all available keys
Object.keys(AsyncStorageManager.PREFERENCES).forEach((key: string) => {
prefKeys.push(key);
@@ -223,8 +220,10 @@ export default class AsyncStorageManager {
resultArray.forEach((item: [string, string | null]) => {
const key = item[0];
let val = item[1];
- if (val === null) val = AsyncStorageManager.PREFERENCES[key].default;
- this.#currentPreferences[key] = val;
+ if (val === null) {
+ val = AsyncStorageManager.PREFERENCES[key].default;
+ }
+ this.currentPreferences[key] = val;
});
}
@@ -237,16 +236,18 @@ export default class AsyncStorageManager {
*/
setPreference(
key: string,
- // eslint-disable-next-line flowtype/no-weak-types
- value: number | string | boolean | {...} | Array,
+ value: number | string | boolean | object | Array,
) {
if (AsyncStorageManager.PREFERENCES[key] != null) {
let convertedValue;
- if (typeof value === 'string') convertedValue = value;
- else if (typeof value === 'boolean' || typeof value === 'number')
+ if (typeof value === 'string') {
+ convertedValue = value;
+ } else if (typeof value === 'boolean' || typeof value === 'number') {
convertedValue = value.toString();
- else convertedValue = JSON.stringify(value);
- this.#currentPreferences[key] = convertedValue;
+ } else {
+ convertedValue = JSON.stringify(value);
+ }
+ this.currentPreferences[key] = convertedValue;
AsyncStorage.setItem(key, convertedValue);
}
}
@@ -259,6 +260,6 @@ export default class AsyncStorageManager {
* @returns {string|null}
*/
getPreference(key: string): string | null {
- return this.#currentPreferences[key];
+ return this.currentPreferences[key];
}
}
diff --git a/src/managers/ThemeManager.js b/src/managers/ThemeManager.js
deleted file mode 100644
index 0b6872d..0000000
--- a/src/managers/ThemeManager.js
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (c) 2019 - 2020 Arnaud Vergnet.
- *
- * This file is part of Campus INSAT.
- *
- * Campus INSAT is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Campus INSAT is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Campus INSAT. If not, see .
- */
-
-// @flow
-
-import {DarkTheme, DefaultTheme} from 'react-native-paper';
-import {Appearance} from 'react-native-appearance';
-import AsyncStorageManager from './AsyncStorageManager';
-import AprilFoolsManager from './AprilFoolsManager';
-
-const colorScheme = Appearance.getColorScheme();
-
-export type CustomThemeType = {
- ...DefaultTheme,
- colors: {
- primary: string,
- accent: string,
- tabIcon: string,
- card: string,
- dividerBackground: string,
- ripple: string,
- textDisabled: string,
- icon: string,
- subtitle: string,
- success: string,
- warning: string,
- danger: string,
-
- // Calendar/Agenda
- agendaBackgroundColor: string,
- agendaDayTextColor: string,
-
- // PROXIWASH
- proxiwashFinishedColor: string,
- proxiwashReadyColor: string,
- proxiwashRunningColor: string,
- proxiwashRunningNotStartedColor: string,
- proxiwashRunningBgColor: string,
- proxiwashBrokenColor: string,
- proxiwashErrorColor: string,
- proxiwashUnknownColor: string,
-
- // Screens
- planningColor: string,
- proximoColor: string,
- proxiwashColor: string,
- menuColor: string,
- tutorinsaColor: string,
-
- // Tetris
- tetrisBackground: string,
- tetrisBorder: string,
- tetrisScore: string,
- tetrisI: string,
- tetrisO: string,
- tetrisT: string,
- tetrisS: string,
- tetrisZ: string,
- tetrisJ: string,
- tetrisL: string,
-
- gameGold: string,
- gameSilver: string,
- gameBronze: string,
-
- // Mascot Popup
- mascotMessageArrow: string,
- },
-};
-
-/**
- * Singleton class used to manage themes
- */
-export default class ThemeManager {
- static instance: ThemeManager | null = null;
-
- updateThemeCallback: null | (() => void);
-
- constructor() {
- this.updateThemeCallback = null;
- }
-
- /**
- * Gets the light theme
- *
- * @return {CustomThemeType} Object containing theme variables
- * */
- static getWhiteTheme(): CustomThemeType {
- return {
- ...DefaultTheme,
- colors: {
- ...DefaultTheme.colors,
- primary: '#be1522',
- accent: '#be1522',
- tabIcon: '#929292',
- card: '#fff',
- dividerBackground: '#e2e2e2',
- ripple: 'rgba(0,0,0,0.2)',
- textDisabled: '#c1c1c1',
- icon: '#5d5d5d',
- subtitle: '#707070',
- success: '#5cb85c',
- warning: '#f0ad4e',
- danger: '#d9534f',
- cc: 'dst',
-
- // Calendar/Agenda
- agendaBackgroundColor: '#f3f3f4',
- agendaDayTextColor: '#636363',
-
- // PROXIWASH
- proxiwashFinishedColor: '#a5dc9d',
- proxiwashReadyColor: 'transparent',
- proxiwashRunningColor: '#a0ceff',
- proxiwashRunningNotStartedColor: '#c9e0ff',
- proxiwashRunningBgColor: '#c7e3ff',
- proxiwashBrokenColor: '#ffa8a2',
- proxiwashErrorColor: '#ffa8a2',
- proxiwashUnknownColor: '#b6b6b6',
-
- // Screens
- planningColor: '#d9b10a',
- proximoColor: '#ec5904',
- proxiwashColor: '#1fa5ee',
- menuColor: '#e91314',
- tutorinsaColor: '#f93943',
-
- // Tetris
- tetrisBackground: '#f0f0f0',
- tetrisScore: '#e2bd33',
- tetrisI: '#3cd9e6',
- tetrisO: '#ffdd00',
- tetrisT: '#a716e5',
- tetrisS: '#09c528',
- tetrisZ: '#ff0009',
- tetrisJ: '#2a67e3',
- tetrisL: '#da742d',
-
- gameGold: '#ffd610',
- gameSilver: '#7b7b7b',
- gameBronze: '#a15218',
-
- // Mascot Popup
- mascotMessageArrow: '#dedede',
- },
- };
- }
-
- /**
- * Gets the dark theme
- *
- * @return {CustomThemeType} Object containing theme variables
- * */
- static getDarkTheme(): CustomThemeType {
- return {
- ...DarkTheme,
- colors: {
- ...DarkTheme.colors,
- primary: '#be1522',
- accent: '#be1522',
- tabBackground: '#181818',
- tabIcon: '#6d6d6d',
- card: 'rgb(18,18,18)',
- dividerBackground: '#222222',
- ripple: 'rgba(255,255,255,0.2)',
- textDisabled: '#5b5b5b',
- icon: '#b3b3b3',
- subtitle: '#aaaaaa',
- success: '#5cb85c',
- warning: '#f0ad4e',
- danger: '#d9534f',
-
- // Calendar/Agenda
- agendaBackgroundColor: '#171717',
- agendaDayTextColor: '#6d6d6d',
-
- // PROXIWASH
- proxiwashFinishedColor: '#31682c',
- proxiwashReadyColor: 'transparent',
- proxiwashRunningColor: '#213c79',
- proxiwashRunningNotStartedColor: '#1e263e',
- proxiwashRunningBgColor: '#1a2033',
- proxiwashBrokenColor: '#7e2e2f',
- proxiwashErrorColor: '#7e2e2f',
- proxiwashUnknownColor: '#535353',
-
- // Screens
- planningColor: '#d99e09',
- proximoColor: '#ec5904',
- proxiwashColor: '#1fa5ee',
- menuColor: '#b81213',
- tutorinsaColor: '#f93943',
-
- // Tetris
- tetrisBackground: '#181818',
- tetrisScore: '#e2d707',
- tetrisI: '#30b3be',
- tetrisO: '#c1a700',
- tetrisT: '#9114c7',
- tetrisS: '#08a121',
- tetrisZ: '#b50008',
- tetrisJ: '#0f37b9',
- tetrisL: '#b96226',
-
- gameGold: '#ffd610',
- gameSilver: '#7b7b7b',
- gameBronze: '#a15218',
-
- // Mascot Popup
- mascotMessageArrow: '#323232',
- },
- };
- }
-
- /**
- * Get this class instance or create one if none is found
- *
- * @returns {ThemeManager}
- */
- static getInstance(): ThemeManager {
- if (ThemeManager.instance == null)
- ThemeManager.instance = new ThemeManager();
- return ThemeManager.instance;
- }
-
- /**
- * Gets night mode status.
- * If Follow System Preferences is enabled, will first use system theme.
- * If disabled or not available, will use value stored din preferences
- *
- * @returns {boolean} Night mode state
- */
- static getNightMode(): boolean {
- return (
- (AsyncStorageManager.getBool(
- AsyncStorageManager.PREFERENCES.nightMode.key,
- ) &&
- (!AsyncStorageManager.getBool(
- AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
- ) ||
- colorScheme === 'no-preference')) ||
- (AsyncStorageManager.getBool(
- AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
- ) &&
- colorScheme === 'dark')
- );
- }
-
- /**
- * Get the current theme based on night mode and events
- *
- * @returns {CustomThemeType} The current theme
- */
- static getCurrentTheme(): CustomThemeType {
- if (AprilFoolsManager.getInstance().isAprilFoolsEnabled())
- return AprilFoolsManager.getAprilFoolsTheme(ThemeManager.getWhiteTheme());
- return ThemeManager.getBaseTheme();
- }
-
- /**
- * Get the theme based on night mode
- *
- * @return {CustomThemeType} The theme
- */
- static getBaseTheme(): CustomThemeType {
- if (ThemeManager.getNightMode()) return ThemeManager.getDarkTheme();
- return ThemeManager.getWhiteTheme();
- }
-
- /**
- * Sets the function to be called when the theme is changed (allows for general reload of the app)
- *
- * @param callback Function to call after theme change
- */
- setUpdateThemeCallback(callback: () => void) {
- this.updateThemeCallback = callback;
- }
-
- /**
- * Set night mode and save it to preferences
- *
- * @param isNightMode True to enable night mode, false to disable
- */
- setNightMode(isNightMode: boolean) {
- AsyncStorageManager.set(
- AsyncStorageManager.PREFERENCES.nightMode.key,
- isNightMode,
- );
- if (this.updateThemeCallback != null) this.updateThemeCallback();
- }
-}
diff --git a/src/managers/ThemeManager.ts b/src/managers/ThemeManager.ts
new file mode 100644
index 0000000..11c2b31
--- /dev/null
+++ b/src/managers/ThemeManager.ts
@@ -0,0 +1,298 @@
+/*
+ * Copyright (c) 2019 - 2020 Arnaud Vergnet.
+ *
+ * This file is part of Campus INSAT.
+ *
+ * Campus INSAT is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Campus INSAT is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Campus INSAT. If not, see .
+ */
+
+import {DarkTheme, DefaultTheme} from 'react-native-paper';
+import {Appearance} from 'react-native-appearance';
+import AsyncStorageManager from './AsyncStorageManager';
+import AprilFoolsManager from './AprilFoolsManager';
+
+const colorScheme = Appearance.getColorScheme();
+
+declare global {
+ namespace ReactNativePaper {
+ interface ThemeColors {
+ primary: string;
+ accent: string;
+ border: string;
+ tabIcon: string;
+ card: string;
+ dividerBackground: string;
+ ripple: string;
+ textDisabled: string;
+ icon: string;
+ subtitle: string;
+ success: string;
+ warning: string;
+ danger: string;
+
+ // Calendar/Agenda
+ agendaBackgroundColor: string;
+ agendaDayTextColor: string;
+
+ // PROXIWASH
+ proxiwashFinishedColor: string;
+ proxiwashReadyColor: string;
+ proxiwashRunningColor: string;
+ proxiwashRunningNotStartedColor: string;
+ proxiwashRunningBgColor: string;
+ proxiwashBrokenColor: string;
+ proxiwashErrorColor: string;
+ proxiwashUnknownColor: string;
+
+ // Screens
+ planningColor: string;
+ proximoColor: string;
+ proxiwashColor: string;
+ menuColor: string;
+ tutorinsaColor: string;
+
+ // Tetris
+ tetrisBackground: string;
+ tetrisScore: string;
+ tetrisI: string;
+ tetrisO: string;
+ tetrisT: string;
+ tetrisS: string;
+ tetrisZ: string;
+ tetrisJ: string;
+ tetrisL: string;
+
+ gameGold: string;
+ gameSilver: string;
+ gameBronze: string;
+
+ // Mascot Popup
+ mascotMessageArrow: string;
+ }
+ }
+}
+
+const CustomWhiteTheme: ReactNativePaper.Theme = {
+ ...DefaultTheme,
+ colors: {
+ ...DefaultTheme.colors,
+ primary: '#be1522',
+ accent: '#be1522',
+ border: '#e2e2e2',
+ tabIcon: '#929292',
+ card: '#fff',
+ dividerBackground: '#e2e2e2',
+ ripple: 'rgba(0,0,0,0.2)',
+ textDisabled: '#c1c1c1',
+ icon: '#5d5d5d',
+ subtitle: '#707070',
+ success: '#5cb85c',
+ warning: '#f0ad4e',
+ danger: '#d9534f',
+
+ // Calendar/Agenda
+ agendaBackgroundColor: '#f3f3f4',
+ agendaDayTextColor: '#636363',
+
+ // PROXIWASH
+ proxiwashFinishedColor: '#a5dc9d',
+ proxiwashReadyColor: 'transparent',
+ proxiwashRunningColor: '#a0ceff',
+ proxiwashRunningNotStartedColor: '#c9e0ff',
+ proxiwashRunningBgColor: '#c7e3ff',
+ proxiwashBrokenColor: '#ffa8a2',
+ proxiwashErrorColor: '#ffa8a2',
+ proxiwashUnknownColor: '#b6b6b6',
+
+ // Screens
+ planningColor: '#d9b10a',
+ proximoColor: '#ec5904',
+ proxiwashColor: '#1fa5ee',
+ menuColor: '#e91314',
+ tutorinsaColor: '#f93943',
+
+ // Tetris
+ tetrisBackground: '#f0f0f0',
+ tetrisScore: '#e2bd33',
+ tetrisI: '#3cd9e6',
+ tetrisO: '#ffdd00',
+ tetrisT: '#a716e5',
+ tetrisS: '#09c528',
+ tetrisZ: '#ff0009',
+ tetrisJ: '#2a67e3',
+ tetrisL: '#da742d',
+
+ gameGold: '#ffd610',
+ gameSilver: '#7b7b7b',
+ gameBronze: '#a15218',
+
+ // Mascot Popup
+ mascotMessageArrow: '#dedede',
+ },
+};
+
+const CustomDarkTheme: ReactNativePaper.Theme = {
+ ...DarkTheme,
+ colors: {
+ ...DarkTheme.colors,
+ primary: '#be1522',
+ accent: '#be1522',
+ border: '#222222',
+ tabIcon: '#6d6d6d',
+ card: 'rgb(18,18,18)',
+ dividerBackground: '#222222',
+ ripple: 'rgba(255,255,255,0.2)',
+ textDisabled: '#5b5b5b',
+ icon: '#b3b3b3',
+ subtitle: '#aaaaaa',
+ success: '#5cb85c',
+ warning: '#f0ad4e',
+ danger: '#d9534f',
+
+ // Calendar/Agenda
+ agendaBackgroundColor: '#171717',
+ agendaDayTextColor: '#6d6d6d',
+
+ // PROXIWASH
+ proxiwashFinishedColor: '#31682c',
+ proxiwashReadyColor: 'transparent',
+ proxiwashRunningColor: '#213c79',
+ proxiwashRunningNotStartedColor: '#1e263e',
+ proxiwashRunningBgColor: '#1a2033',
+ proxiwashBrokenColor: '#7e2e2f',
+ proxiwashErrorColor: '#7e2e2f',
+ proxiwashUnknownColor: '#535353',
+
+ // Screens
+ planningColor: '#d99e09',
+ proximoColor: '#ec5904',
+ proxiwashColor: '#1fa5ee',
+ menuColor: '#b81213',
+ tutorinsaColor: '#f93943',
+
+ // Tetris
+ tetrisBackground: '#181818',
+ tetrisScore: '#e2d707',
+ tetrisI: '#30b3be',
+ tetrisO: '#c1a700',
+ tetrisT: '#9114c7',
+ tetrisS: '#08a121',
+ tetrisZ: '#b50008',
+ tetrisJ: '#0f37b9',
+ tetrisL: '#b96226',
+
+ gameGold: '#ffd610',
+ gameSilver: '#7b7b7b',
+ gameBronze: '#a15218',
+
+ // Mascot Popup
+ mascotMessageArrow: '#323232',
+ },
+};
+
+/**
+ * Singleton class used to manage themes
+ */
+export default class ThemeManager {
+ static instance: ThemeManager | null = null;
+
+ updateThemeCallback: null | (() => void);
+
+ constructor() {
+ this.updateThemeCallback = null;
+ }
+
+ /**
+ * Get this class instance or create one if none is found
+ *
+ * @returns {ThemeManager}
+ */
+ static getInstance(): ThemeManager {
+ if (ThemeManager.instance == null) {
+ ThemeManager.instance = new ThemeManager();
+ }
+ return ThemeManager.instance;
+ }
+
+ /**
+ * Gets night mode status.
+ * If Follow System Preferences is enabled, will first use system theme.
+ * If disabled or not available, will use value stored din preferences
+ *
+ * @returns {boolean} Night mode state
+ */
+ static getNightMode(): boolean {
+ return (
+ (AsyncStorageManager.getBool(
+ AsyncStorageManager.PREFERENCES.nightMode.key,
+ ) &&
+ (!AsyncStorageManager.getBool(
+ AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
+ ) ||
+ colorScheme === 'no-preference')) ||
+ (AsyncStorageManager.getBool(
+ AsyncStorageManager.PREFERENCES.nightModeFollowSystem.key,
+ ) &&
+ colorScheme === 'dark')
+ );
+ }
+
+ /**
+ * Get the current theme based on night mode and events
+ *
+ * @returns {ReactNativePaper.Theme} The current theme
+ */
+ static getCurrentTheme(): ReactNativePaper.Theme {
+ if (AprilFoolsManager.getInstance().isAprilFoolsEnabled()) {
+ return AprilFoolsManager.getAprilFoolsTheme(CustomWhiteTheme);
+ }
+ return ThemeManager.getBaseTheme();
+ }
+
+ /**
+ * Get the theme based on night mode
+ *
+ * @return {ReactNativePaper.Theme} The theme
+ */
+ static getBaseTheme(): ReactNativePaper.Theme {
+ if (ThemeManager.getNightMode()) {
+ return CustomDarkTheme;
+ }
+ return CustomWhiteTheme;
+ }
+
+ /**
+ * Sets the function to be called when the theme is changed (allows for general reload of the app)
+ *
+ * @param callback Function to call after theme change
+ */
+ setUpdateThemeCallback(callback: () => void) {
+ this.updateThemeCallback = callback;
+ }
+
+ /**
+ * Set night mode and save it to preferences
+ *
+ * @param isNightMode True to enable night mode, false to disable
+ */
+ setNightMode(isNightMode: boolean) {
+ AsyncStorageManager.set(
+ AsyncStorageManager.PREFERENCES.nightMode.key,
+ isNightMode,
+ );
+ if (this.updateThemeCallback != null) {
+ this.updateThemeCallback();
+ }
+ }
+}