2026-03-10 19:04:18 +08:00
|
|
|
import React, { useState } from 'react';
|
|
|
|
|
import { View, StyleSheet, Dimensions, Text, Platform, Modal, TouchableOpacity, StatusBar } from 'react-native';
|
|
|
|
|
import { Ionicons } from '@expo/vector-icons';
|
2026-03-06 14:52:28 +08:00
|
|
|
import { NativeVideoPlayer } from './NativeVideoPlayer';
|
2026-03-10 19:04:18 +08:00
|
|
|
import type { PlayUrlResponse } from '../services/types';
|
2026-03-05 18:02:54 +08:00
|
|
|
|
|
|
|
|
const { width } = Dimensions.get('window');
|
|
|
|
|
const VIDEO_HEIGHT = width * 0.5625;
|
|
|
|
|
|
|
|
|
|
interface Props {
|
2026-03-10 19:04:18 +08:00
|
|
|
playData: PlayUrlResponse | null;
|
|
|
|
|
qualities: { qn: number; desc: string }[];
|
|
|
|
|
currentQn: number;
|
|
|
|
|
onQualityChange: (qn: number) => void;
|
|
|
|
|
onMiniPlayer?: () => void;
|
2026-03-05 18:02:54 +08:00
|
|
|
}
|
|
|
|
|
|
2026-03-10 19:04:18 +08:00
|
|
|
export function VideoPlayer({ playData, qualities, currentQn, onQualityChange, onMiniPlayer }: Props) {
|
|
|
|
|
const [fullscreen, setFullscreen] = useState(false);
|
|
|
|
|
|
|
|
|
|
if (!playData) {
|
2026-03-05 18:02:54 +08:00
|
|
|
return (
|
|
|
|
|
<View style={[styles.container, styles.placeholder]}>
|
|
|
|
|
<Text style={styles.placeholderText}>视频加载中...</Text>
|
|
|
|
|
</View>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-06 12:58:41 +08:00
|
|
|
if (Platform.OS === 'web') {
|
2026-03-10 19:04:18 +08:00
|
|
|
const url = playData.durl?.[0]?.url ?? '';
|
2026-03-06 12:58:41 +08:00
|
|
|
return (
|
|
|
|
|
<View style={styles.container}>
|
|
|
|
|
<video
|
2026-03-10 19:04:18 +08:00
|
|
|
src={url}
|
2026-03-06 12:58:41 +08:00
|
|
|
style={{ width: '100%', height: '100%', backgroundColor: '#000' } as any}
|
|
|
|
|
controls
|
|
|
|
|
playsInline
|
|
|
|
|
/>
|
|
|
|
|
</View>
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-10 19:04:18 +08:00
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<NativeVideoPlayer
|
|
|
|
|
playData={playData}
|
|
|
|
|
qualities={qualities}
|
|
|
|
|
currentQn={currentQn}
|
|
|
|
|
onQualityChange={onQualityChange}
|
|
|
|
|
onFullscreen={() => setFullscreen(true)}
|
|
|
|
|
onMiniPlayer={onMiniPlayer}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
<Modal visible={fullscreen} animationType="fade" statusBarTranslucent>
|
|
|
|
|
<StatusBar hidden />
|
|
|
|
|
<View style={styles.fullscreenContainer}>
|
|
|
|
|
<NativeVideoPlayer
|
|
|
|
|
playData={playData}
|
|
|
|
|
qualities={qualities}
|
|
|
|
|
currentQn={currentQn}
|
|
|
|
|
onQualityChange={onQualityChange}
|
|
|
|
|
onFullscreen={() => setFullscreen(false)}
|
|
|
|
|
style={{ width: '100%', height: '100%' } as any}
|
|
|
|
|
/>
|
|
|
|
|
<TouchableOpacity style={styles.closeBtn} onPress={() => setFullscreen(false)}>
|
|
|
|
|
<Ionicons name="close" size={28} color="#fff" />
|
|
|
|
|
</TouchableOpacity>
|
|
|
|
|
</View>
|
|
|
|
|
</Modal>
|
|
|
|
|
</>
|
|
|
|
|
);
|
2026-03-05 18:02:54 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
|
|
|
|
container: { width, height: VIDEO_HEIGHT, backgroundColor: '#000' },
|
|
|
|
|
placeholder: { justifyContent: 'center', alignItems: 'center' },
|
|
|
|
|
placeholderText: { color: '#fff', fontSize: 14 },
|
2026-03-10 19:04:18 +08:00
|
|
|
fullscreenContainer: { flex: 1, backgroundColor: '#000' },
|
|
|
|
|
closeBtn: {
|
|
|
|
|
position: 'absolute',
|
|
|
|
|
top: 40,
|
|
|
|
|
right: 16,
|
|
|
|
|
padding: 8,
|
|
|
|
|
backgroundColor: 'rgba(0,0,0,0.4)',
|
|
|
|
|
borderRadius: 20,
|
|
|
|
|
},
|
2026-03-05 18:02:54 +08:00
|
|
|
});
|