import React, { useState } from 'react'; import { View, Text, ScrollView, StyleSheet, TouchableOpacity, Image, ActivityIndicator, } from 'react-native'; import { SafeAreaView } from 'react-native-safe-area-context'; import { useLocalSearchParams, useRouter } from 'expo-router'; import { Ionicons } from '@expo/vector-icons'; import { useLiveDetail } from '../../hooks/useLiveDetail'; import { useLiveDanmaku } from '../../hooks/useLiveDanmaku'; import { LivePlayer } from '../../components/LivePlayer'; import DanmakuList from '../../components/DanmakuList'; import { formatCount } from '../../utils/format'; import { proxyImageUrl } from '../../utils/imageUrl'; export default function LiveDetailScreen() { const { roomId } = useLocalSearchParams<{ roomId: string }>(); const router = useRouter(); const id = parseInt(roomId ?? '0', 10); const { room, anchor, stream, loading, error, changeQuality } = useLiveDetail(id); const [danmakuVisible, setDanmakuVisible] = useState(true); const isLive = room?.live_status === 1; const hlsUrl = stream?.hlsUrl ?? ''; const qualities = stream?.qualities ?? []; const currentQn = stream?.qn ?? 0; const danmakus = useLiveDanmaku(isLive ? id : 0); return ( {/* TopBar */} router.back()} style={styles.backBtn}> {room?.title ?? '直播间'} {/* Player */} {/* Content */} {loading ? ( ) : error ? ( {error} ) : room ? ( {/* Room title */} {room.title} {/* Live status */} {isLive ? ( 直播中 ) : ( 未开播 )} {/* Online count */} {formatCount(room.online)} {/* Area tags */} {room.parent_area_name ? ( {room.parent_area_name} ) : null} {room.area_name ? ( {room.area_name} ) : null} {/* Divider */} {/* Anchor row */} {anchor && ( {anchor.uname} + 关注 )} {/* Room description */} {!!room.description && ( {room.description} )} {/* Live danmaku list */} setDanmakuVisible(v => !v)} style={styles.danmakuList} /> ) : null} ); } const styles = StyleSheet.create({ safe: { flex: 1, backgroundColor: '#fff' }, topBar: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8, borderBottomWidth: StyleSheet.hairlineWidth, borderBottomColor: '#eee', }, backBtn: { padding: 4 }, topTitle: { flex: 1, fontSize: 15, fontWeight: '600', marginLeft: 4, color: '#212121', }, loader: { marginVertical: 30 }, errorText: { textAlign: 'center', color: '#f00', padding: 20 }, content: { flex: 1 }, scroll: { flex: 1 }, titleSection: { padding: 14 }, title: { fontSize: 16, fontWeight: '600', color: '#212121', lineHeight: 22, marginBottom: 8, }, metaRow: { flexDirection: 'row', alignItems: 'center', gap: 10, marginBottom: 8 }, livePill: { flexDirection: 'row', alignItems: 'center', backgroundColor: '#fff0f0', paddingHorizontal: 8, paddingVertical: 3, borderRadius: 4, gap: 4, }, offlinePill: { backgroundColor: '#f5f5f5' }, liveDot: { width: 6, height: 6, borderRadius: 3, backgroundColor: '#f00' }, livePillText: { fontSize: 12, color: '#f00', fontWeight: '600' }, offlinePillText: { color: '#999' }, onlineRow: { flexDirection: 'row', alignItems: 'center', gap: 3 }, onlineText: { fontSize: 12, color: '#999' }, areaRow: { flexDirection: 'row', gap: 6 }, areaTag: { fontSize: 11, color: '#00AEEC', backgroundColor: '#e8f7fd', paddingHorizontal: 8, paddingVertical: 2, borderRadius: 10, }, divider: { height: StyleSheet.hairlineWidth, backgroundColor: '#f0f0f0', marginHorizontal: 14, }, anchorRow: { flexDirection: 'row', alignItems: 'center', paddingHorizontal: 14, paddingVertical: 12, }, avatar: { width: 40, height: 40, borderRadius: 20, marginRight: 10 }, anchorName: { flex: 1, fontSize: 14, color: '#212121', fontWeight: '500' }, followBtn: { backgroundColor: '#00AEEC', paddingHorizontal: 14, paddingVertical: 5, borderRadius: 14, }, followTxt: { color: '#fff', fontSize: 12, fontWeight: '600' }, descBox: { padding: 14, paddingTop: 4 }, descText: { fontSize: 14, color: '#555', lineHeight: 22 }, danmakuList: { maxHeight: 220 }, });