From bd531f2344c181261afaf8c43c96daf569b58f09 Mon Sep 17 00:00:00 2001 From: Eric Bailey Date: Wed, 8 Nov 2023 13:55:38 -0600 Subject: [PATCH] Pull language methods into api context (#1847) * Pull language methods into api context * Rename for consistency --- src/state/preferences/index.tsx | 2 +- src/state/preferences/languages.tsx | 159 ++++++++++-------- src/view/com/composer/Composer.tsx | 7 +- .../select-language/SelectLangBtn.tsx | 6 +- .../ContentLanguagesSettings.tsx | 9 +- .../lang-settings/PostLanguagesSettings.tsx | 9 +- src/view/screens/LanguageSettings.tsx | 6 +- 7 files changed, 105 insertions(+), 93 deletions(-) diff --git a/src/state/preferences/index.tsx b/src/state/preferences/index.tsx index 50cb86c6..1f4348cf 100644 --- a/src/state/preferences/index.tsx +++ b/src/state/preferences/index.tsx @@ -2,7 +2,7 @@ import React from 'react' import {Provider as LanguagesProvider} from './languages' import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required' -export {useLanguagePrefs, useSetLanguagePrefs} from './languages' +export {useLanguagePrefs, useLanguagePrefsApi} from './languages' export { useRequireAltTextEnabled, useSetRequireAltTextEnabled, diff --git a/src/state/preferences/languages.tsx b/src/state/preferences/languages.tsx index 49b63550..95cf6741 100644 --- a/src/state/preferences/languages.tsx +++ b/src/state/preferences/languages.tsx @@ -2,24 +2,36 @@ import React from 'react' import * as persisted from '#/state/persisted' type SetStateCb = ( - v: persisted.Schema['languagePrefs'], + s: persisted.Schema['languagePrefs'], ) => persisted.Schema['languagePrefs'] type StateContext = persisted.Schema['languagePrefs'] -type SetContext = (fn: SetStateCb) => void +type ApiContext = { + setPrimaryLanguage: (code2: string) => void + setPostLanguage: (commaSeparatedLangCodes: string) => void + toggleContentLanguage: (code2: string) => void + togglePostLanguage: (code2: string) => void + savePostLanguageToHistory: () => void +} const stateContext = React.createContext( persisted.defaults.languagePrefs, ) -const setContext = React.createContext((_: SetStateCb) => {}) +const apiContext = React.createContext({ + setPrimaryLanguage: (_: string) => {}, + setPostLanguage: (_: string) => {}, + toggleContentLanguage: (_: string) => {}, + togglePostLanguage: (_: string) => {}, + savePostLanguageToHistory: () => {}, +}) 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) + const s = fn(persisted.get('languagePrefs')) + setState(s) + persisted.write('languagePrefs', s) }, [setState], ) @@ -30,11 +42,75 @@ export function Provider({children}: React.PropsWithChildren<{}>) { }) }, [setStateWrapped]) + const api = React.useMemo( + () => ({ + setPrimaryLanguage(code2: string) { + setStateWrapped(s => ({...s, primaryLanguage: code2})) + }, + setPostLanguage(commaSeparatedLangCodes: string) { + setStateWrapped(s => ({...s, postLanguage: commaSeparatedLangCodes})) + }, + toggleContentLanguage(code2: string) { + setStateWrapped(s => { + const exists = s.contentLanguages.includes(code2) + const next = exists + ? s.contentLanguages.filter(lang => lang !== code2) + : s.contentLanguages.concat(code2) + return { + ...s, + contentLanguages: next, + } + }) + }, + togglePostLanguage(code2: string) { + setStateWrapped(s => { + const exists = hasPostLanguage(state.postLanguage, code2) + let next = s.postLanguage + + if (exists) { + next = toPostLanguages(s.postLanguage) + .filter(lang => lang !== code2) + .join(',') + } else { + // sort alphabetically for deterministic comparison in context menu + next = toPostLanguages(s.postLanguage) + .concat([code2]) + .sort((a, b) => a.localeCompare(b)) + .join(',') + } + + return { + ...s, + postLanguage: next, + } + }) + }, + /** + * Saves whatever language codes are currently selected into a history array, + * which is then used to populate the language selector menu. + */ + savePostLanguageToHistory() { + // filter out duplicate `this.postLanguage` if exists, and prepend + // value to start of array + setStateWrapped(s => ({ + ...s, + postLanguageHistory: [s.postLanguage] + .concat( + s.postLanguageHistory.filter( + commaSeparatedLangCodes => + commaSeparatedLangCodes !== s.postLanguage, + ), + ) + .slice(0, 6), + })) + }, + }), + [state, setStateWrapped], + ) + return ( - - {children} - + {children} ) } @@ -43,32 +119,14 @@ export function useLanguagePrefs() { return React.useContext(stateContext) } -export function useSetLanguagePrefs() { - return React.useContext(setContext) +export function useLanguagePrefsApi() { + return React.useContext(apiContext) } 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) @@ -77,46 +135,3 @@ export function toPostLanguages(postLanguage: string): string[] { 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), - })) -} diff --git a/src/view/com/composer/Composer.tsx b/src/view/com/composer/Composer.tsx index 68f70682..cdc9768f 100644 --- a/src/view/com/composer/Composer.tsx +++ b/src/view/com/composer/Composer.tsx @@ -53,9 +53,8 @@ import {useModals, useModalControls} from '#/state/modals' import {useRequireAltTextEnabled} from '#/state/preferences' import { useLanguagePrefs, - useSetLanguagePrefs, + useLanguagePrefsApi, toPostLanguages, - savePostLanguageToHistory, } from '#/state/preferences/languages' type Props = ComposerOpts @@ -73,7 +72,7 @@ export const ComposePost = observer(function ComposePost({ const store = useStores() const requireAltTextEnabled = useRequireAltTextEnabled() const langPrefs = useLanguagePrefs() - const setLangPrefs = useSetLanguagePrefs() + const setLangPrefs = useLanguagePrefsApi() const textInput = useRef(null) const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true}) const [isProcessing, setIsProcessing] = useState(false) @@ -245,7 +244,7 @@ export const ComposePost = observer(function ComposePost({ if (!replyTo) { store.me.mainFeed.onPostCreated() } - savePostLanguageToHistory(setLangPrefs) + setLangPrefs.savePostLanguageToHistory() onPost?.() onClose() Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`) diff --git a/src/view/com/composer/select-language/SelectLangBtn.tsx b/src/view/com/composer/select-language/SelectLangBtn.tsx index 6c45f338..896df041 100644 --- a/src/view/com/composer/select-language/SelectLangBtn.tsx +++ b/src/view/com/composer/select-language/SelectLangBtn.tsx @@ -17,7 +17,7 @@ import {codeToLanguageName} from '../../../../locale/helpers' import {useModalControls} from '#/state/modals' import { useLanguagePrefs, - useSetLanguagePrefs, + useLanguagePrefsApi, toPostLanguages, hasPostLanguage, } from '#/state/preferences/languages' @@ -26,7 +26,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() { const pal = usePalette('default') const {openModal} = useModalControls() const langPrefs = useLanguagePrefs() - const setLangPrefs = useSetLanguagePrefs() + const setLangPrefs = useLanguagePrefsApi() const onPressMore = useCallback(async () => { if (isNative) { @@ -63,7 +63,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() { : ['far', 'circle'], label: langName, onPress() { - setLangPrefs(v => ({...v, postLanguage: commaSeparatedLangCodes})) + setLangPrefs.setPostLanguage(commaSeparatedLangCodes) }, }) } diff --git a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx index d37d51e4..0b19abc6 100644 --- a/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/ContentLanguagesSettings.tsx @@ -11,8 +11,7 @@ import {ConfirmLanguagesButton} from './ConfirmLanguagesButton' import {useModalControls} from '#/state/modals' import { useLanguagePrefs, - useSetLanguagePrefs, - toggleContentLanguage, + useLanguagePrefsApi, } from '#/state/preferences/languages' export const snapPoints = ['100%'] @@ -20,7 +19,7 @@ export const snapPoints = ['100%'] export function Component({}: {}) { const {closeModal} = useModalControls() const langPrefs = useLanguagePrefs() - const setLangPrefs = useSetLanguagePrefs() + const setLangPrefs = useLanguagePrefsApi() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const onPressDone = React.useCallback(() => { @@ -50,9 +49,9 @@ export function Component({}: {}) { const onPress = React.useCallback( (code2: string) => { - toggleContentLanguage(langPrefs, setLangPrefs, code2) + setLangPrefs.toggleContentLanguage(code2) }, - [langPrefs, setLangPrefs], + [setLangPrefs], ) return ( diff --git a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx index 4a39da75..7ec26ca5 100644 --- a/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx +++ b/src/view/com/modals/lang-settings/PostLanguagesSettings.tsx @@ -12,9 +12,8 @@ import {ToggleButton} from 'view/com/util/forms/ToggleButton' import {useModalControls} from '#/state/modals' import { useLanguagePrefs, - useSetLanguagePrefs, + useLanguagePrefsApi, hasPostLanguage, - togglePostLanguage, } from '#/state/preferences/languages' export const snapPoints = ['100%'] @@ -22,7 +21,7 @@ export const snapPoints = ['100%'] export const Component = observer(function PostLanguagesSettingsImpl() { const {closeModal} = useModalControls() const langPrefs = useLanguagePrefs() - const setLangPrefs = useSetLanguagePrefs() + const setLangPrefs = useLanguagePrefsApi() const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const onPressDone = React.useCallback(() => { @@ -52,9 +51,9 @@ export const Component = observer(function PostLanguagesSettingsImpl() { const onPress = React.useCallback( (code2: string) => { - togglePostLanguage(langPrefs, setLangPrefs, code2) + setLangPrefs.togglePostLanguage(code2) }, - [langPrefs, setLangPrefs], + [setLangPrefs], ) return ( diff --git a/src/view/screens/LanguageSettings.tsx b/src/view/screens/LanguageSettings.tsx index c94364e9..67745152 100644 --- a/src/view/screens/LanguageSettings.tsx +++ b/src/view/screens/LanguageSettings.tsx @@ -19,7 +19,7 @@ import {LANGUAGES} from 'lib/../locale/languages' import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select' import {useSetMinimalShellMode} from '#/state/shell' import {useModalControls} from '#/state/modals' -import {useLanguagePrefs, useSetLanguagePrefs} from '#/state/preferences' +import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences' type Props = NativeStackScreenProps @@ -28,7 +28,7 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl( ) { const pal = usePalette('default') const langPrefs = useLanguagePrefs() - const setLangPrefs = useSetLanguagePrefs() + const setLangPrefs = useLanguagePrefsApi() const {isTabletOrDesktop} = useWebMediaQueries() const {screen, track} = useAnalytics() const setMinimalShellMode = useSetMinimalShellMode() @@ -49,7 +49,7 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl( const onChangePrimaryLanguage = React.useCallback( (value: Parameters[0]) => { if (langPrefs.primaryLanguage !== value) { - setLangPrefs(v => ({...v, primaryLanguage: value})) + setLangPrefs.setPrimaryLanguage(value) } }, [langPrefs, setLangPrefs],