import {useCallback, useMemo, useState} from 'react'
import {useWindowDimensions, View} from 'react-native'
import {useSafeAreaInsets} from 'react-native-safe-area-context'
import {msg, Trans} from '@lingui/macro'
import {useLingui} from '@lingui/react'
import {languageName} from '#/locale/helpers'
import {type Language, LANGUAGES, LANGUAGES_MAP_CODE2} from '#/locale/languages'
import {isNative, isWeb} from '#/platform/detection'
import {
useLanguagePrefs,
useLanguagePrefsApi,
} from '#/state/preferences/languages'
import {ErrorScreen} from '#/view/com/util/error/ErrorScreen'
import {ErrorBoundary} from '#/view/com/util/ErrorBoundary'
import {atoms as a, useTheme, web} from '#/alf'
import {Button, ButtonIcon, ButtonText} from '#/components/Button'
import * as Dialog from '#/components/Dialog'
import {SearchInput} from '#/components/forms/SearchInput'
import * as Toggle from '#/components/forms/Toggle'
import {TimesLarge_Stroke2_Corner0_Rounded as XIcon} from '#/components/icons/Times'
import {Text} from '#/components/Typography'
export function PostLanguageSelectDialog({
control,
}: {
control: Dialog.DialogControlProps
}) {
const {height} = useWindowDimensions()
const insets = useSafeAreaInsets()
const renderErrorBoundary = useCallback(
(error: any) => ,
[],
)
return (
)
}
export function DialogInner() {
const control = Dialog.useDialogContext()
const [headerHeight, setHeaderHeight] = useState(0)
const allowedLanguages = useMemo(() => {
const uniqueLanguagesMap = LANGUAGES.filter(lang => !!lang.code2).reduce(
(acc, lang) => {
acc[lang.code2] = lang
return acc
},
{} as Record,
)
return Object.values(uniqueLanguagesMap)
}, [])
const langPrefs = useLanguagePrefs()
const [checkedLanguagesCode2, setCheckedLanguagesCode2] = useState(
langPrefs.postLanguage.split(',') || [langPrefs.primaryLanguage],
)
const [search, setSearch] = useState('')
const setLangPrefs = useLanguagePrefsApi()
const t = useTheme()
const {_} = useLingui()
const handleClose = () => {
control.close(() => {
let langsString = checkedLanguagesCode2.join(',')
if (!langsString) {
langsString = langPrefs.primaryLanguage
}
setLangPrefs.setPostLanguage(langsString)
})
}
// NOTE(@elijaharita): Displayed languages are split into 3 lists for
// ordering.
const displayedLanguages = useMemo(() => {
function mapCode2List(code2List: string[]) {
return code2List.map(code2 => LANGUAGES_MAP_CODE2[code2]).filter(Boolean)
}
// NOTE(@elijaharita): Get recent language codes and map them to language
// objects. Both the user account's saved language history and the current
// checked languages are displayed here.
const recentLanguagesCode2 =
Array.from(
new Set([...checkedLanguagesCode2, ...langPrefs.postLanguageHistory]),
).slice(0, 5) || []
const recentLanguages = mapCode2List(recentLanguagesCode2)
// NOTE(@elijaharita): helper functions
const matchesSearch = (lang: Language) =>
lang.name.toLowerCase().includes(search.toLowerCase())
const isChecked = (lang: Language) =>
checkedLanguagesCode2.includes(lang.code2)
const isInRecents = (lang: Language) =>
recentLanguagesCode2.includes(lang.code2)
const checkedRecent = recentLanguages.filter(isChecked)
if (search) {
// NOTE(@elijaharita): if a search is active, we ALWAYS show checked
// items, as well as any items that match the search.
const uncheckedRecent = recentLanguages
.filter(lang => !isChecked(lang))
.filter(matchesSearch)
const unchecked = allowedLanguages.filter(lang => !isChecked(lang))
const all = unchecked
.filter(matchesSearch)
.filter(lang => !isInRecents(lang))
return {
all,
checkedRecent,
uncheckedRecent,
}
} else {
// NOTE(@elijaharita): if no search is active, we show everything.
const uncheckedRecent = recentLanguages.filter(lang => !isChecked(lang))
const all = allowedLanguages
.filter(lang => !recentLanguagesCode2.includes(lang.code2))
.filter(lang => !isInRecents(lang))
return {
all,
checkedRecent,
uncheckedRecent,
}
}
}, [
allowedLanguages,
search,
langPrefs.postLanguageHistory,
checkedLanguagesCode2,
])
const listHeader = (
setHeaderHeight(evt.nativeEvent.layout.height)}>
Choose Post Languages
Select up to 3 languages used in this post
{isWeb && (
)}
setSearch('')}
/>
)
const isCheckedRecentEmpty =
displayedLanguages.checkedRecent.length > 0 ||
displayedLanguages.uncheckedRecent.length > 0
const isDisplayedLanguagesEmpty = displayedLanguages.all.length === 0
const flatListData = [
...(isCheckedRecentEmpty
? [{type: 'header', label: _(msg`Recently used`)}]
: []),
...displayedLanguages.checkedRecent.map(lang => ({type: 'item', lang})),
...displayedLanguages.uncheckedRecent.map(lang => ({type: 'item', lang})),
...(isDisplayedLanguagesEmpty
? []
: [{type: 'header', label: _(msg`All languages`)}]),
...displayedLanguages.all.map(lang => ({type: 'item', lang})),
]
return (
{
if (item.type === 'header') {
return (
{item.label}
)
}
const lang = item.lang
return (
{languageName(lang, langPrefs.appLanguage)}
)
}}
footer={
}
/>
)
}
function DialogError({details}: {details?: string}) {
const {_} = useLingui()
const control = Dialog.useDialogContext()
return (
)
}