diff options
author | Paul Frazee <pfrazee@gmail.com> | 2023-11-08 09:38:28 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-11-08 09:38:28 -0800 |
commit | 5843e212c0ebbfc6c3831929bbbaa72e1a289aba (patch) | |
tree | 08b6beed54700c56b65edbff32dc32baae0a4208 /src/state/preferences | |
parent | e75b2d508baf9b19e7340657ac2951e9f057b735 (diff) | |
download | voidsky-5843e212c0ebbfc6c3831929bbbaa72e1a289aba.tar.zst |
Move language preferences to new persistence + context (#1837)
Diffstat (limited to 'src/state/preferences')
-rw-r--r-- | src/state/preferences/index.tsx | 8 | ||||
-rw-r--r-- | src/state/preferences/languages.tsx | 122 |
2 files changed, 130 insertions, 0 deletions
diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx new file mode 100644 index 000000000..56c93f812 --- /dev/null +++ b/src/state/preferences/index.tsx @@ -0,0 +1,8 @@ +import React from 'react' +import {Provider as LanguagesProvider} from './languages' + +export {useLanguagePrefs, useSetLanguagePrefs} from './languages' + +export function Provider({children}: React.PropsWithChildren<{}>) { + return <LanguagesProvider>{children}</LanguagesProvider> +} diff --git a/src/state/preferences/languages.tsx b/src/state/preferences/languages.tsx new file mode 100644 index 000000000..49b63550d --- /dev/null +++ b/src/state/preferences/languages.tsx @@ -0,0 +1,122 @@ +import React from 'react' +import * as persisted from '#/state/persisted' + +type SetStateCb = ( + v: persisted.Schema['languagePrefs'], +) => persisted.Schema['languagePrefs'] +type StateContext = persisted.Schema['languagePrefs'] +type SetContext = (fn: SetStateCb) => void + +const stateContext = React.createContext<StateContext>( + persisted.defaults.languagePrefs, +) +const setContext = React.createContext<SetContext>((_: SetStateCb) => {}) + +export function Provider({children}: React.PropsWithChildren<{}>) { + const [state, setState] = React.useState(persisted.get('languagePrefs')) + + const setStateWrapped = React.useCallback( + (fn: SetStateCb) => { + const v = fn(persisted.get('languagePrefs')) + setState(v) + persisted.write('languagePrefs', v) + }, + [setState], + ) + + React.useEffect(() => { + return persisted.onUpdate(() => { + setState(persisted.get('languagePrefs')) + }) + }, [setStateWrapped]) + + return ( + <stateContext.Provider value={state}> + <setContext.Provider value={setStateWrapped}> + {children} + </setContext.Provider> + </stateContext.Provider> + ) +} + +export function useLanguagePrefs() { + return React.useContext(stateContext) +} + +export function useSetLanguagePrefs() { + return React.useContext(setContext) +} + +export function getContentLanguages() { + return persisted.get('languagePrefs').contentLanguages +} + +export function toggleContentLanguage( + state: StateContext, + setState: SetContext, + code2: string, +) { + if (state.contentLanguages.includes(code2)) { + setState(v => ({ + ...v, + contentLanguages: v.contentLanguages.filter(lang => lang !== code2), + })) + } else { + setState(v => ({ + ...v, + contentLanguages: v.contentLanguages.concat(code2), + })) + } +} + +export function toPostLanguages(postLanguage: string): string[] { + // filter out empty strings if exist + return postLanguage.split(',').filter(Boolean) +} + +export function hasPostLanguage(postLanguage: string, code2: string): boolean { + return toPostLanguages(postLanguage).includes(code2) +} + +export function togglePostLanguage( + state: StateContext, + setState: SetContext, + code2: string, +) { + if (hasPostLanguage(state.postLanguage, code2)) { + setState(v => ({ + ...v, + postLanguage: toPostLanguages(v.postLanguage) + .filter(lang => lang !== code2) + .join(','), + })) + } else { + // sort alphabetically for deterministic comparison in context menu + setState(v => ({ + ...v, + postLanguage: toPostLanguages(v.postLanguage) + .concat([code2]) + .sort((a, b) => a.localeCompare(b)) + .join(','), + })) + } +} + +/** + * Saves whatever language codes are currently selected into a history array, + * which is then used to populate the language selector menu. + */ +export function savePostLanguageToHistory(setState: SetContext) { + // filter out duplicate `this.postLanguage` if exists, and prepend + // value to start of array + setState(v => ({ + ...v, + postLanguageHistory: [v.postLanguage] + .concat( + v.postLanguageHistory.filter( + commaSeparatedLangCodes => commaSeparatedLangCodes !== v.postLanguage, + ), + ) + .slice(0, 6), + })) +} |