forked from
jollywhoppers.com/witchsky.app
Bluesky app fork with some witchin' additions 馃挮
1import {useCallback, useMemo, useState} from 'react'
2import {View} from 'react-native'
3import {msg, Trans} from '@lingui/macro'
4import {useLingui} from '@lingui/react'
5
6import {
7 type CommonNavigatorParams,
8 type NativeStackScreenProps,
9} from '#/lib/routes/types'
10import {languageName, sanitizeAppLanguageSetting} from '#/locale/helpers'
11import {APP_LANGUAGES, LANGUAGES} from '#/locale/languages'
12import {useLanguagePrefs, useLanguagePrefsApi} from '#/state/preferences'
13import {atoms as a, web} from '#/alf'
14import {Admonition} from '#/components/Admonition'
15import {Button} from '#/components/Button'
16import {useDialogControl} from '#/components/Dialog'
17import {LanguageSelectDialog} from '#/components/dialogs/LanguageSelectDialog'
18import * as Toggle from '#/components/forms/Toggle'
19import {PlusLarge_Stroke2_Corner0_Rounded as PlusIcon} from '#/components/icons/Plus'
20import * as Layout from '#/components/Layout'
21import * as Select from '#/components/Select'
22import {Text} from '#/components/Typography'
23import * as SettingsList from './components/SettingsList'
24
25const DEDUPED_LANGUAGES = LANGUAGES.filter(
26 (lang, i, arr) =>
27 lang.code2 && arr.findIndex(l => l.code2 === lang.code2) === i,
28)
29
30type Props = NativeStackScreenProps<CommonNavigatorParams, 'LanguageSettings'>
31export function LanguageSettingsScreen({}: Props) {
32 const {_} = useLingui()
33 const langPrefs = useLanguagePrefs()
34 const setLangPrefs = useLanguagePrefsApi()
35
36 const contentLanguagePrefsControl = useDialogControl()
37
38 const onChangePrimaryLanguage = useCallback(
39 (value: string) => {
40 if (!value) return
41 if (langPrefs.primaryLanguage !== value) {
42 setLangPrefs.setPrimaryLanguage(value)
43 }
44 },
45 [langPrefs, setLangPrefs],
46 )
47
48 const onChangeAppLanguage = useCallback(
49 (value: string) => {
50 if (!value) return
51 if (langPrefs.appLanguage !== value) {
52 setLangPrefs.setAppLanguage(sanitizeAppLanguageSetting(value))
53 }
54 },
55 [langPrefs, setLangPrefs],
56 )
57
58 const [recentLanguages, setRecentLanguages] = useState<string[]>(
59 langPrefs.contentLanguages,
60 )
61
62 const possibleLanguages = useMemo(() => {
63 return [
64 ...new Set([
65 ...recentLanguages,
66 ...langPrefs.contentLanguages,
67 ...langPrefs.primaryLanguage,
68 ]),
69 ]
70 .map(lang => LANGUAGES.find(l => l.code2 === lang))
71 .filter(x => !!x)
72 }, [recentLanguages, langPrefs.contentLanguages, langPrefs.primaryLanguage])
73
74 return (
75 <Layout.Screen testID="PreferencesLanguagesScreen">
76 <Layout.Header.Outer>
77 <Layout.Header.BackButton />
78 <Layout.Header.Content>
79 <Layout.Header.TitleText>
80 <Trans>Languages</Trans>
81 </Layout.Header.TitleText>
82 </Layout.Header.Content>
83 <Layout.Header.Slot />
84 </Layout.Header.Outer>
85 <Layout.Content>
86 <SettingsList.Container>
87 <SettingsList.Group iconInset={false}>
88 <SettingsList.ItemText>
89 <Trans>App language</Trans>
90 </SettingsList.ItemText>
91 <View style={[a.gap_md, a.w_full]}>
92 <Text style={[a.leading_snug]}>
93 <Trans>
94 Select which language to use for the app's user interface.
95 </Trans>
96 </Text>
97 <Select.Root
98 value={sanitizeAppLanguageSetting(langPrefs.appLanguage)}
99 onValueChange={onChangeAppLanguage}>
100 <Select.Trigger label={_(msg`Select app language`)}>
101 <Select.ValueText />
102 <Select.Icon />
103 </Select.Trigger>
104 <Select.Content
105 label={_(msg`App language`)}
106 renderItem={({label, value}) => (
107 <Select.Item value={value} label={label}>
108 <Select.ItemIndicator />
109 <Select.ItemText>{label}</Select.ItemText>
110 </Select.Item>
111 )}
112 items={APP_LANGUAGES.map(l => ({
113 label: l.name,
114 value: l.code2,
115 }))}
116 />
117 </Select.Root>
118 </View>
119 </SettingsList.Group>
120 <SettingsList.Divider />
121 <SettingsList.Group iconInset={false}>
122 <SettingsList.ItemText>
123 <Trans>Primary language</Trans>
124 </SettingsList.ItemText>
125 <View style={[a.gap_md, a.w_full]}>
126 <Text style={[a.leading_snug]}>
127 <Trans>
128 Select your preferred language for translations in your feed.
129 </Trans>
130 </Text>
131 <Select.Root
132 value={langPrefs.primaryLanguage}
133 onValueChange={onChangePrimaryLanguage}>
134 <Select.Trigger label={_(msg`Select primary language`)}>
135 <Select.ValueText />
136 <Select.Icon />
137 </Select.Trigger>
138 <Select.Content
139 label={_(msg`Primary language`)}
140 renderItem={({label, value}) => (
141 <Select.Item value={value} label={label}>
142 <Select.ItemIndicator />
143 <Select.ItemText>{label}</Select.ItemText>
144 </Select.Item>
145 )}
146 items={DEDUPED_LANGUAGES.map(l => ({
147 label: languageName(l, langPrefs.appLanguage),
148 value: l.code2,
149 }))}
150 />
151 </Select.Root>
152 </View>
153 </SettingsList.Group>
154 <SettingsList.Divider />
155 <SettingsList.Group iconInset={false}>
156 <SettingsList.ItemText>
157 <Trans>Content languages</Trans>
158 </SettingsList.ItemText>
159 <View style={[a.gap_md]}>
160 <Text style={[a.leading_snug]}>
161 <Trans>
162 Select which languages you want your subscribed feeds to
163 include. If none are selected, all languages will be shown.
164 </Trans>
165 </Text>
166
167 {langPrefs.contentLanguages.length === 0 && (
168 <Admonition type="info">
169 <Trans>All languages will be shown in your feeds.</Trans>
170 </Admonition>
171 )}
172
173 <View style={[a.w_full, web({maxWidth: 400})]}>
174 <Toggle.Group
175 label={_(msg`Select content languages`)}
176 values={langPrefs.contentLanguages}
177 onChange={setLangPrefs.setContentLanguages}>
178 <Toggle.PanelGroup>
179 {possibleLanguages.map((language, index) => {
180 const name = languageName(language, langPrefs.appLanguage)
181 return (
182 <Toggle.Item
183 key={language.code2}
184 name={language.code2}
185 label={name}>
186 {({selected}) => (
187 <Toggle.Panel
188 active={selected}
189 adjacent={index === 0 ? 'trailing' : 'both'}>
190 <Toggle.Checkbox />
191 <Toggle.PanelText>{name}</Toggle.PanelText>
192 </Toggle.Panel>
193 )}
194 </Toggle.Item>
195 )
196 })}
197 <Button
198 label={_(msg`Add more languages...`)}
199 onPress={contentLanguagePrefsControl.open}>
200 <Toggle.Panel adjacent="leading">
201 <Toggle.PanelIcon icon={PlusIcon} />
202 <Toggle.PanelText>
203 Add more languages...
204 </Toggle.PanelText>
205 </Toggle.Panel>
206 </Button>
207 </Toggle.PanelGroup>
208 </Toggle.Group>
209 </View>
210
211 <LanguageSelectDialog
212 control={contentLanguagePrefsControl}
213 titleText={<Trans>Select content languages</Trans>}
214 subtitleText={
215 <Trans>
216 If none are selected, all languages will be shown in your
217 feeds.
218 </Trans>
219 }
220 currentLanguages={langPrefs.contentLanguages}
221 onSelectLanguages={languages => {
222 setLangPrefs.setContentLanguages(languages)
223 setRecentLanguages(recent => [
224 ...new Set([...recent, ...languages]),
225 ])
226 }}
227 />
228 </View>
229 </SettingsList.Group>
230 </SettingsList.Container>
231 </Layout.Content>
232 </Layout.Screen>
233 )
234}