ALF content language dialog (#9471)

Co-authored-by: Eric Bailey <git@esb.lol>
This commit is contained in:
Samuel Newman
2026-02-18 16:57:32 +00:00
committed by GitHub
parent bdf143ce79
commit 512ce3d5d0
14 changed files with 170 additions and 659 deletions
-4
View File
@@ -7,7 +7,6 @@ import {usePalette} from '#/lib/hooks/usePalette'
import {useModalControls, useModals} from '#/state/modals'
import {FullWindowOverlay} from '#/components/FullWindowOverlay'
import {createCustomBackdrop} from '../util/BottomSheetCustomBackdrop'
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
import * as UserAddRemoveListsModal from './UserAddRemoveLists'
const DEFAULT_SNAPPOINTS = ['90%']
@@ -44,9 +43,6 @@ export function ModalsContainer() {
if (activeModal?.name === 'user-add-remove-lists') {
snapPoints = UserAddRemoveListsModal.snapPoints
element = <UserAddRemoveListsModal.Component {...activeModal} />
} else if (activeModal?.name === 'content-languages-settings') {
snapPoints = ContentLanguagesSettingsModal.snapPoints
element = <ContentLanguagesSettingsModal.Component />
} else {
return null
}
-3
View File
@@ -6,7 +6,6 @@ import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {type Modal as ModalIface} from '#/state/modals'
import {useModalControls, useModals} from '#/state/modals'
import * as ContentLanguagesSettingsModal from './lang-settings/ContentLanguagesSettings'
import * as UserAddRemoveLists from './UserAddRemoveLists'
export function ModalsContainer() {
@@ -47,8 +46,6 @@ function Modal({modal}: {modal: ModalIface}) {
let element
if (modal.name === 'user-add-remove-lists') {
element = <UserAddRemoveLists.Component {...modal} />
} else if (modal.name === 'content-languages-settings') {
element = <ContentLanguagesSettingsModal.Component />
} else {
return null
}
@@ -1,64 +0,0 @@
import {Pressable, StyleSheet, Text, View} from 'react-native'
import {LinearGradient} from 'expo-linear-gradient'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {colors, gradients, s} from '#/lib/styles'
export const ConfirmLanguagesButton = ({
onPress,
extraText,
}: {
onPress: () => void
extraText?: string
}) => {
const pal = usePalette('default')
const {_} = useLingui()
const {isMobile} = useWebMediaQueries()
return (
<View
style={[
styles.btnContainer,
pal.borderDark,
isMobile && {
paddingBottom: 40,
borderTopWidth: 1,
},
]}>
<Pressable
testID="confirmContentLanguagesBtn"
onPress={onPress}
accessibilityRole="button"
accessibilityLabel={_(msg`Confirm content language settings`)}
accessibilityHint="">
<LinearGradient
colors={[gradients.blueLight.start, gradients.blueLight.end]}
start={{x: 0, y: 0}}
end={{x: 1, y: 1}}
style={[styles.btn]}>
<Text style={[s.white, s.bold, s.f18]}>
<Trans>Done{extraText}</Trans>
</Text>
</LinearGradient>
</Pressable>
</View>
)
}
const styles = StyleSheet.create({
btnContainer: {
paddingTop: 10,
paddingHorizontal: 10,
},
btn: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
width: '100%',
borderRadius: 32,
padding: 14,
backgroundColor: colors.gray1,
},
})
@@ -1,128 +0,0 @@
import React from 'react'
import {StyleSheet, View} from 'react-native'
import {Trans} from '@lingui/macro'
import {usePalette} from '#/lib/hooks/usePalette'
import {useWebMediaQueries} from '#/lib/hooks/useWebMediaQueries'
import {deviceLanguageCodes} from '#/locale/deviceLocales'
import {languageName} from '#/locale/helpers'
import {useModalControls} from '#/state/modals'
import {
useLanguagePrefs,
useLanguagePrefsApi,
} from '#/state/preferences/languages'
import {LANGUAGES, LANGUAGES_MAP_CODE2} from '../../../../locale/languages'
import {Text} from '../../util/text/Text'
import {ScrollView} from '../util'
import {ConfirmLanguagesButton} from './ConfirmLanguagesButton'
import {LanguageToggle} from './LanguageToggle'
export const snapPoints = ['100%']
export function Component({}: {}) {
const {closeModal} = useModalControls()
const langPrefs = useLanguagePrefs()
const setLangPrefs = useLanguagePrefsApi()
const pal = usePalette('default')
const {isMobile} = useWebMediaQueries()
const onPressDone = React.useCallback(() => {
closeModal()
}, [closeModal])
const languages = React.useMemo(() => {
const langs = LANGUAGES.filter(
lang =>
!!lang.code2.trim() &&
LANGUAGES_MAP_CODE2[lang.code2].code3 === lang.code3,
)
// sort so that device & selected languages are on top, then alphabetically
langs.sort((a, b) => {
const hasA =
langPrefs.contentLanguages.includes(a.code2) ||
deviceLanguageCodes.includes(a.code2)
const hasB =
langPrefs.contentLanguages.includes(b.code2) ||
deviceLanguageCodes.includes(b.code2)
if (hasA === hasB) return a.name.localeCompare(b.name)
if (hasA) return -1
return 1
})
return langs
}, [langPrefs])
const onPress = React.useCallback(
(code2: string) => {
setLangPrefs.toggleContentLanguage(code2)
},
[setLangPrefs],
)
return (
<View
testID="contentLanguagesModal"
style={[
pal.view,
styles.container,
// @ts-ignore vh is web only
isMobile
? {
paddingTop: 20,
}
: {
maxHeight: '90vh',
},
]}>
<Text style={[pal.text, styles.title]}>
<Trans>Content Languages</Trans>
</Text>
<Text style={[pal.text, styles.description]}>
<Trans>
Which languages would you like to see in your algorithmic feeds?
</Trans>
</Text>
<Text style={[pal.textLight, styles.description]}>
<Trans>Leave them all unselected to see any language.</Trans>
</Text>
<ScrollView style={styles.scrollContainer}>
{languages.map(lang => (
<LanguageToggle
key={lang.code2}
code2={lang.code2}
langType="contentLanguages"
name={languageName(lang, langPrefs.appLanguage)}
onPress={() => {
onPress(lang.code2)
}}
/>
))}
<View
style={{
height: isMobile ? 60 : 0,
}}
/>
</ScrollView>
<ConfirmLanguagesButton onPress={onPressDone} />
</View>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
title: {
textAlign: 'center',
fontWeight: '600',
fontSize: 24,
marginBottom: 12,
},
description: {
textAlign: 'center',
paddingHorizontal: 16,
marginBottom: 10,
},
scrollContainer: {
flex: 1,
paddingHorizontal: 10,
},
})
@@ -1,53 +0,0 @@
import {StyleSheet} from 'react-native'
import {usePalette} from '#/lib/hooks/usePalette'
import {toPostLanguages, useLanguagePrefs} from '#/state/preferences/languages'
import {ToggleButton} from '#/view/com/util/forms/ToggleButton'
export function LanguageToggle({
code2,
name,
onPress,
langType,
}: {
code2: string
name: string
onPress: () => void
langType: 'contentLanguages' | 'postLanguages'
}) {
const pal = usePalette('default')
const langPrefs = useLanguagePrefs()
const values =
langType === 'contentLanguages'
? langPrefs.contentLanguages
: toPostLanguages(langPrefs.postLanguage)
const isSelected = values.includes(code2)
// enforce a max of 3 selections for post languages
let isDisabled = false
if (langType === 'postLanguages' && values.length >= 3 && !isSelected) {
isDisabled = true
}
return (
<ToggleButton
label={name}
isSelected={isSelected}
onPress={isDisabled ? undefined : onPress}
style={[pal.border, styles.languageToggle, isDisabled && styles.dimmed]}
/>
)
}
const styles = StyleSheet.create({
languageToggle: {
borderTopWidth: 1,
borderRadius: 0,
paddingHorizontal: 6,
paddingVertical: 12,
},
dimmed: {
opacity: 0.5,
},
})