mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-03-11 17:45:38 +00:00
373 lines
No EOL
9.2 KiB
TypeScript
373 lines
No EOL
9.2 KiB
TypeScript
import React from 'react';
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
ScrollView,
|
|
SafeAreaView,
|
|
Platform,
|
|
TouchableOpacity,
|
|
StatusBar,
|
|
Switch,
|
|
} from 'react-native';
|
|
import { useNavigation } from '@react-navigation/native';
|
|
import { useSettings, AppSettings } from '../hooks/useSettings';
|
|
import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
|
|
import { useTheme } from '../contexts/ThemeContext';
|
|
|
|
const ANDROID_STATUSBAR_HEIGHT = StatusBar.currentHeight || 0;
|
|
|
|
interface SettingItemProps {
|
|
title: string;
|
|
description?: string;
|
|
icon: string;
|
|
isSelected: boolean;
|
|
onPress: () => void;
|
|
isLast?: boolean;
|
|
}
|
|
|
|
const SettingItem: React.FC<SettingItemProps> = ({
|
|
title,
|
|
description,
|
|
icon,
|
|
isSelected,
|
|
onPress,
|
|
isLast,
|
|
}) => {
|
|
const { currentTheme } = useTheme();
|
|
|
|
return (
|
|
<TouchableOpacity
|
|
onPress={onPress}
|
|
activeOpacity={0.7}
|
|
style={[
|
|
styles.settingItem,
|
|
!isLast && styles.settingItemBorder,
|
|
{ borderBottomColor: 'rgba(255,255,255,0.08)' },
|
|
]}
|
|
>
|
|
<View style={styles.settingContent}>
|
|
<View style={[
|
|
styles.settingIconContainer,
|
|
{ backgroundColor: 'rgba(255,255,255,0.1)' }
|
|
]}>
|
|
<MaterialIcons
|
|
name={icon}
|
|
size={20}
|
|
color={currentTheme.colors.primary}
|
|
/>
|
|
</View>
|
|
<View style={styles.settingText}>
|
|
<Text
|
|
style={[
|
|
styles.settingTitle,
|
|
{ color: currentTheme.colors.text },
|
|
]}
|
|
>
|
|
{title}
|
|
</Text>
|
|
{description && (
|
|
<Text
|
|
style={[
|
|
styles.settingDescription,
|
|
{ color: currentTheme.colors.textMuted },
|
|
]}
|
|
>
|
|
{description}
|
|
</Text>
|
|
)}
|
|
</View>
|
|
{isSelected && (
|
|
<MaterialIcons
|
|
name="check"
|
|
size={24}
|
|
color={currentTheme.colors.primary}
|
|
style={styles.checkIcon}
|
|
/>
|
|
)}
|
|
</View>
|
|
</TouchableOpacity>
|
|
);
|
|
};
|
|
|
|
const PlayerSettingsScreen: React.FC = () => {
|
|
const { settings, updateSetting } = useSettings();
|
|
const { currentTheme } = useTheme();
|
|
const navigation = useNavigation();
|
|
|
|
const playerOptions = [
|
|
{
|
|
id: 'internal',
|
|
title: 'Built-in Player',
|
|
description: 'Use the app\'s default video player',
|
|
icon: 'play-circle-outline',
|
|
},
|
|
...(Platform.OS === 'ios' ? [
|
|
{
|
|
id: 'vlc',
|
|
title: 'VLC',
|
|
description: 'Open streams in VLC media player',
|
|
icon: 'video-library',
|
|
},
|
|
{
|
|
id: 'infuse',
|
|
title: 'Infuse',
|
|
description: 'Open streams in Infuse player',
|
|
icon: 'smart-display',
|
|
},
|
|
{
|
|
id: 'outplayer',
|
|
title: 'OutPlayer',
|
|
description: 'Open streams in OutPlayer',
|
|
icon: 'slideshow',
|
|
},
|
|
{
|
|
id: 'vidhub',
|
|
title: 'VidHub',
|
|
description: 'Open streams in VidHub player',
|
|
icon: 'ondemand-video',
|
|
},
|
|
] : [
|
|
{
|
|
id: 'external',
|
|
title: 'External Player',
|
|
description: 'Open streams in your preferred video player',
|
|
icon: 'open-in-new',
|
|
},
|
|
]),
|
|
];
|
|
|
|
const handleBack = () => {
|
|
navigation.goBack();
|
|
};
|
|
|
|
return (
|
|
<SafeAreaView
|
|
style={[
|
|
styles.container,
|
|
{ backgroundColor: currentTheme.colors.darkBackground },
|
|
]}
|
|
>
|
|
<StatusBar
|
|
translucent
|
|
backgroundColor="transparent"
|
|
barStyle="light-content"
|
|
/>
|
|
|
|
<View style={styles.header}>
|
|
<TouchableOpacity
|
|
onPress={handleBack}
|
|
style={styles.backButton}
|
|
activeOpacity={0.7}
|
|
>
|
|
<MaterialIcons
|
|
name="arrow-back"
|
|
size={24}
|
|
color={currentTheme.colors.text}
|
|
/>
|
|
</TouchableOpacity>
|
|
<Text
|
|
style={[
|
|
styles.headerTitle,
|
|
{ color: currentTheme.colors.text },
|
|
]}
|
|
>
|
|
Video Player
|
|
</Text>
|
|
</View>
|
|
|
|
<ScrollView
|
|
style={styles.scrollView}
|
|
contentContainerStyle={styles.scrollContent}
|
|
>
|
|
<View style={styles.section}>
|
|
<Text
|
|
style={[
|
|
styles.sectionTitle,
|
|
{ color: currentTheme.colors.textMuted },
|
|
]}
|
|
>
|
|
PLAYER SELECTION
|
|
</Text>
|
|
<View
|
|
style={[
|
|
styles.card,
|
|
{
|
|
backgroundColor: currentTheme.colors.elevation2,
|
|
},
|
|
]}
|
|
>
|
|
{playerOptions.map((option, index) => (
|
|
<SettingItem
|
|
key={option.id}
|
|
title={option.title}
|
|
description={option.description}
|
|
icon={option.icon}
|
|
isSelected={
|
|
Platform.OS === 'ios'
|
|
? settings.preferredPlayer === option.id
|
|
: settings.useExternalPlayer === (option.id === 'external')
|
|
}
|
|
onPress={() => {
|
|
if (Platform.OS === 'ios') {
|
|
updateSetting('preferredPlayer', option.id as AppSettings['preferredPlayer'], false);
|
|
} else {
|
|
updateSetting('useExternalPlayer', option.id === 'external', false);
|
|
}
|
|
}}
|
|
isLast={index === playerOptions.length - 1}
|
|
/>
|
|
))}
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.section}>
|
|
<Text
|
|
style={[
|
|
styles.sectionTitle,
|
|
{ color: currentTheme.colors.textMuted },
|
|
]}
|
|
>
|
|
PLAYBACK OPTIONS
|
|
</Text>
|
|
<View
|
|
style={[
|
|
styles.card,
|
|
{
|
|
backgroundColor: currentTheme.colors.elevation2,
|
|
},
|
|
]}
|
|
>
|
|
<View style={styles.settingItem}>
|
|
<View style={styles.settingContent}>
|
|
<View style={[
|
|
styles.settingIconContainer,
|
|
{ backgroundColor: 'rgba(255,255,255,0.1)' }
|
|
]}>
|
|
<MaterialIcons
|
|
name="play-arrow"
|
|
size={20}
|
|
color={currentTheme.colors.primary}
|
|
/>
|
|
</View>
|
|
<View style={styles.settingText}>
|
|
<Text
|
|
style={[
|
|
styles.settingTitle,
|
|
{ color: currentTheme.colors.text },
|
|
]}
|
|
>
|
|
Auto-play Best Stream
|
|
</Text>
|
|
<Text
|
|
style={[
|
|
styles.settingDescription,
|
|
{ color: currentTheme.colors.textMuted },
|
|
]}
|
|
>
|
|
Automatically play the highest quality stream when available
|
|
</Text>
|
|
</View>
|
|
<Switch
|
|
value={settings.autoplayBestStream}
|
|
onValueChange={(value) => updateSetting('autoplayBestStream', value)}
|
|
trackColor={{
|
|
false: 'rgba(255,255,255,0.2)',
|
|
true: currentTheme.colors.primary + '40'
|
|
}}
|
|
thumbColor={settings.autoplayBestStream ? currentTheme.colors.primary : 'rgba(255,255,255,0.8)'}
|
|
ios_backgroundColor="rgba(255,255,255,0.2)"
|
|
/>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
);
|
|
};
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
flex: 1,
|
|
},
|
|
header: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingHorizontal: 16,
|
|
paddingTop: Platform.OS === 'android' ? ANDROID_STATUSBAR_HEIGHT + 16 : 16,
|
|
paddingBottom: 8,
|
|
},
|
|
backButton: {
|
|
padding: 8,
|
|
marginRight: 16,
|
|
borderRadius: 20,
|
|
},
|
|
headerTitle: {
|
|
fontSize: 20,
|
|
fontWeight: '600',
|
|
},
|
|
scrollView: {
|
|
flex: 1,
|
|
},
|
|
scrollContent: {
|
|
paddingBottom: 24,
|
|
},
|
|
section: {
|
|
paddingHorizontal: 16,
|
|
paddingTop: 24,
|
|
},
|
|
sectionTitle: {
|
|
fontSize: 13,
|
|
fontWeight: '600',
|
|
marginBottom: 8,
|
|
paddingHorizontal: 4,
|
|
letterSpacing: 0.5,
|
|
},
|
|
card: {
|
|
borderRadius: 12,
|
|
overflow: 'hidden',
|
|
marginBottom: 24,
|
|
shadowColor: 'rgba(0,0,0,0.1)',
|
|
shadowOffset: { width: 0, height: 2 },
|
|
shadowOpacity: 0.5,
|
|
shadowRadius: 4,
|
|
elevation: 3,
|
|
},
|
|
settingItem: {
|
|
paddingVertical: 16,
|
|
paddingHorizontal: 16,
|
|
},
|
|
settingItemBorder: {
|
|
borderBottomWidth: 1,
|
|
},
|
|
settingContent: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
settingIconContainer: {
|
|
width: 36,
|
|
height: 36,
|
|
borderRadius: 10,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
marginRight: 16,
|
|
},
|
|
settingText: {
|
|
flex: 1,
|
|
},
|
|
settingTitle: {
|
|
fontSize: 16,
|
|
fontWeight: '500',
|
|
marginBottom: 2,
|
|
},
|
|
settingDescription: {
|
|
fontSize: 14,
|
|
marginTop: 2,
|
|
},
|
|
checkIcon: {
|
|
marginLeft: 16,
|
|
},
|
|
});
|
|
|
|
export default PlayerSettingsScreen;
|