/* * Copyright (C) Contributors to the Suwayomi project * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ import { useMemo, useState } from 'react'; import Button from '@mui/material/Button'; import DialogTitle from '@mui/material/DialogTitle'; import DialogContent from '@mui/material/DialogContent'; import DialogActions from '@mui/material/DialogActions'; import Dialog from '@mui/material/Dialog'; import Switch from '@mui/material/Switch'; import IconButton from '@mui/material/IconButton'; import FilterListIcon from '@mui/icons-material/FilterList'; import ListItemText from '@mui/material/ListItemText'; import ListItem from '@mui/material/ListItem'; import { useTranslation } from 'react-i18next'; import { Virtuoso } from 'react-virtuoso'; import Box from '@mui/material/Box'; import ListItemAvatar from '@mui/material/ListItemAvatar'; import { CustomTooltip } from '@/base/components/CustomTooltip.tsx'; import { translateExtensionLanguage } from '@/features/extension/Extensions.utils.ts'; import { languageSortComparator } from '@/base/utils/Languages.ts'; import { SourceDisplayNameInfo, SourceIconInfo, SourceIdInfo, SourceLanguageInfo, SourceMetaInfo, SourceNameInfo, } from '@/features/source/Source.types.ts'; import { Sources } from '@/features/source/services/Sources'; import { getSourceMetadata, updateSourceMetadata } from '@/features/source/services/SourceMetadata.ts'; import { requestManager } from '@/lib/requests/RequestManager.ts'; import { ListCardAvatar } from '@/base/components/lists/cards/ListCardAvatar.tsx'; import { makeToast } from '@/base/utils/Toast.ts'; import { getErrorMessage } from '@/lib/HelperFunctions.ts'; import { toUniqueISOLanguageCodes } from '@/lib/ISOLanguageUtil.ts'; export const SourceLanguageSelect = ({ selectedLanguages, setSelectedLanguages, languages, sources, }: { selectedLanguages: string[]; setSelectedLanguages: (languages: string[]) => void; languages: string[]; sources: (SourceIdInfo & SourceLanguageInfo & SourceNameInfo & SourceDisplayNameInfo & SourceIconInfo & SourceMetaInfo)[]; }) => { const { t } = useTranslation(); const [tmpSourceIdToEnabledState, setTmpSourceIdToEnabledState] = useState>({}); const [tmpSelectedLanguages, setTmpSelectedLanguages] = useState(toUniqueISOLanguageCodes(selectedLanguages)); const [open, setOpen] = useState(false); const sourcesByLanguage = useMemo(() => Sources.groupByLanguage(sources), [sources]); const languagesSortedBySelectState = useMemo( () => toUniqueISOLanguageCodes([ ...tmpSelectedLanguages.toSorted(languageSortComparator), ...languages.toSorted(languageSortComparator), ]), [languages, tmpSelectedLanguages], ); const handleCancel = () => { setOpen(false); setTmpSourceIdToEnabledState({}); setTmpSelectedLanguages(toUniqueISOLanguageCodes(selectedLanguages)); }; const handleOk = () => { setOpen(false); Promise.all( Object.entries(tmpSourceIdToEnabledState).map(([sourceId, enabled]) => updateSourceMetadata(sources.find((source) => source.id === sourceId)!, 'isEnabled', enabled), ), ).catch((e) => makeToast(t('global.error.label.failed_to_save_changes'), 'error', getErrorMessage(e))); setTmpSourceIdToEnabledState({}); setSelectedLanguages(toUniqueISOLanguageCodes(tmpSelectedLanguages)); }; const handleChange = (language: string, selected: boolean) => { if (selected) { setTmpSelectedLanguages([...tmpSelectedLanguages, language]); } else { setTmpSelectedLanguages(tmpSelectedLanguages.toSpliced(tmpSelectedLanguages.indexOf(language), 1)); } }; return ( <> setOpen(true)} aria-label="display more actions" edge="end" color="inherit"> {t('global.language.title.enabled_languages')} languagesSortedBySelectState[index]} itemContent={(_index, language) => { const sourcesOfLanguage = sourcesByLanguage[language] ?? []; const isEnabled = tmpSelectedLanguages.includes(language); return ( <> handleChange(language, e.target.checked)} /> {isEnabled && !!sourcesOfLanguage.length && ( {sourcesOfLanguage.map((source) => ( setTmpSourceIdToEnabledState({ ...tmpSourceIdToEnabledState, [source.id]: e.target.checked, }) } /> ))} )} ); }} /> ); };