import React, { useState } from 'react'; import { View, StyleSheet, Dimensions, TouchableOpacity, Text, Modal, FlatList, } from 'react-native'; import { WebView } from 'react-native-webview'; import { Ionicons } from '@expo/vector-icons'; import { buildMpd } from '../utils/buildMpd'; import type { PlayUrlResponse } from '../services/types'; const { width } = Dimensions.get('window'); const VIDEO_HEIGHT = width * 0.5625; interface Props { playData: PlayUrlResponse | null; qualities: { qn: number; desc: string }[]; currentQn: number; onQualityChange: (qn: number) => void; onFullscreen: () => void; onMiniPlayer?: () => void; style?: object; } function buildMp4Html(url: string): string { return ` `; } function buildDashHtml(mpdStr: string): string { const mpdBase64 = `data:application/dash+xml;base64,${btoa(unescape(encodeURIComponent(mpdStr)))}`; return ` `; } function getHtml(playData: PlayUrlResponse | null): string { if (!playData) return ''; if (playData.dash) { const v = playData.dash.video[0]; const a = playData.dash.audio[0]; if (v && a) { const mpd = buildMpd(v.baseUrl, v.codecs, v.bandwidth, a.baseUrl, a.codecs, a.bandwidth); return buildDashHtml(mpd); } } const url = playData.durl?.[0]?.url; if (url) return buildMp4Html(url); return ''; } export function NativeVideoPlayer({ playData, qualities, currentQn, onQualityChange, onFullscreen, onMiniPlayer, style, }: Props) { const [showQuality, setShowQuality] = useState(false); const currentDesc = qualities.find(q => q.qn === currentQn)?.desc ?? (currentQn ? String(currentQn) : 'HD'); const html = getHtml(playData); return ( setShowQuality(true)}> {currentDesc} {onMiniPlayer && ( )} setShowQuality(false)}> 选择清晰度 {qualities.map(q => ( { setShowQuality(false); onQualityChange(q.qn); }} > {q.desc} {q.qn === currentQn && } ))} ); } const styles = StyleSheet.create({ container: { width, height: VIDEO_HEIGHT, backgroundColor: '#000' }, webview: { flex: 1, backgroundColor: '#000' }, controls: { position: 'absolute', bottom: 8, right: 8, flexDirection: 'row', gap: 8, }, ctrlBtn: { backgroundColor: 'rgba(0,0,0,0.55)', borderRadius: 4, paddingHorizontal: 8, paddingVertical: 4, alignItems: 'center', justifyContent: 'center', }, qualityText: { color: '#fff', fontSize: 12, fontWeight: '600' }, modalOverlay: { flex: 1, backgroundColor: 'rgba(0,0,0,0.5)', justifyContent: 'center', alignItems: 'center', }, qualityList: { backgroundColor: '#fff', borderRadius: 12, paddingVertical: 8, paddingHorizontal: 16, minWidth: 180, }, qualityTitle: { fontSize: 15, fontWeight: '700', color: '#212121', paddingVertical: 10, textAlign: 'center' }, qualityItem: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', paddingVertical: 12, borderTopWidth: StyleSheet.hairlineWidth, borderTopColor: '#eee', }, qualityItemText: { fontSize: 14, color: '#333' }, qualityItemActive: { color: '#00AEEC', fontWeight: '700' }, });