Pull language methods into api context (#1847)

* Pull language methods into api context

* Rename for consistency
zio/stable
Eric Bailey 2023-11-08 13:55:38 -06:00 committed by GitHub
parent f18b15241a
commit bd531f2344
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 105 additions and 93 deletions

View File

@ -2,7 +2,7 @@ import React from 'react'
import {Provider as LanguagesProvider} from './languages' import {Provider as LanguagesProvider} from './languages'
import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required' import {Provider as AltTextRequiredProvider} from '../preferences/alt-text-required'
export {useLanguagePrefs, useSetLanguagePrefs} from './languages' export {useLanguagePrefs, useLanguagePrefsApi} from './languages'
export { export {
useRequireAltTextEnabled, useRequireAltTextEnabled,
useSetRequireAltTextEnabled, useSetRequireAltTextEnabled,

View File

@ -2,24 +2,36 @@ import React from 'react'
import * as persisted from '#/state/persisted' import * as persisted from '#/state/persisted'
type SetStateCb = ( type SetStateCb = (
v: persisted.Schema['languagePrefs'], s: persisted.Schema['languagePrefs'],
) => persisted.Schema['languagePrefs'] ) => persisted.Schema['languagePrefs']
type StateContext = 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<StateContext>( const stateContext = React.createContext<StateContext>(
persisted.defaults.languagePrefs, persisted.defaults.languagePrefs,
) )
const setContext = React.createContext<SetContext>((_: SetStateCb) => {}) const apiContext = React.createContext<ApiContext>({
setPrimaryLanguage: (_: string) => {},
setPostLanguage: (_: string) => {},
toggleContentLanguage: (_: string) => {},
togglePostLanguage: (_: string) => {},
savePostLanguageToHistory: () => {},
})
export function Provider({children}: React.PropsWithChildren<{}>) { export function Provider({children}: React.PropsWithChildren<{}>) {
const [state, setState] = React.useState(persisted.get('languagePrefs')) const [state, setState] = React.useState(persisted.get('languagePrefs'))
const setStateWrapped = React.useCallback( const setStateWrapped = React.useCallback(
(fn: SetStateCb) => { (fn: SetStateCb) => {
const v = fn(persisted.get('languagePrefs')) const s = fn(persisted.get('languagePrefs'))
setState(v) setState(s)
persisted.write('languagePrefs', v) persisted.write('languagePrefs', s)
}, },
[setState], [setState],
) )
@ -30,11 +42,75 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
}) })
}, [setStateWrapped]) }, [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 ( return (
<stateContext.Provider value={state}> <stateContext.Provider value={state}>
<setContext.Provider value={setStateWrapped}> <apiContext.Provider value={api}>{children}</apiContext.Provider>
{children}
</setContext.Provider>
</stateContext.Provider> </stateContext.Provider>
) )
} }
@ -43,32 +119,14 @@ export function useLanguagePrefs() {
return React.useContext(stateContext) return React.useContext(stateContext)
} }
export function useSetLanguagePrefs() { export function useLanguagePrefsApi() {
return React.useContext(setContext) return React.useContext(apiContext)
} }
export function getContentLanguages() { export function getContentLanguages() {
return persisted.get('languagePrefs').contentLanguages 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[] { export function toPostLanguages(postLanguage: string): string[] {
// filter out empty strings if exist // filter out empty strings if exist
return postLanguage.split(',').filter(Boolean) return postLanguage.split(',').filter(Boolean)
@ -77,46 +135,3 @@ export function toPostLanguages(postLanguage: string): string[] {
export function hasPostLanguage(postLanguage: string, code2: string): boolean { export function hasPostLanguage(postLanguage: string, code2: string): boolean {
return toPostLanguages(postLanguage).includes(code2) 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),
}))
}

View File

@ -53,9 +53,8 @@ import {useModals, useModalControls} from '#/state/modals'
import {useRequireAltTextEnabled} from '#/state/preferences' import {useRequireAltTextEnabled} from '#/state/preferences'
import { import {
useLanguagePrefs, useLanguagePrefs,
useSetLanguagePrefs, useLanguagePrefsApi,
toPostLanguages, toPostLanguages,
savePostLanguageToHistory,
} from '#/state/preferences/languages' } from '#/state/preferences/languages'
type Props = ComposerOpts type Props = ComposerOpts
@ -73,7 +72,7 @@ export const ComposePost = observer(function ComposePost({
const store = useStores() const store = useStores()
const requireAltTextEnabled = useRequireAltTextEnabled() const requireAltTextEnabled = useRequireAltTextEnabled()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
const setLangPrefs = useSetLanguagePrefs() const setLangPrefs = useLanguagePrefsApi()
const textInput = useRef<TextInputRef>(null) const textInput = useRef<TextInputRef>(null)
const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true}) const [isKeyboardVisible] = useIsKeyboardVisible({iosUseWillEvents: true})
const [isProcessing, setIsProcessing] = useState(false) const [isProcessing, setIsProcessing] = useState(false)
@ -245,7 +244,7 @@ export const ComposePost = observer(function ComposePost({
if (!replyTo) { if (!replyTo) {
store.me.mainFeed.onPostCreated() store.me.mainFeed.onPostCreated()
} }
savePostLanguageToHistory(setLangPrefs) setLangPrefs.savePostLanguageToHistory()
onPost?.() onPost?.()
onClose() onClose()
Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`) Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`)

View File

@ -17,7 +17,7 @@ import {codeToLanguageName} from '../../../../locale/helpers'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import { import {
useLanguagePrefs, useLanguagePrefs,
useSetLanguagePrefs, useLanguagePrefsApi,
toPostLanguages, toPostLanguages,
hasPostLanguage, hasPostLanguage,
} from '#/state/preferences/languages' } from '#/state/preferences/languages'
@ -26,7 +26,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() {
const pal = usePalette('default') const pal = usePalette('default')
const {openModal} = useModalControls() const {openModal} = useModalControls()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
const setLangPrefs = useSetLanguagePrefs() const setLangPrefs = useLanguagePrefsApi()
const onPressMore = useCallback(async () => { const onPressMore = useCallback(async () => {
if (isNative) { if (isNative) {
@ -63,7 +63,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() {
: ['far', 'circle'], : ['far', 'circle'],
label: langName, label: langName,
onPress() { onPress() {
setLangPrefs(v => ({...v, postLanguage: commaSeparatedLangCodes})) setLangPrefs.setPostLanguage(commaSeparatedLangCodes)
}, },
}) })
} }

View File

@ -11,8 +11,7 @@ import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import { import {
useLanguagePrefs, useLanguagePrefs,
useSetLanguagePrefs, useLanguagePrefsApi,
toggleContentLanguage,
} from '#/state/preferences/languages' } from '#/state/preferences/languages'
export const snapPoints = ['100%'] export const snapPoints = ['100%']
@ -20,7 +19,7 @@ export const snapPoints = ['100%']
export function Component({}: {}) { export function Component({}: {}) {
const {closeModal} = useModalControls() const {closeModal} = useModalControls()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
const setLangPrefs = useSetLanguagePrefs() const setLangPrefs = useLanguagePrefsApi()
const pal = usePalette('default') const pal = usePalette('default')
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const onPressDone = React.useCallback(() => { const onPressDone = React.useCallback(() => {
@ -50,9 +49,9 @@ export function Component({}: {}) {
const onPress = React.useCallback( const onPress = React.useCallback(
(code2: string) => { (code2: string) => {
toggleContentLanguage(langPrefs, setLangPrefs, code2) setLangPrefs.toggleContentLanguage(code2)
}, },
[langPrefs, setLangPrefs], [setLangPrefs],
) )
return ( return (

View File

@ -12,9 +12,8 @@ import {ToggleButton} from 'view/com/util/forms/ToggleButton'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import { import {
useLanguagePrefs, useLanguagePrefs,
useSetLanguagePrefs, useLanguagePrefsApi,
hasPostLanguage, hasPostLanguage,
togglePostLanguage,
} from '#/state/preferences/languages' } from '#/state/preferences/languages'
export const snapPoints = ['100%'] export const snapPoints = ['100%']
@ -22,7 +21,7 @@ export const snapPoints = ['100%']
export const Component = observer(function PostLanguagesSettingsImpl() { export const Component = observer(function PostLanguagesSettingsImpl() {
const {closeModal} = useModalControls() const {closeModal} = useModalControls()
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
const setLangPrefs = useSetLanguagePrefs() const setLangPrefs = useLanguagePrefsApi()
const pal = usePalette('default') const pal = usePalette('default')
const {isMobile} = useWebMediaQueries() const {isMobile} = useWebMediaQueries()
const onPressDone = React.useCallback(() => { const onPressDone = React.useCallback(() => {
@ -52,9 +51,9 @@ export const Component = observer(function PostLanguagesSettingsImpl() {
const onPress = React.useCallback( const onPress = React.useCallback(
(code2: string) => { (code2: string) => {
togglePostLanguage(langPrefs, setLangPrefs, code2) setLangPrefs.togglePostLanguage(code2)
}, },
[langPrefs, setLangPrefs], [setLangPrefs],
) )
return ( return (

View File

@ -19,7 +19,7 @@ import {LANGUAGES} from 'lib/../locale/languages'
import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select' import RNPickerSelect, {PickerSelectProps} from 'react-native-picker-select'
import {useSetMinimalShellMode} from '#/state/shell' import {useSetMinimalShellMode} from '#/state/shell'
import {useModalControls} from '#/state/modals' import {useModalControls} from '#/state/modals'
import {useLanguagePrefs, useSetLanguagePrefs} from '#/state/preferences' import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'> type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
@ -28,7 +28,7 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl(
) { ) {
const pal = usePalette('default') const pal = usePalette('default')
const langPrefs = useLanguagePrefs() const langPrefs = useLanguagePrefs()
const setLangPrefs = useSetLanguagePrefs() const setLangPrefs = useLanguagePrefsApi()
const {isTabletOrDesktop} = useWebMediaQueries() const {isTabletOrDesktop} = useWebMediaQueries()
const {screen, track} = useAnalytics() const {screen, track} = useAnalytics()
const setMinimalShellMode = useSetMinimalShellMode() const setMinimalShellMode = useSetMinimalShellMode()
@ -49,7 +49,7 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl(
const onChangePrimaryLanguage = React.useCallback( const onChangePrimaryLanguage = React.useCallback(
(value: Parameters<PickerSelectProps['onValueChange']>[0]) => { (value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
if (langPrefs.primaryLanguage !== value) { if (langPrefs.primaryLanguage !== value) {
setLangPrefs(v => ({...v, primaryLanguage: value})) setLangPrefs.setPrimaryLanguage(value)
} }
}, },
[langPrefs, setLangPrefs], [langPrefs, setLangPrefs],