Files
physical-expo/components/match-card-league.tsx
2026-01-19 14:50:47 +08:00

281 lines
7.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
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;
}
export function MatchCardLeague({
match,
onPress,
onFavoriteToggle,
}: MatchCardLeagueProps) {
const router = useRouter();
const { theme } = useTheme();
const [isFav, setIsFav] = useState(match.fav);
const [loading, setLoading] = useState(false);
React.useEffect(() => {
setIsFav(match.fav);
}, [match.fav]);
const isDark = theme === "dark";
// 截图中的卡片背景通常非常深,接近纯黑
const cardBg = isDark ? "#1C1C1E" : "#FFFFFF";
const textColor = isDark ? "#FFFFFF" : "#000000";
// 赢家的高亮颜色 (截图中的橙黄色)
const winnerColor = "#FF9500";
const loserColor = isDark ? "#FFFFFF" : "#000000";
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);
}
};
// --- 数据解析与样式逻辑 ---
// 假设 match 对象中有 homeScore 和 awayScore (数字或字符串)
// 如果 API 只有 "1 - 0" 这种 scoreText你需要在这里拆分
// 这里为了演示,假设 match 对象已经扩展了这些字段,或者我们从 scoreText 简单解析
let homeScore = 0;
let awayScore = 0;
// 简单的解析逻辑 demo (根据你的实际数据结构调整)
if (match.scoreText && match.scoreText.includes("-")) {
const parts = match.scoreText.split("-");
homeScore = parseInt(parts[0].trim()) || 0;
awayScore = parseInt(parts[1].trim()) || 0;
}
// 如果 match 对象里直接有 match.homeScore 最好:
// homeScore = match.homeScore;
// awayScore = match.awayScore;
// 判断文字颜色和背景样式
let homeColor = loserColor;
let awayColor = loserColor;
let homeScoreBg = "#2C2C2E"; // 默认深灰背景
let awayScoreBg = "#2C2C2E";
let homeBorderColor = "transparent";
let awayBorderColor = "transparent";
if (homeScore > awayScore) {
homeColor = "#000000"; // 赢家黑色文字
homeScoreBg = winnerColor; // 金色背景
homeBorderColor = winnerColor;
} else if (awayScore > homeScore) {
awayColor = "#000000"; // 赢家黑色文字
awayScoreBg = winnerColor; // 金色背景
awayBorderColor = winnerColor;
}
// 如果相等,保持默认深灰背景
return (
<Pressable
onPress={handlePress}
style={({ pressed }) => [
styles.card,
{ backgroundColor: cardBg, opacity: pressed ? 0.8 : 1 },
]}
>
{/* 1. 左侧:时间/状态 */}
<View style={styles.leftColumn}>
{/* 如果有状态字段 match.meta (如 'FT', 'AET'), 优先显示,否则显示时间 */}
<ThemedText style={styles.statusText}>
{(match.meta || match.time || "").toUpperCase()}
</ThemedText>
</View>
{/* 2. 中间:球队信息 (上下排布) */}
<View style={styles.teamsColumn}>
{/* 主队行 */}
<View style={styles.teamRow}>
<Image
source={{ uri: (match as any).homeLogo || match.homeTeamLogo || "https://placehold.co/24x24/png" }}
style={styles.teamLogo}
/>
<ThemedText style={[styles.teamName, { color: textColor }]} numberOfLines={1}>
{match.home || match.homeTeamName}
</ThemedText>
</View>
{/* 客队行 */}
<View style={[styles.teamRow, { marginTop: 6 }]}>
<Image
source={{ uri: (match as any).awayLogo || match.awayTeamLogo || "https://placehold.co/24x24/png" }}
style={styles.teamLogo}
/>
<ThemedText style={[styles.teamName, { color: textColor }]} numberOfLines={1}>
{match.away || match.awayTeamName}
</ThemedText>
</View>
</View>
{/* 3. 右侧:比分与铃铛 */}
<View style={styles.rightWrapper}>
{/* 比分列 (上下排布) */}
<View style={styles.scoresColumn}>
<View style={[
styles.scoreBox,
{
backgroundColor: homeScoreBg,
borderColor: homeBorderColor,
borderWidth: homeBorderColor !== "transparent" ? 1.5 : 0,
}
]}>
<ThemedText style={[styles.scoreText, { color: homeColor }]}>
{homeScore}
</ThemedText>
</View>
<View style={[
styles.scoreBox,
{
backgroundColor: awayScoreBg,
borderColor: awayBorderColor,
borderWidth: awayBorderColor !== "transparent" ? 1.5 : 0,
marginTop: 6,
}
]}>
<ThemedText style={[styles.scoreText, { color: awayColor }]}>
{awayScore}
</ThemedText>
</View>
</View>
{/* 收藏按钮 */}
<TouchableOpacity
onPress={(e) => {
e.stopPropagation();
toggleFavorite();
}}
disabled={loading}
hitSlop={{ top: 10, bottom: 10, left: 10, right: 10 }}
style={styles.favoriteButton}
>
<IconSymbol
name={isFav ? "star" : "star-outline"}
size={20}
color={isFav ? "#FFD700" : "#545458"}
/>
</TouchableOpacity>
</View>
</Pressable>
);
}
const styles = StyleSheet.create({
card: {
flexDirection: "row",
paddingVertical: 14,
paddingHorizontal: 16,
marginHorizontal: 0,
marginBottom: 0,
borderRadius: 12,
alignItems: "center",
minHeight: 68,
},
// 左侧时间列
leftColumn: {
width: 52,
justifyContent: "center",
alignItems: "flex-start",
marginRight: 12,
},
statusText: {
fontSize: 12,
color: "#8E8E93", // 次要文本颜色 (Grey)
fontWeight: "600",
},
// 中间球队列
teamsColumn: {
flex: 1,
justifyContent: "center",
paddingRight: 8,
},
teamRow: {
flexDirection: "row",
alignItems: "center",
},
teamLogo: {
width: 22,
height: 22,
borderRadius: 11, // 圆形图标
marginRight: 10,
backgroundColor: "#3A3A3C", // 图片加载占位
},
teamName: {
fontSize: 16,
fontWeight: "500",
flex: 1,
},
// 右侧整体包装
rightWrapper: {
flexDirection: "row",
alignItems: "center",
},
// 比分列
scoresColumn: {
alignItems: "flex-end", // 数字右对齐
justifyContent: "center",
marginRight: 12,
},
scoreBox: {
minWidth: 32,
height: 28,
borderRadius: 6,
justifyContent: "center",
alignItems: "center",
paddingHorizontal: 8,
},
scoreText: {
fontSize: 16,
fontWeight: "700",
lineHeight: 20,
},
// 收藏按钮
favoriteButton: {
paddingHorizontal: 4,
paddingVertical: 4,
justifyContent: 'center',
alignItems: 'center',
}
});