mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-01-11 20:10:25 +00:00
patch: bottom sheet back button behavior, SettingsScreen.tsx refactor
This commit is contained in:
parent
d31cd2fcdc
commit
6974768457
5 changed files with 97 additions and 186 deletions
|
|
@ -31,6 +31,7 @@ import { TraktService } from '../../services/traktService';
|
|||
import { stremioService } from '../../services/stremioService';
|
||||
import { streamCacheService } from '../../services/streamCacheService';
|
||||
import { useSettings } from '../../hooks/useSettings';
|
||||
import { useBottomSheetBackHandler } from '../../hooks/useBottomSheetBackHandler';
|
||||
|
||||
|
||||
// Define interface for continue watching items
|
||||
|
|
@ -122,6 +123,7 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
|
||||
// Bottom sheet for item actions
|
||||
const actionSheetRef = useRef<BottomSheetModal>(null);
|
||||
const { onChange, onDismiss } = useBottomSheetBackHandler();
|
||||
const [selectedItem, setSelectedItem] = useState<ContinueWatchingItem | null>(null);
|
||||
|
||||
// Enhanced responsive sizing for tablets and TV screens
|
||||
|
|
@ -1620,7 +1622,9 @@ const ContinueWatchingSection = React.forwardRef<ContinueWatchingRef>((props, re
|
|||
}}
|
||||
onDismiss={() => {
|
||||
setSelectedItem(null);
|
||||
onDismiss(actionSheetRef);
|
||||
}}
|
||||
onChange={onChange(actionSheetRef)}
|
||||
>
|
||||
<BottomSheetView style={[styles.actionSheetContent, { paddingBottom: insets.bottom + 16 }]}>
|
||||
{selectedItem && (
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
import React, { useMemo, useCallback, forwardRef, RefObject } from 'react';
|
||||
import React, { useMemo, useCallback, forwardRef, RefObject, useState } from 'react';
|
||||
import { View, Text, TouchableOpacity } from 'react-native';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { MaterialIcons } from '@expo/vector-icons';
|
||||
import { BottomSheetModal, BottomSheetScrollView, BottomSheetBackdrop } from '@gorhom/bottom-sheet';
|
||||
import { DiscoverCatalog } from './searchUtils';
|
||||
import { searchStyles as styles } from './searchStyles';
|
||||
import { useBottomSheetBackHandler } from '../../hooks/useBottomSheetBackHandler';
|
||||
|
||||
interface DiscoverBottomSheetsProps {
|
||||
typeSheetRef: RefObject<BottomSheetModal>;
|
||||
|
|
@ -40,6 +41,8 @@ export const DiscoverBottomSheets = ({
|
|||
const typeSnapPoints = useMemo(() => ['25%'], []);
|
||||
const catalogSnapPoints = useMemo(() => ['50%'], []);
|
||||
const genreSnapPoints = useMemo(() => ['50%'], []);
|
||||
const [activeBottomSheetRef, setActiveBottomSheetRef] = useState(null);
|
||||
const {onDismiss, onChange} = useBottomSheetBackHandler();
|
||||
|
||||
const renderBackdrop = useCallback(
|
||||
(props: any) => (
|
||||
|
|
@ -71,6 +74,8 @@ export const DiscoverBottomSheets = ({
|
|||
handleIndicatorStyle={{
|
||||
backgroundColor: currentTheme.colors.mediumGray,
|
||||
}}
|
||||
onDismiss={onDismiss(catalogSheetRef)}
|
||||
onChange={onChange(catalogSheetRef)}
|
||||
>
|
||||
<View style={[styles.bottomSheetHeader, { backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }]}>
|
||||
<Text style={[styles.bottomSheetTitle, { color: currentTheme.colors.white }]}>
|
||||
|
|
@ -130,6 +135,8 @@ export const DiscoverBottomSheets = ({
|
|||
handleIndicatorStyle={{
|
||||
backgroundColor: currentTheme.colors.mediumGray,
|
||||
}}
|
||||
onDismiss={onDismiss(genreSheetRef)}
|
||||
onChange={onChange(genreSheetRef)}
|
||||
>
|
||||
<View style={[styles.bottomSheetHeader, { backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }]}>
|
||||
<Text style={[styles.bottomSheetTitle, { color: currentTheme.colors.white }]}>
|
||||
|
|
@ -203,6 +210,8 @@ export const DiscoverBottomSheets = ({
|
|||
handleIndicatorStyle={{
|
||||
backgroundColor: currentTheme.colors.mediumGray,
|
||||
}}
|
||||
onDismiss={onDismiss(typeSheetRef)}
|
||||
onChange={onChange(typeSheetRef)}
|
||||
>
|
||||
<View style={[styles.bottomSheetHeader, { backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }]}>
|
||||
<Text style={[styles.bottomSheetTitle, { color: currentTheme.colors.white }]}>
|
||||
|
|
|
|||
9
src/constants/locales.ts
Normal file
9
src/constants/locales.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export const LOCALES = [
|
||||
{ code: 'en', key: 'english' },
|
||||
{ code: 'pt-BR', key: 'portuguese_br' },
|
||||
{ code: 'pt-PT', key: 'portuguese_pt' },
|
||||
{ code: 'de', key: 'german' },
|
||||
{ code: 'ar', key: 'arabic' },
|
||||
{ code: 'fr', key: 'french' },
|
||||
{ code: 'it', key: 'italian' }
|
||||
];
|
||||
41
src/hooks/useBottomSheetBackHandler.ts
Normal file
41
src/hooks/useBottomSheetBackHandler.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
import { useEffect, useRef } from 'react';
|
||||
|
||||
import { BackHandler } from 'react-native';
|
||||
import { BottomSheetModal } from '@gorhom/bottom-sheet';
|
||||
|
||||
export function useBottomSheetBackHandler() {
|
||||
const activeSheetRef =
|
||||
useRef<React.RefObject<BottomSheetModal> | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const sub = BackHandler.addEventListener(
|
||||
'hardwareBackPress',
|
||||
() => {
|
||||
if (activeSheetRef.current?.current) {
|
||||
activeSheetRef.current.current.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
return () => sub.remove();
|
||||
}, []);
|
||||
|
||||
const onChange =
|
||||
(ref: React.RefObject<BottomSheetModal>) =>
|
||||
(index: number) => {
|
||||
if (index >= 0) {
|
||||
activeSheetRef.current = ref;
|
||||
}
|
||||
};
|
||||
|
||||
const onDismiss =
|
||||
(ref: React.RefObject<BottomSheetModal>) => () => {
|
||||
if (activeSheetRef.current === ref) {
|
||||
activeSheetRef.current = null;
|
||||
}
|
||||
};
|
||||
|
||||
return { onChange, onDismiss };
|
||||
}
|
||||
|
|
@ -45,6 +45,8 @@ import { AppearanceSettingsContent } from './settings/AppearanceSettingsScreen';
|
|||
import { IntegrationsSettingsContent } from './settings/IntegrationsSettingsScreen';
|
||||
import { AboutSettingsContent, AboutFooter } from './settings/AboutSettingsScreen';
|
||||
import { SettingsCard, SettingItem, ChevronRight, CustomSwitch } from './settings/SettingsComponents';
|
||||
import { useBottomSheetBackHandler } from '../hooks/useBottomSheetBackHandler';
|
||||
import { LOCALES } from '../constants/locales';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
const isTablet = width >= 768;
|
||||
|
|
@ -151,6 +153,7 @@ const SettingsScreen: React.FC = () => {
|
|||
const { settings, updateSetting } = useSettings();
|
||||
const [hasUpdateBadge, setHasUpdateBadge] = useState(false);
|
||||
const languageSheetRef = useRef<BottomSheetModal>(null);
|
||||
const { onChange, onDismiss } = useBottomSheetBackHandler();
|
||||
const insets = useSafeAreaInsets();
|
||||
|
||||
// Render backdrop for bottom sheet
|
||||
|
|
@ -626,15 +629,7 @@ const SettingsScreen: React.FC = () => {
|
|||
<SettingsCard title="GENERAL">
|
||||
<SettingItem
|
||||
title={t('settings.language')}
|
||||
description={
|
||||
i18n.language === 'pt-BR' ? t('settings.portuguese_br') :
|
||||
i18n.language === 'pt-PT' ? t('settings.portuguese_pt') :
|
||||
i18n.language === 'de' ? t('settings.german') :
|
||||
i18n.language === 'ar' ? t('settings.arabic') :
|
||||
i18n.language === 'es' ? t('settings.spanish') :
|
||||
i18n.language === 'fr' ? t('settings.french') :
|
||||
i18n.language === 'it' ? t('settings.italian') :
|
||||
t('settings.english')
|
||||
description={t(`settings.${LOCALES.find(l => l.code === i18n.language)?.key}`)
|
||||
}
|
||||
icon="globe"
|
||||
renderControl={() => <ChevronRight />}
|
||||
|
|
@ -870,12 +865,14 @@ const SettingsScreen: React.FC = () => {
|
|||
backgroundColor: currentTheme.colors.mediumGray,
|
||||
width: 40,
|
||||
}}
|
||||
onChange={onChange(languageSheetRef)}
|
||||
onDismiss={onDismiss(languageSheetRef)}
|
||||
>
|
||||
<View style={[styles.bottomSheetHeader, { backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }]}>
|
||||
<Text style={[styles.bottomSheetTitle, { color: currentTheme.colors.white }]}>
|
||||
{t('settings.select_language')}
|
||||
</Text>
|
||||
<TouchableOpacity onPress={() => languageSheetRef.current?.close()}>
|
||||
<TouchableOpacity onPress={() => languageSheetRef.current?.dismiss()}>
|
||||
<Feather name="x" size={24} color={currentTheme.colors.lightGray} />
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
|
@ -883,181 +880,32 @@ const SettingsScreen: React.FC = () => {
|
|||
style={{ backgroundColor: currentTheme.colors.darkGray || '#0A0C0C' }}
|
||||
contentContainerStyle={[styles.bottomSheetContent, { paddingBottom: insets.bottom + 16 }]}
|
||||
>
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'en' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('en');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'en' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.english')}
|
||||
</Text>
|
||||
{i18n.language === 'en' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'pt-BR' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('pt-BR');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'pt-BR' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.portuguese_br')}
|
||||
</Text>
|
||||
{i18n.language === 'pt-BR' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'pt-PT' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('pt-PT');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'pt-PT' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.portuguese_pt')}
|
||||
</Text>
|
||||
{i18n.language === 'pt-PT' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'de' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('de');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'de' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.german')}
|
||||
</Text>
|
||||
{i18n.language === 'de' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'ar' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('ar');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'ar' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.arabic')}
|
||||
</Text>
|
||||
{i18n.language === 'ar' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'es' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('es');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'es' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.spanish')}
|
||||
</Text>
|
||||
{i18n.language === 'es' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'fr' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('fr');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'fr' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.french')}
|
||||
</Text>
|
||||
{i18n.language === 'fr' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
|
||||
<TouchableOpacity
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === 'it' && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage('it');
|
||||
languageSheetRef.current?.close();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === 'it' && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t('settings.italian')}
|
||||
</Text>
|
||||
{i18n.language === 'it' && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
{
|
||||
LOCALES.sort((a,b) => a.key.localeCompare(b.key)).map(l =>
|
||||
<TouchableOpacity
|
||||
key={l.key}
|
||||
style={[
|
||||
styles.languageOption,
|
||||
i18n.language === l.code && { backgroundColor: currentTheme.colors.primary + '20' }
|
||||
]}
|
||||
onPress={() => {
|
||||
i18n.changeLanguage(l.code);
|
||||
languageSheetRef.current?.dismiss();
|
||||
}}
|
||||
>
|
||||
<Text style={[
|
||||
styles.languageText,
|
||||
{ color: currentTheme.colors.highEmphasis },
|
||||
i18n.language === l.code && { color: currentTheme.colors.primary, fontWeight: 'bold' }
|
||||
]}>
|
||||
{t(`settings.${l.key}`)}
|
||||
</Text>
|
||||
{i18n.language === l.code && (
|
||||
<Feather name="check" size={20} color={currentTheme.colors.primary} />
|
||||
)}
|
||||
</TouchableOpacity>
|
||||
)
|
||||
}
|
||||
</BottomSheetScrollView>
|
||||
</BottomSheetModal>
|
||||
</View>
|
||||
|
|
|
|||
Loading…
Reference in a new issue