diff --git a/src/screens/SettingsScreen.tsx b/src/screens/SettingsScreen.tsx
index f87e2d1b..4db1341b 100644
--- a/src/screens/SettingsScreen.tsx
+++ b/src/screens/SettingsScreen.tsx
@@ -436,7 +436,13 @@ const SettingsScreen: React.FC = () => {
return (
<>
-
+ i18n.changeLanguage(code)}
+ isTablet={isTablet}
+ isLast
+ />
>
@@ -703,7 +709,11 @@ const SettingsScreen: React.FC = () => {
(settingsConfig?.categories?.['playback']?.visible !== false)
) && (
-
+ i18n.changeLanguage(code)}
+ />
{(settingsConfig?.categories?.['content']?.visible !== false) && (
a.name.localeCompare(b.name));
+export interface LanguageOption {
+ code: string;
+ name: string;
+}
interface LanguageSettingItemProps {
+ title: string;
+ value: string;
+ onChange: (code: string) => void;
+ languages?: LanguageOption[];
isTablet?: boolean;
isLast?: boolean;
}
-export const LanguageSettingItem: React.FC = ({ isTablet = false, isLast = false }) => {
- const { t, i18n } = useTranslation();
+export const LanguageSettingItem: React.FC = ({
+ title,
+ value,
+ onChange,
+ languages,
+ isTablet = false,
+ isLast = false,
+}) => {
const { currentTheme } = useTheme();
const insets = useSafeAreaInsets();
const sheetRef = useRef(null);
- const { onChange, onDismiss } = useBottomSheetBackHandler();
+ const { onChange: onSheetChange, onDismiss } = useBottomSheetBackHandler();
+
+ const sortedLanguages = useMemo(() => {
+ const sorted = [...(languages ?? LOCALES)].sort((a, b) => a.name.localeCompare(b.name));
+ const selectedIndex = sorted.findIndex(l => l.code === value || l.code === value?.split('-')[0]);
+ if (selectedIndex > 0) {
+ const [selected] = sorted.splice(selectedIndex, 1);
+ sorted.unshift(selected);
+ }
+ return sorted;
+ }, [languages, value]);
const currentLocale =
- LOCALES.find(l => l.code === i18n.language) ??
- LOCALES.find(l => l.code === i18n.language?.split('-')[0]);
+ sortedLanguages.find(l => l.code === value) ??
+ sortedLanguages.find(l => l.code === value?.split('-')[0]);
const renderBackdrop = useCallback(
(props: any) => (
@@ -37,7 +59,7 @@ export const LanguageSettingItem: React.FC = ({ isTabl
return (
<>
}
@@ -61,12 +83,12 @@ export const LanguageSettingItem: React.FC = ({ isTabl
backgroundColor: currentTheme.colors.mediumGray,
width: 40,
}}
- onChange={onChange(sheetRef)}
+ onChange={onSheetChange(sheetRef)}
onDismiss={onDismiss(sheetRef)}
>
- {t('settings.select_language')}
+ {title}
sheetRef.current?.dismiss()}>
@@ -76,9 +98,8 @@ export const LanguageSettingItem: React.FC = ({ isTabl
style={{ backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }}
contentContainerStyle={[styles.sheetContent, { paddingBottom: insets.bottom + 16 }]}
>
- {SORTED_LOCALES.map(l => {
- const isSelected = i18n.language === l.code ||
- i18n.language?.split('-')[0] === l.code;
+ {sortedLanguages.map(l => {
+ const isSelected = value === l.code || value?.split('-')[0] === l.code;
return (
= ({ isTabl
isSelected && { backgroundColor: currentTheme.colors.primary + '20' },
]}
onPress={() => {
- i18n.changeLanguage(l.code);
+ onChange(l.code);
sheetRef.current?.dismiss();
}}
>
diff --git a/src/screens/settings/PlaybackSettingsScreen.tsx b/src/screens/settings/PlaybackSettingsScreen.tsx
index ed0abd6b..69895300 100644
--- a/src/screens/settings/PlaybackSettingsScreen.tsx
+++ b/src/screens/settings/PlaybackSettingsScreen.tsx
@@ -8,6 +8,7 @@ import { useSettings } from '../../hooks/useSettings';
import { RootStackParamList } from '../../navigation/AppNavigator';
import ScreenHeader from '../../components/common/ScreenHeader';
import { SettingsCard, SettingItem, CustomSwitch, ChevronRight } from './SettingsComponents';
+import { LanguageSettingItem } from './LanguageSettingItem';
import { useRealtimeConfig } from '../../hooks/useRealtimeConfig';
import { MaterialIcons } from '@expo/vector-icons';
import { BottomSheetModal, BottomSheetScrollView, BottomSheetBackdrop } from '@gorhom/bottom-sheet';
@@ -156,31 +157,10 @@ export const PlaybackSettingsContent: React.FC = (
);
- // Bottom sheet refs
- const audioLanguageSheetRef = useRef(null);
- const subtitleLanguageSheetRef = useRef(null);
const subtitleSourceSheetRef = useRef(null);
-
- // Snap points
- const languageSnapPoints = useMemo(() => ['70%'], []);
const sourceSnapPoints = useMemo(() => ['45%'], []);
- // Handlers to present sheets - ensure only one is open at a time
- const openAudioLanguageSheet = useCallback(() => {
- subtitleLanguageSheetRef.current?.dismiss();
- subtitleSourceSheetRef.current?.dismiss();
- setTimeout(() => audioLanguageSheetRef.current?.present(), 100);
- }, []);
-
- const openSubtitleLanguageSheet = useCallback(() => {
- audioLanguageSheetRef.current?.dismiss();
- subtitleSourceSheetRef.current?.dismiss();
- setTimeout(() => subtitleLanguageSheetRef.current?.present(), 100);
- }, []);
-
const openSubtitleSourceSheet = useCallback(() => {
- audioLanguageSheetRef.current?.dismiss();
- subtitleLanguageSheetRef.current?.dismiss();
setTimeout(() => subtitleSourceSheetRef.current?.present(), 100);
}, []);
@@ -195,11 +175,6 @@ export const PlaybackSettingsContent: React.FC = (
return itemIds.some(id => isItemVisible(id));
};
- const getLanguageName = (code: string) => {
- const lang = AVAILABLE_LANGUAGES.find(l => l.code === code);
- return lang ? lang.name : code.toUpperCase();
- };
-
const getSourceLabel = (value: string) => {
if (value === 'internal') return t('settings.options.internal_first');
if (value === 'external') return t('settings.options.external_first');
@@ -220,16 +195,6 @@ export const PlaybackSettingsContent: React.FC = (
[]
);
- const handleSelectAudioLanguage = (code: string) => {
- updateSetting('preferredAudioLanguage', code);
- audioLanguageSheetRef.current?.dismiss();
- };
-
- const handleSelectSubtitleLanguage = (code: string) => {
- updateSetting('preferredSubtitleLanguage', code);
- subtitleLanguageSheetRef.current?.dismiss();
- };
-
const handleSelectSubtitleSource = (value: 'internal' | 'external' | 'any') => {
updateSetting('subtitleSourcePreference', value);
subtitleSourceSheetRef.current?.dismiss();
@@ -322,20 +287,18 @@ export const PlaybackSettingsContent: React.FC = (
{/* Audio & Subtitle Preferences */}
- }
- onPress={openAudioLanguageSheet}
+ value={settings?.preferredAudioLanguage || 'en'}
+ onChange={(code) => updateSetting('preferredAudioLanguage', code)}
+ languages={AVAILABLE_LANGUAGES}
isTablet={isTablet}
/>
- }
- onPress={openSubtitleLanguageSheet}
+ value={settings?.preferredSubtitleLanguage || 'en'}
+ onChange={(code) => updateSetting('preferredSubtitleLanguage', code)}
+ languages={AVAILABLE_LANGUAGES}
isTablet={isTablet}
/>
= (
)}
- {/* Audio Language Bottom Sheet */}
-
-
- {t('settings.items.preferred_audio')}
-
-
- {AVAILABLE_LANGUAGES.map((lang) => {
- const isSelected = lang.code === (settings?.preferredAudioLanguage || 'en');
- return (
- handleSelectAudioLanguage(lang.code)}
- >
-
- {lang.name}
-
-
- {lang.code.toUpperCase()}
-
- {isSelected && (
-
- )}
-
- );
- })}
-
-
-
- {/* Subtitle Language Bottom Sheet */}
-
-
- {t('settings.items.preferred_subtitle')}
-
-
- {AVAILABLE_LANGUAGES.map((lang) => {
- const isSelected = lang.code === (settings?.preferredSubtitleLanguage || 'en');
- return (
- handleSelectSubtitleLanguage(lang.code)}
- >
-
- {lang.name}
-
-
- {lang.code.toUpperCase()}
-
- {isSelected && (
-
- )}
-
- );
- })}
-
-
-
{/* Subtitle Source Priority Bottom Sheet */}