diff --git a/package-lock.json b/package-lock.json index c7f1625..af562a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1998,10 +1998,10 @@ "fastq": "^1.6.0" } }, - "@react-native-community/async-storage": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/@react-native-community/async-storage/-/async-storage-1.12.1.tgz", - "integrity": "sha512-70WGaH3PKYASi4BThuEEKMkyAgE9k7VytBqmgPRx3MzJx9/MkspwqJGmn3QLCgHLIFUgF1pit2mWICbRJ3T3lg==", + "@react-native-async-storage/async-storage": { + "version": "1.15.4", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.15.4.tgz", + "integrity": "sha512-pC0MS6UBuv/YiVAxtzi7CgUed8oCQNYMtGt0yb/I9fI/BWTiJK5cj4YtW2XtL95K5IuvPX/6uGWaouZ8KqXwdg==", "requires": { "deep-assign": "^3.0.0" } diff --git a/package.json b/package.json index c34ca1d..2eef2cf 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ }, "dependencies": { "@nartc/react-native-barcode-mask": "1.2.0", - "@react-native-community/async-storage": "1.12.1", + "@react-native-async-storage/async-storage": "^1.15.4", "@react-native-community/masked-view": "0.1.11", "@react-native-community/push-notification-ios": "1.8.0", "@react-native-community/slider": "3.0.3", diff --git a/src/components/providers/PreferencesProvider.tsx b/src/components/providers/PreferencesProvider.tsx new file mode 100644 index 0000000..d5ef6e1 --- /dev/null +++ b/src/components/providers/PreferencesProvider.tsx @@ -0,0 +1,67 @@ +import React, { useState } from 'react'; +import { + defaultPreferences, + PreferenceKeys, + PreferencesType, + setPreference, +} from '../../utils/asyncStorage'; +import { + PreferencesContext, + PreferencesContextType, +} from '../../utils/preferencesContext'; + +type Props = { + children: React.ReactChild; + initialPreferences: PreferencesType; +}; + +export default function PreferencesProvider(props: Props) { + const updatePreferences = ( + key: PreferenceKeys, + value: number | string | boolean | object | Array + ) => { + setPreferencesState((prevState) => { + const prevPreferences = { ...prevState.preferences }; + const newPrefs = setPreference(key, value, prevPreferences); + const newSate = { + ...prevState, + preferences: { ...newPrefs }, + }; + return newSate; + }); + }; + + const resetPreferences = () => { + setPreferencesState((prevState) => { + const prevPreferences = { ...prevState.preferences }; + let newPreferences = { ...prevPreferences }; + Object.values(PreferenceKeys).forEach((key) => { + newPreferences = setPreference( + key, + defaultPreferences[key], + prevPreferences + ); + }); + const newSate = { + ...prevState, + preferences: { ...newPreferences }, + }; + return newSate; + }); + }; + + const [ + preferencesState, + setPreferencesState, + ] = useState({ + preferences: { ...props.initialPreferences }, + updatePreferences: updatePreferences, + resetPreferences: resetPreferences, + }); + + return ( + + {props.children} + + ); +} diff --git a/src/managers/AsyncStorageManager.ts b/src/managers/AsyncStorageManager.ts index 178cef0..8db73a0 100644 --- a/src/managers/AsyncStorageManager.ts +++ b/src/managers/AsyncStorageManager.ts @@ -17,7 +17,7 @@ * along with Campus INSAT. If not, see . */ -import AsyncStorage from '@react-native-community/async-storage'; +import AsyncStorage from '@react-native-async-storage/async-storage'; import { SERVICES_KEY } from './ServicesManager'; /** diff --git a/src/utils/asyncStorage.ts b/src/utils/asyncStorage.ts new file mode 100644 index 0000000..0755e68 --- /dev/null +++ b/src/utils/asyncStorage.ts @@ -0,0 +1,170 @@ +import AsyncStorage from '@react-native-async-storage/async-storage'; +import { SERVICES_KEY } from '../managers/ServicesManager'; + +export enum PreferenceKeys { + debugUnlocked = 'debugUnlocked', + showIntro = 'showIntro', + updateNumber = 'updateNumber', + proxiwashNotifications = 'proxiwashNotifications', + nightModeFollowSystem = 'nightModeFollowSystem', + nightMode = 'nightMode', + defaultStartScreen = 'defaultStartScreen', + servicesShowMascot = 'servicesShowMascot', + proxiwashShowMascot = 'proxiwashShowMascot', + homeShowMascot = 'homeShowMascot', + eventsShowMascot = 'eventsShowMascot', + planexShowMascot = 'planexShowMascot', + loginShowMascot = 'loginShowMascot', + voteShowMascot = 'voteShowMascot', + equipmentShowMascot = 'equipmentShowMascot', + gameStartMascot = 'gameStartMascot', + proxiwashWatchedMachines = 'proxiwashWatchedMachines', + showAprilFoolsStart = 'showAprilFoolsStart', + planexCurrentGroup = 'planexCurrentGroup', + planexFavoriteGroups = 'planexFavoriteGroups', + dashboardItems = 'dashboardItems', + gameScores = 'gameScores', + selectedWash = 'selectedWash', +} + +export type PreferencesType = { [key in PreferenceKeys]: string }; + +export const defaultPreferences: { [key in PreferenceKeys]: string } = { + [PreferenceKeys.debugUnlocked]: '0', + [PreferenceKeys.showIntro]: '1', + [PreferenceKeys.updateNumber]: '0', + [PreferenceKeys.proxiwashNotifications]: '5', + [PreferenceKeys.nightModeFollowSystem]: '1', + [PreferenceKeys.nightMode]: '1', + [PreferenceKeys.defaultStartScreen]: 'home', + [PreferenceKeys.servicesShowMascot]: '1', + [PreferenceKeys.proxiwashShowMascot]: '1', + [PreferenceKeys.homeShowMascot]: '1', + [PreferenceKeys.eventsShowMascot]: '1', + [PreferenceKeys.planexShowMascot]: '1', + [PreferenceKeys.loginShowMascot]: '1', + [PreferenceKeys.voteShowMascot]: '1', + [PreferenceKeys.equipmentShowMascot]: '1', + [PreferenceKeys.gameStartMascot]: '1', + [PreferenceKeys.proxiwashWatchedMachines]: '[]', + [PreferenceKeys.showAprilFoolsStart]: '1', + [PreferenceKeys.planexCurrentGroup]: '', + [PreferenceKeys.planexFavoriteGroups]: '[]', + [PreferenceKeys.dashboardItems]: JSON.stringify([ + SERVICES_KEY.EMAIL, + SERVICES_KEY.WASHERS, + SERVICES_KEY.PROXIMO, + SERVICES_KEY.TUTOR_INSA, + SERVICES_KEY.RU, + ]), + [PreferenceKeys.gameScores]: '[]', + [PreferenceKeys.selectedWash]: 'washinsa', +}; + +/** + * Set preferences object current values from AsyncStorage. + * This function should be called once on start. + * + * @return {Promise} + */ +export function retrievePreferences( + keys: Array, + defaults: PreferencesType +): Promise { + return new Promise((resolve: (preferences: PreferencesType) => void) => { + AsyncStorage.multiGet(Object.values(keys)) + .then((result) => { + const preferences = { ...defaults }; + result.forEach((item) => { + let [key, value] = item; + if (value !== null) { + preferences[key as PreferenceKeys] = value; + } + }); + resolve(preferences); + }) + .catch(() => resolve(defaults)); + }); +} + +/** + * Saves the value associated to the given key to preferences. + * This updates the preferences object and saves it to AsyncStorage. + * + * @param key + * @param value + */ +export function setPreference( + key: PreferenceKeys, + value: number | string | boolean | object | Array, + prevPreferences: PreferencesType +): PreferencesType { + let convertedValue: string; + if (typeof value === 'string') { + convertedValue = value; + } else if (typeof value === 'boolean' || typeof value === 'number') { + convertedValue = value.toString(); + } else { + convertedValue = JSON.stringify(value); + } + prevPreferences[key] = convertedValue; + AsyncStorage.setItem(key, convertedValue) + .then(undefined) + .catch(() => console.debug('save error: ' + convertedValue)); + return prevPreferences; +} + +/** + * Gets the boolean value of the given preference + * + * @param key + * @returns {boolean} + */ +export function getPreferenceString( + key: PreferenceKeys, + preferences: PreferencesType +): string | undefined { + return preferences[key]; +} + +/** + * Gets the boolean value of the given preference + * + * @param key + * @returns {boolean} + */ +export function getPreferenceBool( + key: PreferenceKeys, + preferences: PreferencesType +): boolean | undefined { + const value = preferences[key]; + return value ? value === '1' || value === 'true' : undefined; +} + +/** + * Gets the number value of the given preference + * + * @param key + * @returns {number} + */ +export function getPreferenceNumber( + key: PreferenceKeys, + preferences: PreferencesType +): number | undefined { + const value = preferences[key]; + return value !== undefined ? parseFloat(value) : undefined; +} + +/** + * Gets the object value of the given preference + * + * @param key + * @returns {{...}} + */ +export function getPreferenceObject( + key: PreferenceKeys, + preferences: PreferencesType +): object | Array | undefined { + const value = preferences[key]; + return value ? JSON.parse(value) : undefined; +} diff --git a/src/utils/preferencesContext.ts b/src/utils/preferencesContext.ts new file mode 100644 index 0000000..5ea2a16 --- /dev/null +++ b/src/utils/preferencesContext.ts @@ -0,0 +1,25 @@ +import React, { useContext } from 'react'; +import { + defaultPreferences, + PreferenceKeys, + PreferencesType, +} from './asyncStorage'; + +export type PreferencesContextType = { + preferences: PreferencesType; + updatePreferences: ( + key: PreferenceKeys, + value: number | string | boolean | object | Array + ) => void; + resetPreferences: () => void; +}; + +export const PreferencesContext = React.createContext({ + preferences: defaultPreferences, + updatePreferences: () => undefined, + resetPreferences: () => undefined, +}); + +export function usePreferences() { + return useContext(PreferencesContext); +}