import { EmptyPlaceholder } from "@/components/empty-placeholder"; import { ThemedText } from "@/components/themed-text"; import { IconSymbol } from "@/components/ui/icon-symbol"; import { Colors } from "@/constants/theme"; import { useAppState } from "@/context/AppStateContext"; import { useTheme } from "@/context/ThemeContext"; import { addFavorite, removeFavorite } from "@/lib/api"; import { Match } from "@/types/api"; import { useRouter } from "expo-router"; import React, { useState } from "react"; import { Image, Pressable, StyleSheet, TouchableOpacity, View } from "react-native"; interface MatchCardLeagueProps { match: Match; onPress?: (match: Match) => void; onFavoriteToggle?: (matchId: string, isFav: boolean) => void; } const WINNER_BORDER = "#D4A84B"; const WINNER_BG_LIGHT = "#FFF8E7"; const WINNER_BG_DARK = "#3D3422"; const NEUTRAL_BG_LIGHT = "#F5F5F5"; const NEUTRAL_BG_DARK = "#2C2C2E"; const RED_CARD_COLOR = "#C53030"; const YELLOW_CARD_COLOR = "#F59E0B"; export function MatchCardLeague({ match, onPress, onFavoriteToggle, }: MatchCardLeagueProps) { const router = useRouter(); const { theme } = useTheme(); const { state } = useAppState(); const [isFav, setIsFav] = useState(match.fav); const [loading, setLoading] = useState(false); React.useEffect(() => { setIsFav(match.fav); }, [match.fav]); const isTennis = match.sportId === 3; const isDark = theme === "dark"; const textColor = isDark ? Colors.dark.text : Colors.light.text; const secondaryText = isDark ? "#8E8E93" : "#6B7280"; const scoreBorder = isDark ? "rgba(255,255,255,0.18)" : "rgba(0,0,0,0.12)"; const scoreBg = isDark ? "rgba(255,255,255,0.04)" : "rgba(255,255,255,0.6)"; const isLive = React.useMemo(() => { return !!match.isLive; }, [match.isLive]); const handlePress = () => { if (onPress) { onPress(match); } else { router.push(`/match-detail/${match.id}`); } }; const toggleFavorite = async () => { if (loading) return; setLoading(true); const newFavState = !isFav; try { if (newFavState) { await addFavorite({ matchId: parseInt(match.id), type: "match", typeId: match.id, notify: true, }); } else { await removeFavorite({ type: "match", typeId: match.id, }); } setIsFav(newFavState); if (onFavoriteToggle) { onFavoriteToggle(match.id, newFavState); } } catch (error) { console.error("Toggle favorite error:", error); } finally { setLoading(false); } }; const scoreParts = React.useMemo(() => { let s = (match.scoreText || "").trim(); // 对于网球,如果 scoreText 为空或 -,尝试从 scores 字段获取 if (isTennis && (s === "" || s === "-")) { try { const scoresArr = typeof (match as any).scores === 'string' ? JSON.parse((match as any).scores || "[]") : (match as any).scores; if (Array.isArray(scoresArr) && scoresArr.length > 0) { const lastSet = scoresArr[scoresArr.length - 1]; const h = parseInt(lastSet.score_first, 10); const a = parseInt(lastSet.score_second, 10); return { home: lastSet.score_first || "0", away: lastSet.score_second || "0", hasScore: true, homeLead: Number.isFinite(h) && Number.isFinite(a) && h > a, awayLead: Number.isFinite(h) && Number.isFinite(a) && a > h, }; } } catch (e) { } } const m = s.match(/(\d+)\s*[-:]\s*(\d+)/); if (m) { const homeNum = parseInt(m[1], 10); const awayNum = parseInt(m[2], 10); return { home: m[1], away: m[2], hasScore: true, homeLead: Number.isFinite(homeNum) && Number.isFinite(awayNum) && homeNum > awayNum, awayLead: Number.isFinite(homeNum) && Number.isFinite(awayNum) && awayNum > homeNum, }; } if (s && s !== "-" && s !== "0 - 0") return { home: s, away: "", hasScore: true, homeLead: false, awayLead: false }; if (s === "0 - 0") return { home: "0", away: "0", hasScore: true, homeLead: false, awayLead: false }; return { home: "", away: "", hasScore: false, homeLead: false, awayLead: false }; }, [match.scoreText]); const { homeRedCards, awayRedCards, homeYellowCards, awayYellowCards } = React.useMemo(() => { let homeRed = (match as any).homeRedCards || 0; let awayRed = (match as any).awayRedCards || 0; let homeYellow = (match as any).homeYellowCards || 0; let awayYellow = (match as any).awayYellowCards || 0; const matchStats = (match as any).stats; if (matchStats) { try { const stats = typeof matchStats === 'string' ? JSON.parse(matchStats) : matchStats; const redCardsStat = stats.find((s: any) => s.type === "Red Cards"); const yellowCardsStat = stats.find((s: any) => s.type === "Yellow Cards"); if (redCardsStat) { homeRed = parseInt(redCardsStat.home) || 0; awayRed = parseInt(redCardsStat.away) || 0; } if (yellowCardsStat) { homeYellow = parseInt(yellowCardsStat.home) || 0; awayYellow = parseInt(yellowCardsStat.away) || 0; } } catch (e) { console.error("Parse stats error:", e); } } return { homeRedCards: homeRed, awayRedCards: awayRed, homeYellowCards: homeYellow, awayYellowCards: awayYellow }; }, [(match as any).stats, (match as any).homeRedCards, (match as any).awayRedCards]); const cardBg = isDark ? "#1C1C1E" : "#F5F5F5"; const showCards = state.cardsSettings?.enabled !== false; return ( [ styles.card, { backgroundColor: cardBg, opacity: pressed ? 0.7 : 1 }, ]} > {(match.time || "").toUpperCase()} {(() => { const logoUri = isTennis ? (match as any).eventFirstPlayerLogo : ((match as any).homeLogo || match.homeTeamLogo); const hasLogo = logoUri && logoUri.trim() !== "" && !logoUri.includes("placehold"); return hasLogo ? ( ) : ( ); })()} {isTennis ? (match as any).eventFirstPlayer : (match.home || match.homeTeamName)} {!isTennis && showCards && homeYellowCards > 0 && } {!isTennis && showCards && homeRedCards > 0 && } {(() => { const logoUri = isTennis ? (match as any).eventSecondPlayerLogo : ((match as any).awayLogo || match.awayTeamLogo); const hasLogo = logoUri && logoUri.trim() !== "" && !logoUri.includes("placehold"); return hasLogo ? ( ) : ( ); })()} {isTennis ? (match as any).eventSecondPlayer : (match.away || match.awayTeamName)} {!isTennis && showCards && awayYellowCards > 0 && } {!isTennis && showCards && awayRedCards > 0 && } {scoreParts.hasScore ? ( {scoreParts.home} {scoreParts.away} ) : ( )} { e.stopPropagation(); toggleFavorite(); }} disabled={loading} hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }} style={styles.favoriteButton} > ); } const styles = StyleSheet.create({ card: { flexDirection: "row", paddingVertical: 16, paddingHorizontal: 16, alignItems: "center", borderRadius: 12, marginBottom: 8, }, leftColumn: { width: 48, justifyContent: "center", alignItems: "center", marginRight: 8, }, statusText: { fontSize: 14, fontWeight: "600", }, teamsColumn: { flex: 1, justifyContent: "center", paddingRight: 12, }, teamRow: { flexDirection: "row", alignItems: "center", }, teamLogo: { width: 24, height: 24, borderRadius: 14, marginRight: 12, backgroundColor: "#E5E5E5", }, teamLogoGradient: { width: 24, height: 24, borderRadius: 14, marginRight: 12, alignItems: "center", justifyContent: "center", }, teamLogoText: { fontSize: 9, fontWeight: "700", color: "rgba(255, 255, 255, 0.92)", }, teamNameContainer: { flexDirection: "row", alignItems: "center", flex: 1, }, teamName: { fontSize: 13, fontWeight: "500", }, cardBadge: { width: 14, height: 18, borderRadius: 2, marginLeft: 8, }, redCard: { backgroundColor: RED_CARD_COLOR, }, yellowCard: { backgroundColor: YELLOW_CARD_COLOR, }, rightWrapper: { flexDirection: "row", alignItems: "center", gap: 6, }, scoreBox: { width: 45, height: 54, borderRadius: 8, borderWidth: 1.5, alignItems: "center", justifyContent: "center", }, scoreBoxText: { fontSize: 20, fontWeight: "900", }, scoreDivider: { width: "60%", height: 1, marginVertical: 1, }, scoreHalf: { width: "100%", flex: 1, alignItems: "center", justifyContent: "center", borderRadius: 6, }, scoreHalfLead: { backgroundColor: "rgba(255, 149, 0, 0.12)", }, scoreTextLead: { color: "#FF9500", }, scoreBoxPlaceholder: { width: 45, height: 54, }, favoriteButton: { padding: 4, justifyContent: 'center', alignItems: 'center', } });