refactor(Settings): simplify handling for langs

This commit is contained in:
Timothy Z. 2025-06-24 13:01:11 +03:00
parent f2490ee775
commit f49a243009
7 changed files with 29 additions and 37 deletions

View file

@ -26,6 +26,7 @@ const useStreamingServer = require('./useStreamingServer');
const useTorrent = require('./useTorrent');
const useTranslate = require('./useTranslate');
const { default: useOrientation } = require('./useOrientation');
const { default: useLanguageSorting } = require('./useLanguageSorting');
module.exports = {
FileDropProvider,
@ -59,4 +60,5 @@ module.exports = {
useTorrent,
useTranslate,
useOrientation,
useLanguageSorting,
};

View file

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import interfaceLanguages from 'stremio/common/interfaceLanguages.json';
const useLanguageSorting = (options?: MultiselectMenuOption[]) => {
const useLanguageSorting = (options: MultiselectMenuOption[]) => {
const userLangCode = useMemo(() => {
const lang = interfaceLanguages.find((l) => l.codes.includes(navigator.language || 'en-US'));
if (lang) {
@ -17,8 +17,6 @@ const useLanguageSorting = (options?: MultiselectMenuOption[]) => {
}, [options]);
const sortedOptions = useMemo(() => {
if (!isLanguageDropdown || !options) return options;
const matchingIndex = options.findIndex((opt) => {
const lang = interfaceLanguages.find((l) => l.name === opt.label);
return userLangCode.some((code) => lang?.codes.includes(code));

View file

@ -7,7 +7,6 @@ import classNames from 'classnames';
import Option from './Option';
import Icon from '@stremio/stremio-icons/react';
import styles from './Dropdown.less';
import useLanguageSorting from './useLanguageSorting';
type Props = {
options: MultiselectMenuOption[];
@ -20,7 +19,6 @@ type Props = {
const Dropdown = ({ level, setLevel, options, onSelect, value, menuOpen }: Props) => {
const { t } = useTranslation();
const { isLanguageDropdown, sortedOptions } = useLanguageSorting(options);
const optionsRef = useRef(new Map());
const containerRef = useRef(null);
@ -63,8 +61,8 @@ const Dropdown = ({ level, setLevel, options, onSelect, value, menuOpen }: Props
</Button>
: null
}
{(isLanguageDropdown ? sortedOptions : options)
?.filter((option: MultiselectMenuOption) => !option.hidden)
{options
.filter((option: MultiselectMenuOption) => !option.hidden)
.map((option: MultiselectMenuOption) => (
<Option
key={option.value}

View file

@ -23,10 +23,6 @@
opacity: 1;
}
&.separator {
border-bottom: thin solid var(--overlay-color);
}
&:hover {
background-color: rgba(255, 255, 255, 0.15);
}

View file

@ -5,8 +5,6 @@ import classNames from 'classnames';
import { Button } from 'stremio/components';
import styles from './Option.less';
import Icon from '@stremio/stremio-icons/react';
import useLanguageSorting from '../useLanguageSorting';
import interfaceLanguages from 'stremio/common/interfaceLanguages.json';
type Props = {
option: MultiselectMenuOption;
@ -15,15 +13,8 @@ type Props = {
};
const Option = forwardRef<HTMLButtonElement, Props>(({ option, selectedValue, onSelect }, ref) => {
const { userLangCode } = useLanguageSorting();
const selected = useMemo(() => option?.value === selectedValue, [option, selectedValue]);
const separator = useMemo(() => {
const lang = interfaceLanguages.find((l) => l.name === option?.label);
return lang ? userLangCode.some((code) => lang.codes.includes(code)) : false;
}, [option, userLangCode]);
const handleClick = useCallback(() => {
onSelect(option.value);
}, [onSelect, option.value]);
@ -31,7 +22,7 @@ const Option = forwardRef<HTMLButtonElement, Props>(({ option, selectedValue, on
return (
<Button
ref={ref}
className={classNames(styles['option'], { [styles['selected']]: selected }, { [styles['separator']]: separator })}
className={classNames(styles['option'], { [styles['selected']]: selected })}
key={option.id}
onClick={handleClick}
aria-selected={selected}

View file

@ -1,15 +1,20 @@
import { useMemo } from 'react';
import { interfaceLanguages } from 'stremio/common';
import { interfaceLanguages, useLanguageSorting } from 'stremio/common';
import { useServices } from 'stremio/services';
const useGeneralOptions = (profile: Profile) => {
const { core } = useServices();
const interfaceLanguageSelect = useMemo(() => ({
options: interfaceLanguages.map(({ name, codes }) => ({
const interfaceLanguageOptions = useMemo(() =>
interfaceLanguages.map(({ name, codes }) => ({
value: codes[0],
label: name,
})),
})), []);
const { sortedOptions } = useLanguageSorting(interfaceLanguageOptions);
const interfaceLanguageSelect = useMemo(() => ({
options: sortedOptions,
value: interfaceLanguages.find(({ codes }) => codes[1] === profile.settings.interfaceLanguage)?.codes?.[0] || profile.settings.interfaceLanguage,
onSelect: (value: string) => {
core.transport.dispatch({
@ -23,7 +28,7 @@ const useGeneralOptions = (profile: Profile) => {
}
});
}
}), [profile.settings]);
}), [profile.settings, sortedOptions]);
const escExitFullscreenToggle = useMemo(() => ({
checked: profile.settings.escExitFullscreen,

View file

@ -1,7 +1,7 @@
import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { useServices } from 'stremio/services';
import { CONSTANTS, languageNames, usePlatform } from 'stremio/common';
import { CONSTANTS, languageNames, usePlatform, useLanguageSorting } from 'stremio/common';
const LANGUAGES_NAMES: Record<string, string> = languageNames;
@ -10,13 +10,18 @@ const usePlayerOptions = (profile: Profile) => {
const { core } = useServices();
const platform = usePlatform();
const languageOptions = useMemo(() =>
Object.keys(LANGUAGES_NAMES).map((code) => ({
value: code,
label: LANGUAGES_NAMES[code]
})), []);
const { sortedOptions: sortedLanguageOptions } = useLanguageSorting(languageOptions);
const subtitlesLanguageSelect = useMemo(() => ({
options: [
{ value: null, label: t('NONE') },
...Object.keys(LANGUAGES_NAMES).map((code) => ({
value: code,
label: LANGUAGES_NAMES[code]
}))
...sortedLanguageOptions
],
value: profile.settings.subtitlesLanguage,
onSelect: (value: string) => {
@ -31,7 +36,7 @@ const usePlayerOptions = (profile: Profile) => {
}
});
}
}), [profile.settings]);
}), [profile.settings, sortedLanguageOptions, t]);
const subtitlesSizeSelect = useMemo(() => ({
options: CONSTANTS.SUBTITLES_SIZES.map((size) => ({
@ -105,10 +110,7 @@ const usePlayerOptions = (profile: Profile) => {
}), [profile.settings]);
const audioLanguageSelect = useMemo(() => ({
options: Object.keys(LANGUAGES_NAMES).map((code) => ({
value: code,
label: LANGUAGES_NAMES [code]
})),
options: sortedLanguageOptions,
value: profile.settings.audioLanguage,
onSelect: (value: string) => {
core.transport.dispatch({
@ -122,7 +124,7 @@ const usePlayerOptions = (profile: Profile) => {
}
});
}
}), [profile.settings]);
}), [profile.settings, sortedLanguageOptions]);
const surroundSoundToggle = useMemo(() => ({
checked: profile.settings.surroundSound,