import { omit } from 'lodash' ; import React , { useCallback , useContext } from 'react' ; import { useLocalStorage } from 'react-use' ; import { dictionaries , Dictionary } from 'resources/dictionary' ; export type PronunciationType = 'us' | 'uk' | 'jap' | false ; export type AppState = { /**
     * Whether the sound is enabled.
     */ sound : boolean ; /**
     * Available dictionaries.
     * This field should not be written to `localStorage`.
     */ dictionaries : Dictionary [ ] ; /**
     * The selected dictionary.
     */ selectedDictionary : Dictionary ; /**
     * Which type of pronunciation is used.
     * Available options: `"us"`, `"uk"`, `"jap"`and `false`.
     */ pronunciation : PronunciationType ; /**
     * The selected chapter number.
     */ selectedChapter : number ; /**
     * Whether dark mode is enabled
     */ darkMode : boolean ; } ; export type AppStateData = { state : AppState ; dispatch : ( state : AppState ) => void ; } ; const AppStateContext = React . createContext < AppStateData > ( { } as AppStateData ) ; /**
 * Get the global app state.
 */ export function useAppState ( ) { const { state } = useContext ( AppStateContext ) ; return state ; } export function useSetSoundState ( ) { const { state , dispatch } = useContext ( AppStateContext ) ; const setSound = useCallback ( ( sound ) => dispatch ( { ... state , sound } ) , [ state , dispatch ] ) ; return [ state . sound , setSound ] ; } /**
 * Use all available dictionaries.
 */ export function useDictionaries ( ) { const { state } = useContext ( AppStateContext ) ; return state . dictionaries ; } export function useSetDictionary ( ) { const { state , dispatch } = useContext ( AppStateContext ) ; return ( id ) => { const found = dictionaries . find ( ( dict ) => dict . id === id ) ; if ( found !== undefined ) { const lastChapterNumber = Math . floor ( found . length / 20 ) ; dispatch ( { ... state , selectedDictionary : found , selectedChapter : Math . min ( state . selectedChapter , lastChapterNumber ) } ) ; } } ; } /**
 * Use the current selected dictionary.
 */ export function useSelectedDictionary ( ) { const { state } = useContext ( AppStateContext ) ; return state . selectedDictionary ; } export function useSetPronunciationState ( ) { const { state , dispatch } = useContext ( AppStateContext ) ; const setPronunciation = useCallback ( ( pronunciation ) => dispatch ( { ... state , pronunciation } ) , [ state , dispatch ] ) ; return [ state . pronunciation , setPronunciation ] ; } /**
 * Use the current selected chapter.
 */ export function useSelectedChapter ( ) { const { state , dispatch } = useContext ( AppStateContext ) ; return [ state . selectedChapter , ( selectedChapter ) : void => dispatch ( { ... state , selectedChapter } ) ] ; } /**
 * Dark Mode
 */ export function useDarkMode ( ) { const { state , dispatch } = useContext ( AppStateContext ) ; const setDarkMode = useCallback ( ( darkMode ) => { dispatch ( { ... state , darkMode } ) ; darkMode ? document . documentElement . classList . add ( 'dark' ) : document . documentElement . classList . remove ( 'dark' ) ; } , [ state , dispatch ] ) ; return [ state . darkMode , setDarkMode ] ; } const defaultState = { sound : true , dictionaries , selectedDictionary : dictionaries [ 0 ] , pronunciation : 'us' , selectedChapter : 0 , darkMode : window . matchMedia ( '(prefers-color-scheme: dark)' ) . matches , } ; export const AppStateProvider = ( { children } ) => { const [ state , setState ] = useLocalStorage < AppState > ( 'state' , defaultState , options ) ; return < AppStateContext . Provider value = { { state : state ! , dispatch : setState } } > { children } < /AppStateContext.Provider>; } ; const options = { raw : false , serializer ( state ) { return JSON . stringify ( omit ( state , 'dictionaries' ) ) ; } , deserializer ( source ) { const state = JSON . parse ( source ) ; state . dictionaries = dictionaries ; return state ; } , } ;