网球详情页
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { ThemedText } from "@/components/themed-text";
|
||||
import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||
import { addFavorite, checkFavorite, removeFavorite } from "@/lib/api";
|
||||
import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
|
||||
import { storage } from "@/lib/storage";
|
||||
import { MatchDetailData } from "@/types/api";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
@@ -19,6 +20,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
const router = useRouter();
|
||||
const { t } = useTranslation();
|
||||
const { match } = data;
|
||||
const isTennis = match.sportId === 3;
|
||||
|
||||
const [isFav, setIsFav] = useState(false);
|
||||
const [favLoading, setFavLoading] = useState(false);
|
||||
@@ -45,39 +47,45 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
}
|
||||
}, [match.eventKey]);
|
||||
|
||||
// 检查主队收藏状态
|
||||
// 检查主队/第一球员收藏状态
|
||||
React.useEffect(() => {
|
||||
const loadHomeFav = async () => {
|
||||
const token = await storage.getAccessToken();
|
||||
if (!token) return;
|
||||
try {
|
||||
const res = await checkFavorite("team", match.homeTeamKey.toString());
|
||||
setIsHomeFav(res.isFavorite);
|
||||
const teamKey = isTennis ? match.firstPlayerKey : match.homeTeamKey;
|
||||
if (teamKey) {
|
||||
const res = await checkFavorite("team", teamKey.toString());
|
||||
setIsHomeFav(res.isFavorite);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Check home team favorite status error:", error);
|
||||
}
|
||||
};
|
||||
if (match.homeTeamKey) {
|
||||
if (isTennis ? match.firstPlayerKey : match.homeTeamKey) {
|
||||
loadHomeFav();
|
||||
}
|
||||
}, [match.homeTeamKey]);
|
||||
}, [match.homeTeamKey, match.firstPlayerKey, isTennis]);
|
||||
|
||||
// 检查客队收藏状态
|
||||
// 检查客队/第二球员收藏状态
|
||||
React.useEffect(() => {
|
||||
const loadAwayFav = async () => {
|
||||
const token = await storage.getAccessToken();
|
||||
if (!token) return;
|
||||
try {
|
||||
const res = await checkFavorite("team", match.awayTeamKey.toString());
|
||||
setIsAwayFav(res.isFavorite);
|
||||
const teamKey = isTennis ? match.secondPlayerKey : match.awayTeamKey;
|
||||
if (teamKey) {
|
||||
const res = await checkFavorite("team", teamKey.toString());
|
||||
setIsAwayFav(res.isFavorite);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Check away team favorite status error:", error);
|
||||
}
|
||||
};
|
||||
if (match.awayTeamKey) {
|
||||
if (isTennis ? match.secondPlayerKey : match.awayTeamKey) {
|
||||
loadAwayFav();
|
||||
}
|
||||
}, [match.awayTeamKey]);
|
||||
}, [match.awayTeamKey, match.secondPlayerKey, isTennis]);
|
||||
|
||||
const toggleFavorite = async () => {
|
||||
if (favLoading) return;
|
||||
@@ -111,7 +119,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
const setFav = isHome ? setIsHomeFav : setIsAwayFav;
|
||||
const loading = isHome ? homeFavLoading : awayFavLoading;
|
||||
|
||||
if (loading) return;
|
||||
if (loading || !teamKey) return;
|
||||
setLoading(true);
|
||||
|
||||
const newFavState = !isTeamFav;
|
||||
@@ -137,6 +145,36 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
}
|
||||
};
|
||||
|
||||
const getScoreDisplay = () => {
|
||||
if (isTennis) {
|
||||
const scores = (match.scores as any) || [];
|
||||
if (scores.length > 0) {
|
||||
const lastSet = scores[scores.length - 1];
|
||||
return `${lastSet.score_first || "0"}-${lastSet.score_second || "0"}`;
|
||||
}
|
||||
return match.eventGameResult && match.eventGameResult !== "-"
|
||||
? match.eventGameResult
|
||||
: "0-0";
|
||||
}
|
||||
return match.eventFinalResult && match.eventFinalResult !== "-"
|
||||
? match.eventFinalResult
|
||||
: "0-0";
|
||||
};
|
||||
|
||||
const firstPlayerName = isTennis ? match.eventFirstPlayer : match.eventHomeTeam;
|
||||
const secondPlayerName = isTennis ? match.eventSecondPlayer : match.eventAwayTeam;
|
||||
const firstPlayerLogo = isTennis ? match.eventFirstPlayerLogo : match.homeTeamLogo;
|
||||
const secondPlayerLogo = isTennis ? match.eventSecondPlayerLogo : match.awayTeamLogo;
|
||||
const firstPlayerKey = isTennis ? match.firstPlayerKey : match.homeTeamKey;
|
||||
const secondPlayerKey = isTennis ? match.secondPlayerKey : match.awayTeamKey;
|
||||
|
||||
const hasFirstLogo = firstPlayerLogo && firstPlayerLogo.trim() !== "" && !firstPlayerLogo.includes("placehold");
|
||||
const hasSecondLogo = secondPlayerLogo && secondPlayerLogo.trim() !== "" && !secondPlayerLogo.includes("placehold");
|
||||
const firstGradient = getLogoGradient(firstPlayerName || "");
|
||||
const secondGradient = getLogoGradient(secondPlayerName || "");
|
||||
const firstInitials = getInitials(firstPlayerName || "");
|
||||
const secondInitials = getInitials(secondPlayerName || "");
|
||||
|
||||
return (
|
||||
<LinearGradient
|
||||
colors={["#521e10", "#0e0e10"]}
|
||||
@@ -184,8 +222,12 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
<View style={styles.teamInfo}>
|
||||
<View style={styles.teamLogoRow}>
|
||||
<TouchableOpacity
|
||||
onPress={() => toggleTeamFavorite(match.homeTeamKey, true)}
|
||||
disabled={homeFavLoading}
|
||||
onPress={() => {
|
||||
if (firstPlayerKey) {
|
||||
toggleTeamFavorite(firstPlayerKey, true);
|
||||
}
|
||||
}}
|
||||
disabled={homeFavLoading || !firstPlayerKey}
|
||||
style={styles.starBtnLeft}
|
||||
>
|
||||
<IconSymbol
|
||||
@@ -195,41 +237,69 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
<View style={styles.logoContainer}>
|
||||
<Image
|
||||
source={{ uri: match.homeTeamLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
{hasFirstLogo ? (
|
||||
<Image
|
||||
source={{ uri: firstPlayerLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
) : (
|
||||
<LinearGradient
|
||||
colors={[firstGradient.color1, firstGradient.color2]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.teamLogoGradient}
|
||||
>
|
||||
<ThemedText style={styles.teamLogoText}>{firstInitials}</ThemedText>
|
||||
</LinearGradient>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||
{match.eventHomeTeam}
|
||||
{firstPlayerName}
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.centerScore}>
|
||||
<View style={styles.scoreBox}>
|
||||
<ThemedText style={styles.scoreValue}>
|
||||
{match.eventFinalResult && match.eventFinalResult !== "-"
|
||||
? match.eventFinalResult
|
||||
: "0-0"}
|
||||
{getScoreDisplay()}
|
||||
</ThemedText>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.fieldBtn}>
|
||||
<IconSymbol name="football-outline" size={16} color="#FFF" />
|
||||
<IconSymbol
|
||||
name={isTennis ? "tennisball-outline" : "football-outline"}
|
||||
size={16}
|
||||
color="#FFF"
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
<View style={styles.teamInfo}>
|
||||
<View style={styles.teamLogoRow}>
|
||||
<View style={styles.logoContainer}>
|
||||
<Image
|
||||
source={{ uri: match.awayTeamLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
{hasSecondLogo ? (
|
||||
<Image
|
||||
source={{ uri: secondPlayerLogo }}
|
||||
style={styles.teamLogo}
|
||||
/>
|
||||
) : (
|
||||
<LinearGradient
|
||||
colors={[secondGradient.color1, secondGradient.color2]}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 1, y: 1 }}
|
||||
style={styles.teamLogoGradient}
|
||||
>
|
||||
<ThemedText style={styles.teamLogoText}>{secondInitials}</ThemedText>
|
||||
</LinearGradient>
|
||||
)}
|
||||
</View>
|
||||
<TouchableOpacity
|
||||
onPress={() => toggleTeamFavorite(match.awayTeamKey, false)}
|
||||
disabled={awayFavLoading}
|
||||
onPress={() => {
|
||||
if (secondPlayerKey) {
|
||||
toggleTeamFavorite(secondPlayerKey, false);
|
||||
}
|
||||
}}
|
||||
disabled={awayFavLoading || !secondPlayerKey}
|
||||
style={styles.starBtnRight}
|
||||
>
|
||||
<IconSymbol
|
||||
@@ -240,7 +310,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
<ThemedText style={styles.teamName} numberOfLines={2}>
|
||||
{match.eventAwayTeam}
|
||||
{secondPlayerName}
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
@@ -326,6 +396,19 @@ const styles = StyleSheet.create({
|
||||
width: 60,
|
||||
height: 60,
|
||||
resizeMode: "contain",
|
||||
borderRadius: 30,
|
||||
},
|
||||
teamLogoGradient: {
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
},
|
||||
teamLogoText: {
|
||||
fontSize: 20,
|
||||
fontWeight: "700",
|
||||
color: "rgba(255, 255, 255, 0.92)",
|
||||
},
|
||||
teamName: {
|
||||
color: "#FFF",
|
||||
|
||||
Reference in New Issue
Block a user