Move language preferences to new persistence + context (#1837)
parent
e75b2d508b
commit
5843e212c0
|
@ -24,6 +24,7 @@ import {TestCtrls} from 'view/com/testing/TestCtrls'
|
||||||
import {Provider as ShellStateProvider} from 'state/shell'
|
import {Provider as ShellStateProvider} from 'state/shell'
|
||||||
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
|
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
|
||||||
import {Provider as InvitesStateProvider} from 'state/invites'
|
import {Provider as InvitesStateProvider} from 'state/invites'
|
||||||
|
import {Provider as PrefsStateProvider} from 'state/preferences'
|
||||||
|
|
||||||
SplashScreen.preventAutoHideAsync()
|
SplashScreen.preventAutoHideAsync()
|
||||||
|
|
||||||
|
@ -80,11 +81,13 @@ function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ShellStateProvider>
|
<ShellStateProvider>
|
||||||
<MutedThreadsProvider>
|
<PrefsStateProvider>
|
||||||
<InvitesStateProvider>
|
<MutedThreadsProvider>
|
||||||
<InnerApp />
|
<InvitesStateProvider>
|
||||||
</InvitesStateProvider>
|
<InnerApp />
|
||||||
</MutedThreadsProvider>
|
</InvitesStateProvider>
|
||||||
|
</MutedThreadsProvider>
|
||||||
|
</PrefsStateProvider>
|
||||||
</ShellStateProvider>
|
</ShellStateProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {queryClient} from 'lib/react-query'
|
||||||
import {Provider as ShellStateProvider} from 'state/shell'
|
import {Provider as ShellStateProvider} from 'state/shell'
|
||||||
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
|
import {Provider as MutedThreadsProvider} from 'state/muted-threads'
|
||||||
import {Provider as InvitesStateProvider} from 'state/invites'
|
import {Provider as InvitesStateProvider} from 'state/invites'
|
||||||
|
import {Provider as PrefsStateProvider} from 'state/preferences'
|
||||||
|
|
||||||
const InnerApp = observer(function AppImpl() {
|
const InnerApp = observer(function AppImpl() {
|
||||||
const colorMode = useColorMode()
|
const colorMode = useColorMode()
|
||||||
|
@ -70,11 +71,13 @@ function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ShellStateProvider>
|
<ShellStateProvider>
|
||||||
<MutedThreadsProvider>
|
<PrefsStateProvider>
|
||||||
<InvitesStateProvider>
|
<MutedThreadsProvider>
|
||||||
<InnerApp />
|
<InvitesStateProvider>
|
||||||
</InvitesStateProvider>
|
<InnerApp />
|
||||||
</MutedThreadsProvider>
|
</InvitesStateProvider>
|
||||||
|
</MutedThreadsProvider>
|
||||||
|
</PrefsStateProvider>
|
||||||
</ShellStateProvider>
|
</ShellStateProvider>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,11 +10,10 @@ import {isObj, hasProp} from 'lib/type-guards'
|
||||||
import {RootStoreModel} from '../root-store'
|
import {RootStoreModel} from '../root-store'
|
||||||
import {ModerationOpts} from '@atproto/api'
|
import {ModerationOpts} from '@atproto/api'
|
||||||
import {DEFAULT_FEEDS} from 'lib/constants'
|
import {DEFAULT_FEEDS} from 'lib/constants'
|
||||||
import {deviceLocales} from 'platform/detection'
|
|
||||||
import {getAge} from 'lib/strings/time'
|
import {getAge} from 'lib/strings/time'
|
||||||
import {FeedTuner} from 'lib/api/feed-manip'
|
import {FeedTuner} from 'lib/api/feed-manip'
|
||||||
import {LANGUAGES} from '../../../locale/languages'
|
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
|
import {getContentLanguages} from '#/state/preferences/languages'
|
||||||
|
|
||||||
// TEMP we need to permanently convert 'show' to 'ignore', for now we manually convert -prf
|
// TEMP we need to permanently convert 'show' to 'ignore', for now we manually convert -prf
|
||||||
export type LabelPreference = APILabelPreference | 'show'
|
export type LabelPreference = APILabelPreference | 'show'
|
||||||
|
@ -34,9 +33,6 @@ const LABEL_GROUPS = [
|
||||||
'impersonation',
|
'impersonation',
|
||||||
]
|
]
|
||||||
const VISIBILITY_VALUES = ['ignore', 'warn', 'hide']
|
const VISIBILITY_VALUES = ['ignore', 'warn', 'hide']
|
||||||
const DEFAULT_LANG_CODES = (deviceLocales || [])
|
|
||||||
.concat(['en', 'ja', 'pt', 'de'])
|
|
||||||
.slice(0, 6)
|
|
||||||
const THREAD_SORT_VALUES = ['oldest', 'newest', 'most-likes', 'random']
|
const THREAD_SORT_VALUES = ['oldest', 'newest', 'most-likes', 'random']
|
||||||
|
|
||||||
interface LegacyPreferences {
|
interface LegacyPreferences {
|
||||||
|
@ -62,10 +58,6 @@ export class LabelPreferencesModel {
|
||||||
|
|
||||||
export class PreferencesModel {
|
export class PreferencesModel {
|
||||||
adultContentEnabled = false
|
adultContentEnabled = false
|
||||||
primaryLanguage: string = deviceLocales[0] || 'en'
|
|
||||||
contentLanguages: string[] = deviceLocales || []
|
|
||||||
postLanguage: string = deviceLocales[0] || 'en'
|
|
||||||
postLanguageHistory: string[] = DEFAULT_LANG_CODES
|
|
||||||
contentLabels = new LabelPreferencesModel()
|
contentLabels = new LabelPreferencesModel()
|
||||||
savedFeeds: string[] = []
|
savedFeeds: string[] = []
|
||||||
pinnedFeeds: string[] = []
|
pinnedFeeds: string[] = []
|
||||||
|
@ -103,10 +95,6 @@ export class PreferencesModel {
|
||||||
|
|
||||||
serialize() {
|
serialize() {
|
||||||
return {
|
return {
|
||||||
primaryLanguage: this.primaryLanguage,
|
|
||||||
contentLanguages: this.contentLanguages,
|
|
||||||
postLanguage: this.postLanguage,
|
|
||||||
postLanguageHistory: this.postLanguageHistory,
|
|
||||||
contentLabels: this.contentLabels,
|
contentLabels: this.contentLabels,
|
||||||
savedFeeds: this.savedFeeds,
|
savedFeeds: this.savedFeeds,
|
||||||
pinnedFeeds: this.pinnedFeeds,
|
pinnedFeeds: this.pinnedFeeds,
|
||||||
|
@ -120,44 +108,6 @@ export class PreferencesModel {
|
||||||
*/
|
*/
|
||||||
hydrate(v: unknown) {
|
hydrate(v: unknown) {
|
||||||
if (isObj(v)) {
|
if (isObj(v)) {
|
||||||
if (
|
|
||||||
hasProp(v, 'primaryLanguage') &&
|
|
||||||
typeof v.primaryLanguage === 'string'
|
|
||||||
) {
|
|
||||||
this.primaryLanguage = v.primaryLanguage
|
|
||||||
} else {
|
|
||||||
// default to the device languages
|
|
||||||
this.primaryLanguage = deviceLocales[0] || 'en'
|
|
||||||
}
|
|
||||||
// check if content languages in preferences exist, otherwise default to device languages
|
|
||||||
if (
|
|
||||||
hasProp(v, 'contentLanguages') &&
|
|
||||||
Array.isArray(v.contentLanguages) &&
|
|
||||||
typeof v.contentLanguages.every(item => typeof item === 'string')
|
|
||||||
) {
|
|
||||||
this.contentLanguages = v.contentLanguages
|
|
||||||
} else {
|
|
||||||
// default to the device languages
|
|
||||||
this.contentLanguages = deviceLocales
|
|
||||||
}
|
|
||||||
if (hasProp(v, 'postLanguage') && typeof v.postLanguage === 'string') {
|
|
||||||
this.postLanguage = v.postLanguage
|
|
||||||
} else {
|
|
||||||
// default to the device languages
|
|
||||||
this.postLanguage = deviceLocales[0] || 'en'
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
hasProp(v, 'postLanguageHistory') &&
|
|
||||||
Array.isArray(v.postLanguageHistory) &&
|
|
||||||
typeof v.postLanguageHistory.every(item => typeof item === 'string')
|
|
||||||
) {
|
|
||||||
this.postLanguageHistory = v.postLanguageHistory
|
|
||||||
.concat(DEFAULT_LANG_CODES)
|
|
||||||
.slice(0, 6)
|
|
||||||
} else {
|
|
||||||
// default to a starter set
|
|
||||||
this.postLanguageHistory = DEFAULT_LANG_CODES
|
|
||||||
}
|
|
||||||
// check if content labels in preferences exist, then hydrate
|
// check if content labels in preferences exist, then hydrate
|
||||||
if (hasProp(v, 'contentLabels') && typeof v.contentLabels === 'object') {
|
if (hasProp(v, 'contentLabels') && typeof v.contentLabels === 'object') {
|
||||||
Object.assign(this.contentLabels, v.contentLabels)
|
Object.assign(this.contentLabels, v.contentLabels)
|
||||||
|
@ -262,9 +212,6 @@ export class PreferencesModel {
|
||||||
try {
|
try {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
this.contentLabels = new LabelPreferencesModel()
|
this.contentLabels = new LabelPreferencesModel()
|
||||||
this.contentLanguages = deviceLocales
|
|
||||||
this.postLanguage = deviceLocales ? deviceLocales.join(',') : 'en'
|
|
||||||
this.postLanguageHistory = DEFAULT_LANG_CODES
|
|
||||||
this.savedFeeds = []
|
this.savedFeeds = []
|
||||||
this.pinnedFeeds = []
|
this.pinnedFeeds = []
|
||||||
})
|
})
|
||||||
|
@ -276,81 +223,6 @@ export class PreferencesModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// languages
|
|
||||||
// =
|
|
||||||
|
|
||||||
hasContentLanguage(code2: string) {
|
|
||||||
return this.contentLanguages.includes(code2)
|
|
||||||
}
|
|
||||||
|
|
||||||
toggleContentLanguage(code2: string) {
|
|
||||||
if (this.hasContentLanguage(code2)) {
|
|
||||||
this.contentLanguages = this.contentLanguages.filter(
|
|
||||||
lang => lang !== code2,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this.contentLanguages = this.contentLanguages.concat([code2])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A getter that splits `this.postLanguage` into an array of strings.
|
|
||||||
*
|
|
||||||
* This was previously the main field on this model, but now we're
|
|
||||||
* concatenating lang codes to make multi-selection a little better.
|
|
||||||
*/
|
|
||||||
get postLanguages() {
|
|
||||||
// filter out empty strings if exist
|
|
||||||
return this.postLanguage.split(',').filter(Boolean)
|
|
||||||
}
|
|
||||||
|
|
||||||
hasPostLanguage(code2: string) {
|
|
||||||
return this.postLanguages.includes(code2)
|
|
||||||
}
|
|
||||||
|
|
||||||
togglePostLanguage(code2: string) {
|
|
||||||
if (this.hasPostLanguage(code2)) {
|
|
||||||
this.postLanguage = this.postLanguages
|
|
||||||
.filter(lang => lang !== code2)
|
|
||||||
.join(',')
|
|
||||||
} else {
|
|
||||||
// sort alphabetically for deterministic comparison in context menu
|
|
||||||
this.postLanguage = this.postLanguages
|
|
||||||
.concat([code2])
|
|
||||||
.sort((a, b) => a.localeCompare(b))
|
|
||||||
.join(',')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setPostLanguage(commaSeparatedLangCodes: string) {
|
|
||||||
this.postLanguage = commaSeparatedLangCodes
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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
|
|
||||||
this.postLanguageHistory = [this.postLanguage]
|
|
||||||
.concat(
|
|
||||||
this.postLanguageHistory.filter(
|
|
||||||
commaSeparatedLangCodes =>
|
|
||||||
commaSeparatedLangCodes !== this.postLanguage,
|
|
||||||
),
|
|
||||||
)
|
|
||||||
.slice(0, 6)
|
|
||||||
}
|
|
||||||
|
|
||||||
getReadablePostLanguages() {
|
|
||||||
const all = this.postLanguages.map(code2 => {
|
|
||||||
const lang = LANGUAGES.find(l => l.code2 === code2)
|
|
||||||
return lang ? lang.name : code2
|
|
||||||
})
|
|
||||||
return all.join(', ')
|
|
||||||
}
|
|
||||||
|
|
||||||
// moderation
|
// moderation
|
||||||
// =
|
// =
|
||||||
|
|
||||||
|
@ -599,17 +471,13 @@ export class PreferencesModel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setPrimaryLanguage(lang: string) {
|
|
||||||
this.primaryLanguage = lang
|
|
||||||
}
|
|
||||||
|
|
||||||
getFeedTuners(
|
getFeedTuners(
|
||||||
feedType: 'home' | 'following' | 'author' | 'custom' | 'list' | 'likes',
|
feedType: 'home' | 'following' | 'author' | 'custom' | 'list' | 'likes',
|
||||||
) {
|
) {
|
||||||
if (feedType === 'custom') {
|
if (feedType === 'custom') {
|
||||||
return [
|
return [
|
||||||
FeedTuner.dedupReposts,
|
FeedTuner.dedupReposts,
|
||||||
FeedTuner.preferredLangOnly(this.contentLanguages),
|
FeedTuner.preferredLangOnly(getContentLanguages()),
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
if (feedType === 'list') {
|
if (feedType === 'list') {
|
||||||
|
|
|
@ -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>
|
||||||
|
}
|
|
@ -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),
|
||||||
|
}))
|
||||||
|
}
|
|
@ -50,6 +50,12 @@ import {SelectLangBtn} from './select-language/SelectLangBtn'
|
||||||
import {EmojiPickerButton} from './text-input/web/EmojiPicker.web'
|
import {EmojiPickerButton} from './text-input/web/EmojiPicker.web'
|
||||||
import {insertMentionAt} from 'lib/strings/mention-manip'
|
import {insertMentionAt} from 'lib/strings/mention-manip'
|
||||||
import {useRequireAltTextEnabled} from '#/state/shell'
|
import {useRequireAltTextEnabled} from '#/state/shell'
|
||||||
|
import {
|
||||||
|
useLanguagePrefs,
|
||||||
|
useSetLanguagePrefs,
|
||||||
|
toPostLanguages,
|
||||||
|
savePostLanguageToHistory,
|
||||||
|
} from '#/state/preferences/languages'
|
||||||
|
|
||||||
type Props = ComposerOpts
|
type Props = ComposerOpts
|
||||||
export const ComposePost = observer(function ComposePost({
|
export const ComposePost = observer(function ComposePost({
|
||||||
|
@ -63,6 +69,8 @@ export const ComposePost = observer(function ComposePost({
|
||||||
const {isDesktop, isMobile} = useWebMediaQueries()
|
const {isDesktop, isMobile} = useWebMediaQueries()
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const requireAltTextEnabled = useRequireAltTextEnabled()
|
const requireAltTextEnabled = useRequireAltTextEnabled()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
|
const setLangPrefs = useSetLanguagePrefs()
|
||||||
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)
|
||||||
|
@ -212,7 +220,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
labels,
|
labels,
|
||||||
onStateChange: setProcessingState,
|
onStateChange: setProcessingState,
|
||||||
knownHandles: autocompleteView.knownHandles,
|
knownHandles: autocompleteView.knownHandles,
|
||||||
langs: store.preferences.postLanguages,
|
langs: toPostLanguages(langPrefs.postLanguage),
|
||||||
})
|
})
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
if (extLink) {
|
if (extLink) {
|
||||||
|
@ -234,7 +242,7 @@ export const ComposePost = observer(function ComposePost({
|
||||||
if (!replyTo) {
|
if (!replyTo) {
|
||||||
store.me.mainFeed.onPostCreated()
|
store.me.mainFeed.onPostCreated()
|
||||||
}
|
}
|
||||||
store.preferences.savePostLanguageToHistory()
|
savePostLanguageToHistory(setLangPrefs)
|
||||||
onPost?.()
|
onPost?.()
|
||||||
onClose()
|
onClose()
|
||||||
Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`)
|
Toast.show(`Your ${replyTo ? 'reply' : 'post'} has been published`)
|
||||||
|
|
|
@ -15,10 +15,18 @@ import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {useStores} from 'state/index'
|
import {useStores} from 'state/index'
|
||||||
import {isNative} from 'platform/detection'
|
import {isNative} from 'platform/detection'
|
||||||
import {codeToLanguageName} from '../../../../locale/helpers'
|
import {codeToLanguageName} from '../../../../locale/helpers'
|
||||||
|
import {
|
||||||
|
useLanguagePrefs,
|
||||||
|
useSetLanguagePrefs,
|
||||||
|
toPostLanguages,
|
||||||
|
hasPostLanguage,
|
||||||
|
} from '#/state/preferences/languages'
|
||||||
|
|
||||||
export const SelectLangBtn = observer(function SelectLangBtn() {
|
export const SelectLangBtn = observer(function SelectLangBtn() {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
|
const setLangPrefs = useSetLanguagePrefs()
|
||||||
|
|
||||||
const onPressMore = useCallback(async () => {
|
const onPressMore = useCallback(async () => {
|
||||||
if (isNative) {
|
if (isNative) {
|
||||||
|
@ -29,8 +37,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() {
|
||||||
store.shell.openModal({name: 'post-languages-settings'})
|
store.shell.openModal({name: 'post-languages-settings'})
|
||||||
}, [store])
|
}, [store])
|
||||||
|
|
||||||
const postLanguagesPref = store.preferences.postLanguages
|
const postLanguagesPref = toPostLanguages(langPrefs.postLanguage)
|
||||||
const postLanguagePref = store.preferences.postLanguage
|
|
||||||
const items: DropdownItem[] = useMemo(() => {
|
const items: DropdownItem[] = useMemo(() => {
|
||||||
let arr: DropdownItemButton[] = []
|
let arr: DropdownItemButton[] = []
|
||||||
|
|
||||||
|
@ -49,13 +56,14 @@ export const SelectLangBtn = observer(function SelectLangBtn() {
|
||||||
|
|
||||||
arr.push({
|
arr.push({
|
||||||
icon:
|
icon:
|
||||||
langCodes.every(code => store.preferences.hasPostLanguage(code)) &&
|
langCodes.every(code =>
|
||||||
langCodes.length === postLanguagesPref.length
|
hasPostLanguage(langPrefs.postLanguage, code),
|
||||||
|
) && langCodes.length === postLanguagesPref.length
|
||||||
? ['fas', 'circle-dot']
|
? ['fas', 'circle-dot']
|
||||||
: ['far', 'circle'],
|
: ['far', 'circle'],
|
||||||
label: langName,
|
label: langName,
|
||||||
onPress() {
|
onPress() {
|
||||||
store.preferences.setPostLanguage(commaSeparatedLangCodes)
|
setLangPrefs(v => ({...v, postLanguage: commaSeparatedLangCodes}))
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -65,11 +73,11 @@ export const SelectLangBtn = observer(function SelectLangBtn() {
|
||||||
* Re-join here after sanitization bc postLanguageHistory is an array of
|
* Re-join here after sanitization bc postLanguageHistory is an array of
|
||||||
* comma-separated strings too
|
* comma-separated strings too
|
||||||
*/
|
*/
|
||||||
add(postLanguagePref)
|
add(langPrefs.postLanguage)
|
||||||
}
|
}
|
||||||
|
|
||||||
// comma-separted strings of lang codes that have been used in the past
|
// comma-separted strings of lang codes that have been used in the past
|
||||||
for (const lang of store.preferences.postLanguageHistory) {
|
for (const lang of langPrefs.postLanguageHistory) {
|
||||||
add(lang)
|
add(lang)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,7 +90,7 @@ export const SelectLangBtn = observer(function SelectLangBtn() {
|
||||||
onPress: onPressMore,
|
onPress: onPressMore,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}, [store.preferences, onPressMore, postLanguagePref, postLanguagesPref])
|
}, [onPressMore, langPrefs, setLangPrefs, postLanguagesPref])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DropdownButton
|
<DropdownButton
|
||||||
|
|
|
@ -9,11 +9,18 @@ import {deviceLocales} from 'platform/detection'
|
||||||
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
|
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
|
||||||
import {LanguageToggle} from './LanguageToggle'
|
import {LanguageToggle} from './LanguageToggle'
|
||||||
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
|
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
|
||||||
|
import {
|
||||||
|
useLanguagePrefs,
|
||||||
|
useSetLanguagePrefs,
|
||||||
|
toggleContentLanguage,
|
||||||
|
} from '#/state/preferences/languages'
|
||||||
|
|
||||||
export const snapPoints = ['100%']
|
export const snapPoints = ['100%']
|
||||||
|
|
||||||
export function Component({}: {}) {
|
export function Component({}: {}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
|
const setLangPrefs = useSetLanguagePrefs()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {isMobile} = useWebMediaQueries()
|
const {isMobile} = useWebMediaQueries()
|
||||||
const onPressDone = React.useCallback(() => {
|
const onPressDone = React.useCallback(() => {
|
||||||
|
@ -29,23 +36,23 @@ export function Component({}: {}) {
|
||||||
// sort so that device & selected languages are on top, then alphabetically
|
// sort so that device & selected languages are on top, then alphabetically
|
||||||
langs.sort((a, b) => {
|
langs.sort((a, b) => {
|
||||||
const hasA =
|
const hasA =
|
||||||
store.preferences.hasContentLanguage(a.code2) ||
|
langPrefs.contentLanguages.includes(a.code2) ||
|
||||||
deviceLocales.includes(a.code2)
|
deviceLocales.includes(a.code2)
|
||||||
const hasB =
|
const hasB =
|
||||||
store.preferences.hasContentLanguage(b.code2) ||
|
langPrefs.contentLanguages.includes(b.code2) ||
|
||||||
deviceLocales.includes(b.code2)
|
deviceLocales.includes(b.code2)
|
||||||
if (hasA === hasB) return a.name.localeCompare(b.name)
|
if (hasA === hasB) return a.name.localeCompare(b.name)
|
||||||
if (hasA) return -1
|
if (hasA) return -1
|
||||||
return 1
|
return 1
|
||||||
})
|
})
|
||||||
return langs
|
return langs
|
||||||
}, [store])
|
}, [langPrefs])
|
||||||
|
|
||||||
const onPress = React.useCallback(
|
const onPress = React.useCallback(
|
||||||
(code2: string) => {
|
(code2: string) => {
|
||||||
store.preferences.toggleContentLanguage(code2)
|
toggleContentLanguage(langPrefs, setLangPrefs, code2)
|
||||||
},
|
},
|
||||||
[store],
|
[langPrefs, setLangPrefs],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {StyleSheet} from 'react-native'
|
||||||
import {usePalette} from 'lib/hooks/usePalette'
|
import {usePalette} from 'lib/hooks/usePalette'
|
||||||
import {observer} from 'mobx-react-lite'
|
import {observer} from 'mobx-react-lite'
|
||||||
import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
||||||
import {useStores} from 'state/index'
|
import {useLanguagePrefs, toPostLanguages} from '#/state/preferences/languages'
|
||||||
|
|
||||||
export const LanguageToggle = observer(function LanguageToggleImpl({
|
export const LanguageToggle = observer(function LanguageToggleImpl({
|
||||||
code2,
|
code2,
|
||||||
|
@ -17,17 +17,17 @@ export const LanguageToggle = observer(function LanguageToggleImpl({
|
||||||
langType: 'contentLanguages' | 'postLanguages'
|
langType: 'contentLanguages' | 'postLanguages'
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const langPrefs = useLanguagePrefs()
|
||||||
|
|
||||||
const isSelected = store.preferences[langType].includes(code2)
|
const values =
|
||||||
|
langType === 'contentLanguages'
|
||||||
|
? langPrefs.contentLanguages
|
||||||
|
: toPostLanguages(langPrefs.postLanguage)
|
||||||
|
const isSelected = values.includes(code2)
|
||||||
|
|
||||||
// enforce a max of 3 selections for post languages
|
// enforce a max of 3 selections for post languages
|
||||||
let isDisabled = false
|
let isDisabled = false
|
||||||
if (
|
if (langType === 'postLanguages' && values.length >= 3 && !isSelected) {
|
||||||
langType === 'postLanguages' &&
|
|
||||||
store.preferences[langType].length >= 3 &&
|
|
||||||
!isSelected
|
|
||||||
) {
|
|
||||||
isDisabled = true
|
isDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,19 @@ import {deviceLocales} from 'platform/detection'
|
||||||
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
|
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
|
||||||
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
|
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
|
||||||
import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
import {ToggleButton} from 'view/com/util/forms/ToggleButton'
|
||||||
|
import {
|
||||||
|
useLanguagePrefs,
|
||||||
|
useSetLanguagePrefs,
|
||||||
|
hasPostLanguage,
|
||||||
|
togglePostLanguage,
|
||||||
|
} from '#/state/preferences/languages'
|
||||||
|
|
||||||
export const snapPoints = ['100%']
|
export const snapPoints = ['100%']
|
||||||
|
|
||||||
export const Component = observer(function PostLanguagesSettingsImpl() {
|
export const Component = observer(function PostLanguagesSettingsImpl() {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
|
const setLangPrefs = useSetLanguagePrefs()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const {isMobile} = useWebMediaQueries()
|
const {isMobile} = useWebMediaQueries()
|
||||||
const onPressDone = React.useCallback(() => {
|
const onPressDone = React.useCallback(() => {
|
||||||
|
@ -30,23 +38,23 @@ export const Component = observer(function PostLanguagesSettingsImpl() {
|
||||||
// sort so that device & selected languages are on top, then alphabetically
|
// sort so that device & selected languages are on top, then alphabetically
|
||||||
langs.sort((a, b) => {
|
langs.sort((a, b) => {
|
||||||
const hasA =
|
const hasA =
|
||||||
store.preferences.hasPostLanguage(a.code2) ||
|
hasPostLanguage(langPrefs.postLanguage, a.code2) ||
|
||||||
deviceLocales.includes(a.code2)
|
deviceLocales.includes(a.code2)
|
||||||
const hasB =
|
const hasB =
|
||||||
store.preferences.hasPostLanguage(b.code2) ||
|
hasPostLanguage(langPrefs.postLanguage, b.code2) ||
|
||||||
deviceLocales.includes(b.code2)
|
deviceLocales.includes(b.code2)
|
||||||
if (hasA === hasB) return a.name.localeCompare(b.name)
|
if (hasA === hasB) return a.name.localeCompare(b.name)
|
||||||
if (hasA) return -1
|
if (hasA) return -1
|
||||||
return 1
|
return 1
|
||||||
})
|
})
|
||||||
return langs
|
return langs
|
||||||
}, [store])
|
}, [langPrefs])
|
||||||
|
|
||||||
const onPress = React.useCallback(
|
const onPress = React.useCallback(
|
||||||
(code2: string) => {
|
(code2: string) => {
|
||||||
store.preferences.togglePostLanguage(code2)
|
togglePostLanguage(langPrefs, setLangPrefs, code2)
|
||||||
},
|
},
|
||||||
[store],
|
[langPrefs, setLangPrefs],
|
||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -70,14 +78,11 @@ export const Component = observer(function PostLanguagesSettingsImpl() {
|
||||||
</Text>
|
</Text>
|
||||||
<ScrollView style={styles.scrollContainer}>
|
<ScrollView style={styles.scrollContainer}>
|
||||||
{languages.map(lang => {
|
{languages.map(lang => {
|
||||||
const isSelected = store.preferences.hasPostLanguage(lang.code2)
|
const isSelected = hasPostLanguage(langPrefs.postLanguage, lang.code2)
|
||||||
|
|
||||||
// enforce a max of 3 selections for post languages
|
// enforce a max of 3 selections for post languages
|
||||||
let isDisabled = false
|
let isDisabled = false
|
||||||
if (
|
if (langPrefs.postLanguage.split(',').length >= 3 && !isSelected) {
|
||||||
store.preferences.postLanguage.split(',').length >= 3 &&
|
|
||||||
!isSelected
|
|
||||||
) {
|
|
||||||
isDisabled = true
|
isDisabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries'
|
||||||
import {MAX_POST_LINES} from 'lib/constants'
|
import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
|
|
||||||
export const PostThreadItem = observer(function PostThreadItem({
|
export const PostThreadItem = observer(function PostThreadItem({
|
||||||
item,
|
item,
|
||||||
|
@ -54,6 +55,7 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const mutedThreads = useMutedThreads()
|
const mutedThreads = useMutedThreads()
|
||||||
const toggleThreadMute = useToggleThreadMute()
|
const toggleThreadMute = useToggleThreadMute()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
const [deleted, setDeleted] = React.useState(false)
|
const [deleted, setDeleted] = React.useState(false)
|
||||||
const [limitLines, setLimitLines] = React.useState(
|
const [limitLines, setLimitLines] = React.useState(
|
||||||
countLines(item.richText?.text) >= MAX_POST_LINES,
|
countLines(item.richText?.text) >= MAX_POST_LINES,
|
||||||
|
@ -85,15 +87,15 @@ export const PostThreadItem = observer(function PostThreadItem({
|
||||||
|
|
||||||
const translatorUrl = getTranslatorLink(
|
const translatorUrl = getTranslatorLink(
|
||||||
record?.text || '',
|
record?.text || '',
|
||||||
store.preferences.primaryLanguage,
|
langPrefs.primaryLanguage,
|
||||||
)
|
)
|
||||||
const needsTranslation = useMemo(
|
const needsTranslation = useMemo(
|
||||||
() =>
|
() =>
|
||||||
Boolean(
|
Boolean(
|
||||||
store.preferences.primaryLanguage &&
|
langPrefs.primaryLanguage &&
|
||||||
!isPostInLanguage(item.post, [store.preferences.primaryLanguage]),
|
!isPostInLanguage(item.post, [langPrefs.primaryLanguage]),
|
||||||
),
|
),
|
||||||
[item.post, store.preferences.primaryLanguage],
|
[item.post, langPrefs.primaryLanguage],
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressReply = React.useCallback(() => {
|
const onPressReply = React.useCallback(() => {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {countLines} from 'lib/strings/helpers'
|
import {countLines} from 'lib/strings/helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
|
|
||||||
export const Post = observer(function PostImpl({
|
export const Post = observer(function PostImpl({
|
||||||
view,
|
view,
|
||||||
|
@ -109,6 +110,7 @@ const PostLoaded = observer(function PostLoadedImpl({
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
const mutedThreads = useMutedThreads()
|
const mutedThreads = useMutedThreads()
|
||||||
const toggleThreadMute = useToggleThreadMute()
|
const toggleThreadMute = useToggleThreadMute()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
const [limitLines, setLimitLines] = React.useState(
|
const [limitLines, setLimitLines] = React.useState(
|
||||||
countLines(item.richText?.text) >= MAX_POST_LINES,
|
countLines(item.richText?.text) >= MAX_POST_LINES,
|
||||||
)
|
)
|
||||||
|
@ -125,7 +127,7 @@ const PostLoaded = observer(function PostLoadedImpl({
|
||||||
|
|
||||||
const translatorUrl = getTranslatorLink(
|
const translatorUrl = getTranslatorLink(
|
||||||
record?.text || '',
|
record?.text || '',
|
||||||
store.preferences.primaryLanguage,
|
langPrefs.primaryLanguage,
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressReply = React.useCallback(() => {
|
const onPressReply = React.useCallback(() => {
|
||||||
|
|
|
@ -34,6 +34,7 @@ import {MAX_POST_LINES} from 'lib/constants'
|
||||||
import {countLines} from 'lib/strings/helpers'
|
import {countLines} from 'lib/strings/helpers'
|
||||||
import {logger} from '#/logger'
|
import {logger} from '#/logger'
|
||||||
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
import {useMutedThreads, useToggleThreadMute} from '#/state/muted-threads'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
|
|
||||||
export const FeedItem = observer(function FeedItemImpl({
|
export const FeedItem = observer(function FeedItemImpl({
|
||||||
item,
|
item,
|
||||||
|
@ -50,6 +51,7 @@ export const FeedItem = observer(function FeedItemImpl({
|
||||||
showReplyLine?: boolean
|
showReplyLine?: boolean
|
||||||
}) {
|
}) {
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const mutedThreads = useMutedThreads()
|
const mutedThreads = useMutedThreads()
|
||||||
const toggleThreadMute = useToggleThreadMute()
|
const toggleThreadMute = useToggleThreadMute()
|
||||||
|
@ -75,7 +77,7 @@ export const FeedItem = observer(function FeedItemImpl({
|
||||||
}, [record?.reply])
|
}, [record?.reply])
|
||||||
const translatorUrl = getTranslatorLink(
|
const translatorUrl = getTranslatorLink(
|
||||||
record?.text || '',
|
record?.text || '',
|
||||||
store.preferences.primaryLanguage,
|
langPrefs.primaryLanguage,
|
||||||
)
|
)
|
||||||
|
|
||||||
const onPressReply = React.useCallback(() => {
|
const onPressReply = React.useCallback(() => {
|
||||||
|
|
|
@ -17,6 +17,7 @@ import {useFocusEffect} from '@react-navigation/native'
|
||||||
import {ViewHeader} from '../com/util/ViewHeader'
|
import {ViewHeader} from '../com/util/ViewHeader'
|
||||||
import {CenteredView} from 'view/com/util/Views'
|
import {CenteredView} from 'view/com/util/Views'
|
||||||
import {useSetMinimalShellMode} from '#/state/shell'
|
import {useSetMinimalShellMode} from '#/state/shell'
|
||||||
|
import {useLanguagePrefs} from '#/state/preferences'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'AppPasswords'>
|
||||||
export const AppPasswords = withAuthRequired(
|
export const AppPasswords = withAuthRequired(
|
||||||
|
@ -161,6 +162,7 @@ function AppPassword({
|
||||||
}) {
|
}) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const {contentLanguages} = useLanguagePrefs()
|
||||||
|
|
||||||
const onDelete = React.useCallback(async () => {
|
const onDelete = React.useCallback(async () => {
|
||||||
store.shell.openModal({
|
store.shell.openModal({
|
||||||
|
@ -174,8 +176,6 @@ function AppPassword({
|
||||||
})
|
})
|
||||||
}, [store, name])
|
}, [store, name])
|
||||||
|
|
||||||
const {contentLanguages} = store.preferences
|
|
||||||
|
|
||||||
const primaryLocale =
|
const primaryLocale =
|
||||||
contentLanguages.length > 0 ? contentLanguages[0] : 'en-US'
|
contentLanguages.length > 0 ? contentLanguages[0] : 'en-US'
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ import {useFocusEffect} from '@react-navigation/native'
|
||||||
import {LANGUAGES} from 'lib/../locale/languages'
|
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 {useLanguagePrefs, useSetLanguagePrefs} from '#/state/preferences'
|
||||||
|
|
||||||
type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
|
type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
|
||||||
|
|
||||||
|
@ -27,6 +28,8 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl(
|
||||||
) {
|
) {
|
||||||
const pal = usePalette('default')
|
const pal = usePalette('default')
|
||||||
const store = useStores()
|
const store = useStores()
|
||||||
|
const langPrefs = useLanguagePrefs()
|
||||||
|
const setLangPrefs = useSetLanguagePrefs()
|
||||||
const {isTabletOrDesktop} = useWebMediaQueries()
|
const {isTabletOrDesktop} = useWebMediaQueries()
|
||||||
const {screen, track} = useAnalytics()
|
const {screen, track} = useAnalytics()
|
||||||
const setMinimalShellMode = useSetMinimalShellMode()
|
const setMinimalShellMode = useSetMinimalShellMode()
|
||||||
|
@ -45,21 +48,23 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl(
|
||||||
|
|
||||||
const onChangePrimaryLanguage = React.useCallback(
|
const onChangePrimaryLanguage = React.useCallback(
|
||||||
(value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
|
(value: Parameters<PickerSelectProps['onValueChange']>[0]) => {
|
||||||
store.preferences.setPrimaryLanguage(value)
|
if (langPrefs.primaryLanguage !== value) {
|
||||||
|
setLangPrefs(v => ({...v, primaryLanguage: value}))
|
||||||
|
}
|
||||||
},
|
},
|
||||||
[store.preferences],
|
[langPrefs, setLangPrefs],
|
||||||
)
|
)
|
||||||
|
|
||||||
const myLanguages = React.useMemo(() => {
|
const myLanguages = React.useMemo(() => {
|
||||||
return (
|
return (
|
||||||
store.preferences.contentLanguages
|
langPrefs.contentLanguages
|
||||||
.map(lang => LANGUAGES.find(l => l.code2 === lang))
|
.map(lang => LANGUAGES.find(l => l.code2 === lang))
|
||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
.map(l => l.name)
|
.map(l => l.name)
|
||||||
.join(', ')
|
.join(', ')
|
||||||
)
|
)
|
||||||
}, [store.preferences.contentLanguages])
|
}, [langPrefs.contentLanguages])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CenteredView
|
<CenteredView
|
||||||
|
@ -82,7 +87,7 @@ export const LanguageSettingsScreen = observer(function LanguageSettingsImpl(
|
||||||
|
|
||||||
<View style={{position: 'relative'}}>
|
<View style={{position: 'relative'}}>
|
||||||
<RNPickerSelect
|
<RNPickerSelect
|
||||||
value={store.preferences.primaryLanguage}
|
value={langPrefs.primaryLanguage}
|
||||||
onValueChange={onChangePrimaryLanguage}
|
onValueChange={onChangePrimaryLanguage}
|
||||||
items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
|
items={LANGUAGES.filter(l => Boolean(l.code2)).map(l => ({
|
||||||
label: l.name,
|
label: l.name,
|
||||||
|
|
Loading…
Reference in New Issue