diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index b948451..f4080fd 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -1,6 +1,7 @@ import { HomeHeader } from "@/components/home-header"; import { LeagueModal } from "@/components/league-modal"; import { MatchCard } from "@/components/match-card"; +import { MatchCardLeague } from "@/components/match-card-league"; import { SelectionModal } from "@/components/selection-modal"; import { CalendarModal } from "@/components/simple-calendar"; import { ThemedText } from "@/components/themed-text"; @@ -495,9 +496,13 @@ export default function HomeScreen() { item.id} - renderItem={({ item }) => ( - - )} + renderItem={({ item }) => + filterMode === "time" ? ( + + ) : ( + + ) + } contentContainerStyle={styles.listContent} ListEmptyComponent={ diff --git a/components/match-card-league.tsx b/components/match-card-league.tsx new file mode 100644 index 0000000..d655d79 --- /dev/null +++ b/components/match-card-league.tsx @@ -0,0 +1,179 @@ +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 { useRouter } from "expo-router"; +import React, { useState } from "react"; +import { 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); + + // 当外部传入的 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 ? "#38383A" : "#E5E5EA"; + + 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 }, + ]} + > + + + + {match.league} + + + {match.time} + + + + + {match.home} vs2 {match.away} + + + + {match.scoreText} + + { + e.stopPropagation(); + toggleFavorite(); + }} + disabled={loading} + hitSlop={{ top: 12, bottom: 12, left: 12, right: 12 }} + > + + + + + + {match.meta && ( + {match.meta} + )} + + ); +} + +const styles = StyleSheet.create({ + card: { + padding: 12, + marginBottom: 12, + borderRadius: 12, + borderWidth: 1, + }, + header: { + flexDirection: "row", + alignItems: "center", + marginBottom: 8, + }, + leagueBadge: { + paddingHorizontal: 8, + paddingVertical: 4, + borderRadius: 4, + marginRight: 8, + maxWidth: "70%", + }, + leagueText: { + fontSize: 12, + opacity: 0.7, + }, + timeText: { + fontSize: 12, + opacity: 0.5, + }, + teamsContainer: { + flexDirection: "row", + justifyContent: "space-between", + alignItems: "center", + marginBottom: 4, + }, + teamsText: { + fontSize: 16, + flex: 1, + marginRight: 8, + }, + scoreContainer: { + flexDirection: "row", + alignItems: "center", + gap: 12, + }, + scoreText: { + fontSize: 16, + }, + metaText: { + fontSize: 12, + opacity: 0.5, + marginTop: 4, + }, +});