Update App.tsx and related files to use TypeScript
This commit is contained in:
parent
54486d1deb
commit
375fc8b971
4 changed files with 334 additions and 341 deletions
|
@ -17,8 +17,6 @@
|
||||||
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// @flow
|
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import {LogBox, Platform, SafeAreaView, View} from 'react-native';
|
import {LogBox, Platform, SafeAreaView, View} from 'react-native';
|
||||||
import {NavigationContainer} from '@react-navigation/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 {OverflowMenuProvider} from 'react-navigation-header-buttons';
|
||||||
import AsyncStorageManager from './src/managers/AsyncStorageManager';
|
import AsyncStorageManager from './src/managers/AsyncStorageManager';
|
||||||
import CustomIntroSlider from './src/components/Overrides/CustomIntroSlider';
|
import CustomIntroSlider from './src/components/Overrides/CustomIntroSlider';
|
||||||
import type {CustomThemeType} from './src/managers/ThemeManager';
|
|
||||||
import ThemeManager from './src/managers/ThemeManager';
|
import ThemeManager from './src/managers/ThemeManager';
|
||||||
import MainNavigator from './src/navigation/MainNavigator';
|
import MainNavigator from './src/navigation/MainNavigator';
|
||||||
import AprilFoolsManager from './src/managers/AprilFoolsManager';
|
import AprilFoolsManager from './src/managers/AprilFoolsManager';
|
||||||
|
@ -38,6 +35,7 @@ import type {ParsedUrlDataType} from './src/utils/URLHandler';
|
||||||
import URLHandler from './src/utils/URLHandler';
|
import URLHandler from './src/utils/URLHandler';
|
||||||
import {setupStatusBar} from './src/utils/Utils';
|
import {setupStatusBar} from './src/utils/Utils';
|
||||||
import initLocales from './src/utils/Locales';
|
import initLocales from './src/utils/Locales';
|
||||||
|
import {NavigationContainerRef} from '@react-navigation/core';
|
||||||
|
|
||||||
// Native optimizations https://reactnavigation.org/docs/react-native-screens
|
// Native optimizations https://reactnavigation.org/docs/react-native-screens
|
||||||
// Crashes app when navigating away from webview on android 9+
|
// Crashes app when navigating away from webview on android 9+
|
||||||
|
@ -50,15 +48,15 @@ LogBox.ignoreLogs([
|
||||||
]);
|
]);
|
||||||
|
|
||||||
type StateType = {
|
type StateType = {
|
||||||
isLoading: boolean,
|
isLoading: boolean;
|
||||||
showIntro: boolean,
|
showIntro: boolean;
|
||||||
showUpdate: boolean,
|
showUpdate: boolean;
|
||||||
showAprilFools: boolean,
|
showAprilFools: boolean;
|
||||||
currentTheme: CustomThemeType | null,
|
currentTheme: ReactNativePaper.Theme | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class App extends React.Component<null, StateType> {
|
export default class App extends React.Component<null, StateType> {
|
||||||
navigatorRef: {current: null | NavigationContainer};
|
navigatorRef: {current: null | NavigationContainerRef};
|
||||||
|
|
||||||
defaultHomeRoute: string | null;
|
defaultHomeRoute: string | null;
|
||||||
|
|
||||||
|
@ -67,13 +65,13 @@ export default class App extends React.Component<null, StateType> {
|
||||||
urlHandler: URLHandler;
|
urlHandler: URLHandler;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super(null);
|
||||||
this.state = {
|
this.state = {
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
showIntro: true,
|
showIntro: true,
|
||||||
showUpdate: true,
|
showUpdate: true,
|
||||||
showAprilFools: false,
|
showAprilFools: false,
|
||||||
currentTheme: null,
|
currentTheme: undefined,
|
||||||
};
|
};
|
||||||
initLocales();
|
initLocales();
|
||||||
this.navigatorRef = React.createRef();
|
this.navigatorRef = React.createRef();
|
||||||
|
@ -155,8 +153,11 @@ export default class App extends React.Component<null, StateType> {
|
||||||
// Only show intro if this is the first time starting the app
|
// Only show intro if this is the first time starting the app
|
||||||
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
|
ThemeManager.getInstance().setUpdateThemeCallback(this.onUpdateTheme);
|
||||||
// Status bar goes dark if set too fast on ios
|
// Status bar goes dark if set too fast on ios
|
||||||
if (Platform.OS === 'ios') setTimeout(setupStatusBar, 1000);
|
if (Platform.OS === 'ios') {
|
||||||
else setupStatusBar();
|
setTimeout(setupStatusBar, 1000);
|
||||||
|
} else {
|
||||||
|
setupStatusBar();
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
isLoading: false,
|
isLoading: false,
|
||||||
|
@ -192,7 +193,7 @@ export default class App extends React.Component<null, StateType> {
|
||||||
/**
|
/**
|
||||||
* Renders the app based on loading state
|
* Renders the app based on loading state
|
||||||
*/
|
*/
|
||||||
render(): React.Node {
|
render() {
|
||||||
const {state} = this;
|
const {state} = this;
|
||||||
if (state.isLoading) {
|
if (state.isLoading) {
|
||||||
return null;
|
return null;
|
|
@ -17,8 +17,6 @@
|
||||||
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
* along with Campus INSAT. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// @flow
|
|
||||||
|
|
||||||
import AsyncStorage from '@react-native-community/async-storage';
|
import AsyncStorage from '@react-native-community/async-storage';
|
||||||
import {SERVICES_KEY} from './ServicesManager';
|
import {SERVICES_KEY} from './ServicesManager';
|
||||||
|
|
||||||
|
@ -31,7 +29,7 @@ import {SERVICES_KEY} from './ServicesManager';
|
||||||
export default class AsyncStorageManager {
|
export default class AsyncStorageManager {
|
||||||
static instance: AsyncStorageManager | null = null;
|
static instance: AsyncStorageManager | null = null;
|
||||||
|
|
||||||
static PREFERENCES = {
|
static PREFERENCES: {[key: string]: {key: string; default: string}} = {
|
||||||
debugUnlocked: {
|
debugUnlocked: {
|
||||||
key: 'debugUnlocked',
|
key: 'debugUnlocked',
|
||||||
default: '0',
|
default: '0',
|
||||||
|
@ -132,10 +130,10 @@ export default class AsyncStorageManager {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#currentPreferences: {[key: string]: string};
|
private currentPreferences: {[key: string]: string};
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.#currentPreferences = {};
|
this.currentPreferences = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -143,8 +141,9 @@ export default class AsyncStorageManager {
|
||||||
* @returns {AsyncStorageManager}
|
* @returns {AsyncStorageManager}
|
||||||
*/
|
*/
|
||||||
static getInstance(): AsyncStorageManager {
|
static getInstance(): AsyncStorageManager {
|
||||||
if (AsyncStorageManager.instance == null)
|
if (AsyncStorageManager.instance == null) {
|
||||||
AsyncStorageManager.instance = new AsyncStorageManager();
|
AsyncStorageManager.instance = new AsyncStorageManager();
|
||||||
|
}
|
||||||
return AsyncStorageManager.instance;
|
return AsyncStorageManager.instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,8 +155,7 @@ export default class AsyncStorageManager {
|
||||||
*/
|
*/
|
||||||
static set(
|
static set(
|
||||||
key: string,
|
key: string,
|
||||||
// eslint-disable-next-line flowtype/no-weak-types
|
value: number | string | boolean | object | Array<any>,
|
||||||
value: number | string | boolean | {...} | Array<any>,
|
|
||||||
) {
|
) {
|
||||||
AsyncStorageManager.getInstance().setPreference(key, value);
|
AsyncStorageManager.getInstance().setPreference(key, value);
|
||||||
}
|
}
|
||||||
|
@ -200,8 +198,7 @@ export default class AsyncStorageManager {
|
||||||
* @param key
|
* @param key
|
||||||
* @returns {{...}}
|
* @returns {{...}}
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line flowtype/no-weak-types
|
static getObject(key: string): object | Array<any> {
|
||||||
static getObject(key: string): any {
|
|
||||||
return JSON.parse(AsyncStorageManager.getString(key));
|
return JSON.parse(AsyncStorageManager.getString(key));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,7 +209,7 @@ export default class AsyncStorageManager {
|
||||||
* @return {Promise<void>}
|
* @return {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async loadPreferences() {
|
async loadPreferences() {
|
||||||
const prefKeys = [];
|
const prefKeys: Array<string> = [];
|
||||||
// Get all available keys
|
// Get all available keys
|
||||||
Object.keys(AsyncStorageManager.PREFERENCES).forEach((key: string) => {
|
Object.keys(AsyncStorageManager.PREFERENCES).forEach((key: string) => {
|
||||||
prefKeys.push(key);
|
prefKeys.push(key);
|
||||||
|
@ -223,8 +220,10 @@ export default class AsyncStorageManager {
|
||||||
resultArray.forEach((item: [string, string | null]) => {
|
resultArray.forEach((item: [string, string | null]) => {
|
||||||
const key = item[0];
|
const key = item[0];
|
||||||
let val = item[1];
|
let val = item[1];
|
||||||
if (val === null) val = AsyncStorageManager.PREFERENCES[key].default;
|
if (val === null) {
|
||||||
this.#currentPreferences[key] = val;
|
val = AsyncStorageManager.PREFERENCES[key].default;
|
||||||
|
}
|
||||||
|
this.currentPreferences[key] = val;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,16 +236,18 @@ export default class AsyncStorageManager {
|
||||||
*/
|
*/
|
||||||
setPreference(
|
setPreference(
|
||||||
key: string,
|
key: string,
|
||||||
// eslint-disable-next-line flowtype/no-weak-types
|
value: number | string | boolean | object | Array<any>,
|
||||||
value: number | string | boolean | {...} | Array<any>,
|
|
||||||
) {
|
) {
|
||||||
if (AsyncStorageManager.PREFERENCES[key] != null) {
|
if (AsyncStorageManager.PREFERENCES[key] != null) {
|
||||||
let convertedValue;
|
let convertedValue;
|
||||||
if (typeof value === 'string') convertedValue = value;
|
if (typeof value === 'string') {
|
||||||
else if (typeof value === 'boolean' || typeof value === 'number')
|
convertedValue = value;
|
||||||
|
} else if (typeof value === 'boolean' || typeof value === 'number') {
|
||||||
convertedValue = value.toString();
|
convertedValue = value.toString();
|
||||||
else convertedValue = JSON.stringify(value);
|
} else {
|
||||||
this.#currentPreferences[key] = convertedValue;
|
convertedValue = JSON.stringify(value);
|
||||||
|
}
|
||||||
|
this.currentPreferences[key] = convertedValue;
|
||||||
AsyncStorage.setItem(key, convertedValue);
|
AsyncStorage.setItem(key, convertedValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -259,6 +260,6 @@ export default class AsyncStorageManager {
|
||||||
* @returns {string|null}
|
* @returns {string|null}
|
||||||
*/
|
*/
|
||||||
getPreference(key: string): string | null {
|
getPreference(key: string): string | null {
|
||||||
return this.#currentPreferences[key];
|
return this.currentPreferences[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
// @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();
|
|
||||||
}
|
|
||||||
}
|
|
298
src/managers/ThemeManager.ts
Normal file
298
src/managers/ThemeManager.ts
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue