import { ThemedText } from "@/components/themed-text"; import { IconSymbol } from "@/components/ui/icon-symbol"; import { Colors } from "@/constants/theme"; import { useTheme } from "@/context/ThemeContext"; import { addFavorite, removeFavorite } from "@/lib/api"; import { Match } from "@/types/api"; import { Image } from "expo-image"; import { LinearGradient } from "expo-linear-gradient"; import { useRouter } from "expo-router"; import React, { useState } from "react"; import { Pressable, StyleSheet, TouchableOpacity, View } from "react-native"; interface MatchCardProps { match: Match; onPress?: (match: Match) => void; onFavoriteToggle?: (matchId: string, isFav: boolean) => void; } export function MatchCard({ match, onPress, onFavoriteToggle, }: MatchCardProps) { const router = useRouter(); const { theme } = useTheme(); const [isFav, setIsFav] = useState(match.fav); const [loading, setLoading] = useState(false); // console.log("MatchCard render:", JSON.stringify(match)); // 当外部传入的 match.fav 改变时,更新内部状态 React.useEffect(() => { setIsFav(match.fav); }, [match.fav]); const isDark = theme === "dark"; const iconColor = isDark ? Colors.dark.icon : Colors.light.icon; const cardBg = isDark ? "#1C1C1E" : "#FFFFFF"; const borderColor = isDark ? "#2C2C2E" : "rgba(0,0,0,0.06)"; 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 timeLabel = React.useMemo(() => { const raw = (match.time || "").trim(); if (!raw) return ""; if (/^\d{1,3}$/.test(raw)) return `${raw}'`; return raw; }, [match.time]); const leagueShort = React.useMemo(() => { const league = (match.leagueName || match.league || "").trim(); if (!league) return "--"; const first = league.split(/[^A-Za-z0-9]+/).filter(Boolean)[0] || league; return first.slice(0, 3).toUpperCase(); }, [match.leagueName, match.league]); const scoreParts = React.useMemo(() => { const s = (match.scoreText || "").trim(); const m = s.match(/(\d+)\s*[-:]\s*(\d+)/); if (m) return { home: m[1], away: m[2], hasScore: true }; if (s && s !== "-" && s !== "0 - 0") return { home: s, away: "", hasScore: true }; if (s === "0 - 0") return { home: "0", away: "0", hasScore: true }; return { home: "", away: "", hasScore: false }; }, [match.scoreText]); 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); } }; return ( [ styles.card, { backgroundColor: cardBg, borderColor, opacity: pressed ? 0.7 : 1 }, ]} > {isLive && ( )} {/* Left: League short + time */} {leagueShort} {timeLabel} {/* Middle: Teams */} {match.homeTeamLogo ? ( ) : null} {match.homeTeamName || match.home} {match.awayTeamLogo ? ( ) : null} {match.awayTeamName || match.away} {/* Right: Score box + favorite */} {scoreParts.hasScore ? ( {scoreParts.home} {scoreParts.away} ) : ( )} { e.stopPropagation(); toggleFavorite(); }} disabled={loading} hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }} > ); } const styles = StyleSheet.create({ card: { height: 78, paddingHorizontal: 14, marginBottom: 12, borderRadius: 14, borderWidth: 1, justifyContent: "center", overflow: "hidden", // iOS shadow shadowColor: "#000", shadowOffset: { width: 0, height: 0.5 }, shadowOpacity: 0.03, shadowRadius: 2, // Android elevation elevation: 1, }, row: { flexDirection: "row", alignItems: "center", gap: 12, }, left: { width: 52, alignItems: "center", justifyContent: "center", gap: 6, }, leagueShortText: { fontSize: 12, fontWeight: "700", opacity: 0.85, }, timeText: { fontSize: 12, opacity: 0.55, }, timeTextLive: { color: "#FF3B30", opacity: 1, fontWeight: "bold", }, middle: { flex: 1, justifyContent: "center", gap: 8, minWidth: 0, }, teamRow: { flexDirection: "row", alignItems: "center", gap: 8, }, teamLogo: { width: 24, height: 24, }, teamLine: { fontSize: 15, lineHeight: 18, flex: 1, }, right: { flexDirection: "row", alignItems: "center", gap: 10, }, scoreBox: { width: 44, height: 56, borderRadius: 10, borderWidth: 1, borderColor: "rgba(0,0,0,0.12)", backgroundColor: "rgba(255,255,255,0.6)", alignItems: "center", justifyContent: "center", gap: 6, }, scoreBoxText: { fontSize: 16, fontWeight: "700", opacity: 0.9, }, scoreBoxPlaceholder: { width: 44, height: 56, }, });