import { ThemedText } from "@/components/themed-text"; import { ThemedView } from "@/components/themed-view"; import { IconSymbol } from "@/components/ui/icon-symbol"; import { LiveScoreMatch } from "@/types/api"; import { LinearGradient } from "expo-linear-gradient"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { Image, LayoutChangeEvent, Modal, Pressable, StyleSheet, Switch, TouchableOpacity, View, } from "react-native"; import Svg, { Defs, Path, Stop, LinearGradient as SvgLinearGradient, } from "react-native-svg"; interface StatsCardProps { match: LiveScoreMatch; isDark: boolean; } export function StatsCard({ match, isDark }: StatsCardProps) { const { t } = useTranslation(); const [flagSwitch, setFlagSwitch] = useState(true); const [cardSwitch, setCardSwitch] = useState(true); const [showInfo, setShowInfo] = useState(false); const [chartWidth, setChartWidth] = useState(0); const onChartLayout = (event: LayoutChangeEvent) => { setChartWidth(event.nativeEvent.layout.width); }; // 实时时间与进度计算 const getInitialMinutes = () => { const statusIdx = parseInt(match.event_status) || 0; const timeParts = match.event_time?.split(":") || []; const tMin = parseInt(timeParts[0]) || 0; const tSec = parseInt(timeParts[1]) || 0; if (!isNaN(statusIdx) && /^\d+$/.test(match.event_status)) { return { min: Math.max(0, statusIdx - tMin), sec: tSec }; } return { min: tMin, sec: tSec }; }; const initial = getInitialMinutes(); const [minutes, setMinutes] = useState(initial.min); const [seconds, setSeconds] = useState(initial.sec); React.useEffect(() => { const updated = getInitialMinutes(); setMinutes(updated.min); setSeconds(updated.sec); }, [match.event_time, match.event_status]); React.useEffect(() => { const statusStr = match.event_status?.toLowerCase() || ""; const isLive = String(match.event_live) === "1" || statusStr.includes("live") || (parseInt(statusStr) > 0 && parseInt(statusStr) < 120); if (!isLive || statusStr.includes("ht")) return; const interval = setInterval(() => { setSeconds((s) => { if (s >= 59) { setMinutes((m) => m + 1); return 0; } return s + 1; }); }, 1000); return () => clearInterval(interval); }, [match.event_key, match.event_live, match.event_status]); const displayTime = `${minutes}:${seconds.toString().padStart(2, "0")}`; const totalSeconds = minutes * 60 + seconds; const progressPercent = Math.min(100, (totalSeconds / (90 * 60)) * 100); // 从 statistics 中提取数据 const stats = (match.statistics || []) as any[]; const getStatValue = (type: string) => { const stat = stats.find((s) => s.type === type); if (stat && stat.home) { return { home: stat.home, away: stat.away }; } return { home: "0", away: "0" }; }; const possession = getStatValue("Ball Possession"); const corners = getStatValue("Corners"); const yellowCards = getStatValue("Yellow Cards"); // 解析控球率数值 (例如 "53%" -> 53) const homePossession = parseInt(possession.home.toString().replace("%", "")) || 50; const awayPossession = parseInt(possession.away.toString().replace("%", "")) || 50; // 用随机数据模拟压力曲线 const generateData = React.useMemo(() => { const data = []; let h = 10; let a = 10; for (let i = 0; i < 90; i++) { h = Math.max(0, Math.min(40, h + (Math.random() - 0.5) * 10)); a = Math.max(0, Math.min(40, a + (Math.random() - 0.5) * 10)); data.push({ time: i, home: h, away: a, }); } return data; }, [match.event_key]); const getWavePath = ( data: any[], type: "home" | "away", width: number, height: number, ) => { if (width === 0) return ""; const baseY = height / 2; const points = data.map((d, i) => { const x = (i / 89) * width; const val = type === "home" ? d.home : d.away; const y = type === "home" ? baseY - (val / 50) * baseY : baseY + (val / 50) * baseY; return { x, y }; }); // 创建平滑曲线 (使用简单指令) let d = `M 0 ${baseY}`; points.forEach((p) => { d += ` L ${p.x} ${p.y}`; }); d += ` L ${width} ${baseY} Z`; return d; }; const chartData = generateData; const iconTintColor = isDark ? "#888" : "#CCC"; const switchBg = isDark ? "#2C2C2E" : "#F0F0F0"; return ( {/* Header */} {t("detail.stats_card.title")} setShowInfo(true)}> {/* Momentum Chart Area */} {/* 背景色带 */} {/* 网格线和时间刻度 */} {["0'", "15'", "30'", "HT", "60'", "75'", "90'"].map((label, i) => ( {label} ))} {/* 压力曲线模拟 (Wave Chart) */} {chartWidth > 0 && ( {/* Home Wave */} {/* Away Wave */} )} {/* 动态标记:红黄牌 */} {chartWidth > 0 && cardSwitch && match.cards?.map((card, idx) => { const time = parseInt(card.time) || 0; const left = (time / 90) * chartWidth; const isHome = card.home_fault !== ""; const isYellow = (card.card || "") .toLowerCase() .includes("yellow"); return ( ); })} {/* 动态标记:进球 */} {chartWidth > 0 && flagSwitch && match.goalscorers?.map((goal, idx) => { const time = parseInt(goal.time) || 0; const left = (time / 90) * chartWidth; const isHome = !!goal.home_scorer; return ( ); })} {/* Time Progress Slider */} {displayTime} 0:00 HT FT {/* Possession & Stats Bar */} {t("detail.stats_card.possession")} {homePossession}% {awayPossession}% {corners.home} {corners.away} {yellowCards.home} {yellowCards.away} {/* Momentum Info Modal */} setShowInfo(false)} > setShowInfo(false)} > {t("detail.stats_card.info_title")} {t("detail.stats_card.info_desc")} • {t("detail.stats_card.point1")} • {t("detail.stats_card.point2")} • {t("detail.stats_card.point3")} {[...Array(6)].map((_, i) => ( ))} {match.event_home_team} {[...Array(6)].map((_, i) => ( ))} {match.event_away_team} setShowInfo(false)} > {t("detail.stats_card.close")} ); } const styles = StyleSheet.create({ container: { margin: 16, borderRadius: 20, padding: 16, backgroundColor: "#FFF", marginBottom: 20, shadowColor: "#000", shadowOpacity: 0.05, shadowRadius: 10, elevation: 2, }, darkContainer: { backgroundColor: "#1E1E20", }, header: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", marginBottom: 24, }, headerLeft: { flexDirection: "row", alignItems: "center", gap: 8, }, title: { fontSize: 18, fontWeight: "500", color: "#666", }, switches: { flexDirection: "row", gap: 12, }, switchWrapper: { flexDirection: "row", alignItems: "center", backgroundColor: "#F0F0F0", borderRadius: 15, paddingLeft: 8, paddingRight: 2, height: 30, }, smallSwitch: { transform: [{ scaleX: 0.6 }, { scaleY: 0.6 }], }, miniCard: { width: 10, height: 14, borderRadius: 2, }, chartWrapper: { flexDirection: "row", height: 140, marginBottom: 10, }, teamLogos: { width: 40, justifyContent: "center", alignItems: "center", paddingBottom: 20, }, chartLogo: { width: 24, height: 24, borderRadius: 12, }, chartArea: { flex: 1, position: "relative", marginLeft: 8, }, bgGradient: { position: "absolute", top: 0, left: 0, right: 0, bottom: 30, borderRadius: 4, }, gridContainer: { position: "absolute", top: 0, left: 0, right: 0, bottom: 0, flexDirection: "row", justifyContent: "space-between", }, gridLine: { height: "100%", alignItems: "center", }, line: { width: 1, height: "100%", backgroundColor: "#F0F0F0", marginBottom: 4, }, gridLabel: { fontSize: 12, color: "#000", fontWeight: "500", }, waveContainer: { position: "absolute", top: 0, left: 0, right: 0, bottom: 30, }, waveBar: { position: "absolute", width: 1.5, }, eventMarker: { position: "absolute", alignItems: "center", }, square: { width: 12, height: 16, borderRadius: 2, }, goalBox: { flexDirection: "row", alignItems: "center", gap: 2, backgroundColor: "#FFF", padding: 2, borderRadius: 4, borderWidth: 1, borderColor: "#E0E0E0", }, sliderContainer: { marginTop: 20, paddingHorizontal: 10, }, currentTime: { fontSize: 14, color: "#4CAF50", fontWeight: "700", textAlign: "center", marginBottom: 4, marginLeft: "10%", // Offset roughly }, trackContainer: { height: 20, justifyContent: "center", position: "relative", }, track: { height: 3, backgroundColor: "#EEE", borderRadius: 2, }, filledTrack: { position: "absolute", height: 3, backgroundColor: "#3b5998", borderRadius: 2, }, thumb: { position: "absolute", width: 10, height: 10, borderRadius: 5, backgroundColor: "#3b5998", borderWidth: 2, borderColor: "#FFF", marginLeft: -5, }, trackLabels: { flexDirection: "row", justifyContent: "space-between", marginTop: 8, }, trackLabel: { fontSize: 12, color: "#666", fontWeight: "500", }, possessionSection: { marginTop: 24, alignItems: "center", }, possessionTitle: { fontSize: 16, color: "#666", marginBottom: 12, }, possessionBarRow: { flexDirection: "row", height: 36, width: "100%", paddingHorizontal: 4, }, posBar: { flexDirection: "row", alignItems: "center", paddingHorizontal: 12, gap: 8, }, posLogo: { width: 20, height: 20, borderRadius: 10, backgroundColor: "#FFF", }, posValue: { color: "#FFF", fontSize: 14, fontWeight: "700", }, miniStatsRow: { flexDirection: "row", justifyContent: "center", gap: 12, marginTop: 16, }, miniStatBadge: { flexDirection: "row", alignItems: "center", backgroundColor: "#F5F5F5", paddingHorizontal: 16, paddingVertical: 6, borderRadius: 20, gap: 8, minWidth: 80, justifyContent: "center", }, darkStatBadge: { backgroundColor: "#2C2C2E", }, miniStatText: { fontSize: 14, fontWeight: "600", }, yellowCardIcon: { width: 10, height: 14, backgroundColor: "#FFD700", borderRadius: 2, }, modalOverlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.5)", justifyContent: "center", alignItems: "center", padding: 20, }, modalContent: { width: "100%", backgroundColor: "#FFF", borderRadius: 24, padding: 24, shadowColor: "#000", shadowOpacity: 0.1, shadowRadius: 20, elevation: 10, }, darkModalContent: { backgroundColor: "#1E1E20", }, modalTitle: { fontSize: 20, fontWeight: "700", marginBottom: 16, }, modalDesc: { fontSize: 15, lineHeight: 22, marginBottom: 16, }, bulletPoint: { marginBottom: 8, }, bulletText: { fontSize: 15, lineHeight: 22, }, teamInfoRow: { flexDirection: "row", alignItems: "center", marginTop: 16, gap: 12, }, miniLogo: { width: 24, height: 24, borderRadius: 12, }, wavePlaceholder: { flexDirection: "row", alignItems: "center", width: 40, height: 20, gap: 2, }, waveDot: { width: 4, height: 4, borderRadius: 2, }, teamDesc: { flex: 1, fontSize: 14, color: "#666", }, closeButton: { backgroundColor: "#4B77FF", borderRadius: 12, paddingVertical: 12, alignItems: "center", marginTop: 24, alignSelf: "flex-end", paddingHorizontal: 24, }, closeButtonText: { color: "#FFF", fontSize: 16, fontWeight: "600", }, });