为比赛和球队添加收藏功能,更新状态检查和切换逻辑

This commit is contained in:
yuchenglong
2026-01-16 16:15:45 +08:00
parent 69e7a87de6
commit b5fd763c7e
3 changed files with 240 additions and 25 deletions

View File

@@ -38,6 +38,11 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
const [isFav, setIsFav] = useState(false);
const [favLoading, setFavLoading] = useState(false);
const [isHomeFav, setIsHomeFav] = useState(false);
const [isAwayFav, setIsAwayFav] = useState(false);
const [homeFavLoading, setHomeFavLoading] = useState(false);
const [awayFavLoading, setAwayFavLoading] = useState(false);
// 检查收藏状态
React.useEffect(() => {
const loadFavStatus = async () => {
@@ -51,6 +56,36 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
loadFavStatus();
}, [match.event_key]);
// 检查主队收藏状态
React.useEffect(() => {
const loadHomeFav = async () => {
try {
const res = await checkFavorite("team", match.home_team_key.toString());
setIsHomeFav(res.isFavorite);
} catch (error) {
console.error("Check home team favorite status error:", error);
}
};
if (match.home_team_key) {
loadHomeFav();
}
}, [match.home_team_key]);
// 检查客队收藏状态
React.useEffect(() => {
const loadAwayFav = async () => {
try {
const res = await checkFavorite("team", match.away_team_key.toString());
setIsAwayFav(res.isFavorite);
} catch (error) {
console.error("Check away team favorite status error:", error);
}
};
if (match.away_team_key) {
loadAwayFav();
}
}, [match.away_team_key]);
const toggleFavorite = async () => {
if (favLoading) return;
setFavLoading(true);
@@ -76,6 +111,38 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
setFavLoading(false);
}
};
const toggleTeamFavorite = async (teamKey: number, isHome: boolean) => {
const isTeamFav = isHome ? isHomeFav : isAwayFav;
const setLoading = isHome ? setHomeFavLoading : setAwayFavLoading;
const setFav = isHome ? setIsHomeFav : setIsAwayFav;
const loading = isHome ? homeFavLoading : awayFavLoading;
if (loading) return;
setLoading(true);
const newFavState = !isTeamFav;
try {
if (newFavState) {
await addFavorite({
teamId: teamKey,
type: "team",
typeId: teamKey.toString(),
notify: true,
});
} else {
await removeFavorite({
type: "team",
typeId: teamKey.toString(),
});
}
setFav(newFavState);
} catch (error) {
console.error("Toggle team favorite error:", error);
} finally {
setLoading(false);
}
};
const lastServerMatchRef = React.useRef(
`${match.event_status}-${match.event_time}`
);
@@ -163,11 +230,24 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
{/* Score Section */}
<View style={styles.scoreRow}>
<View style={styles.teamInfo}>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.home_team_logo }}
style={styles.teamLogo}
/>
<View style={styles.teamLogoRow}>
<TouchableOpacity
onPress={() => toggleTeamFavorite(match.home_team_key, true)}
disabled={homeFavLoading}
style={styles.starBtnLeft}
>
<IconSymbol
name={isHomeFav ? "star" : "star-outline"}
size={20}
color={isHomeFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
/>
</TouchableOpacity>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.home_team_logo }}
style={styles.teamLogo}
/>
</View>
</View>
<ThemedText style={styles.teamName} numberOfLines={2}>
{match.event_home_team}
@@ -202,11 +282,24 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
</View>
<View style={styles.teamInfo}>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.away_team_logo }}
style={styles.teamLogo}
/>
<View style={styles.teamLogoRow}>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.away_team_logo }}
style={styles.teamLogo}
/>
</View>
<TouchableOpacity
onPress={() => toggleTeamFavorite(match.away_team_key, false)}
disabled={awayFavLoading}
style={styles.starBtnRight}
>
<IconSymbol
name={isAwayFav ? "star" : "star-outline"}
size={20}
color={isAwayFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
/>
</TouchableOpacity>
</View>
<ThemedText style={styles.teamName} numberOfLines={2}>
{match.event_away_team}
@@ -261,13 +354,26 @@ const styles = StyleSheet.create({
alignItems: "center",
width: "30%",
},
teamLogoRow: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
marginBottom: 10,
},
logoContainer: {
width: 70,
height: 70,
marginBottom: 10,
justifyContent: "center",
alignItems: "center",
},
starBtnLeft: {
padding: 8,
marginRight: -4,
},
starBtnRight: {
padding: 8,
marginLeft: -4,
},
teamLogo: {
width: 60,
height: 60,

View File

@@ -22,14 +22,19 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
const [isFav, setIsFav] = useState(false);
const [favLoading, setFavLoading] = useState(false);
// 检查收藏状态
const [isHomeFav, setIsHomeFav] = useState(false);
const [isAwayFav, setIsAwayFav] = useState(false);
const [homeFavLoading, setHomeFavLoading] = useState(false);
const [awayFavLoading, setAwayFavLoading] = useState(false);
// 检查比赛收藏状态
React.useEffect(() => {
const loadFavStatus = async () => {
try {
const res = await checkFavorite("match", match.eventKey.toString());
setIsFav(res.isFavorite);
} catch (error) {
console.error("Check favorite status error:", error);
console.error("Check match favorite status error:", error);
}
};
if (match.eventKey) {
@@ -37,6 +42,36 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
}
}, [match.eventKey]);
// 检查主队收藏状态
React.useEffect(() => {
const loadHomeFav = async () => {
try {
const res = await checkFavorite("team", match.homeTeamKey.toString());
setIsHomeFav(res.isFavorite);
} catch (error) {
console.error("Check home team favorite status error:", error);
}
};
if (match.homeTeamKey) {
loadHomeFav();
}
}, [match.homeTeamKey]);
// 检查客队收藏状态
React.useEffect(() => {
const loadAwayFav = async () => {
try {
const res = await checkFavorite("team", match.awayTeamKey.toString());
setIsAwayFav(res.isFavorite);
} catch (error) {
console.error("Check away team favorite status error:", error);
}
};
if (match.awayTeamKey) {
loadAwayFav();
}
}, [match.awayTeamKey]);
const toggleFavorite = async () => {
if (favLoading) return;
setFavLoading(true);
@@ -44,7 +79,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
try {
if (newFavState) {
await addFavorite({
matchId: Number(match.eventKey),
matchId: Number(match.eventKey),
type: "match",
typeId: match.eventKey.toString(),
notify: true,
@@ -63,6 +98,38 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
}
};
const toggleTeamFavorite = async (teamKey: string, isHome: boolean) => {
const isTeamFav = isHome ? isHomeFav : isAwayFav;
const setLoading = isHome ? setHomeFavLoading : setAwayFavLoading;
const setFav = isHome ? setIsHomeFav : setIsAwayFav;
const loading = isHome ? homeFavLoading : awayFavLoading;
if (loading) return;
setLoading(true);
const newFavState = !isTeamFav;
try {
if (newFavState) {
await addFavorite({
teamId: Number(teamKey),
type: "team",
typeId: teamKey.toString(),
notify: true,
});
} else {
await removeFavorite({
type: "team",
typeId: teamKey.toString(),
});
}
setFav(newFavState);
} catch (error) {
console.error("Toggle team favorite error:", error);
} finally {
setLoading(false);
}
};
return (
<LinearGradient
colors={["#521e10", "#0e0e10"]}
@@ -108,11 +175,24 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
{/* Score Section */}
<View style={styles.scoreRow}>
<View style={styles.teamInfo}>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.homeTeamLogo }}
style={styles.teamLogo}
/>
<View style={styles.teamLogoRow}>
<TouchableOpacity
onPress={() => toggleTeamFavorite(match.homeTeamKey, true)}
disabled={homeFavLoading}
style={styles.starBtnLeft}
>
<IconSymbol
name={isHomeFav ? "star" : "star-outline"}
size={20}
color={isHomeFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
/>
</TouchableOpacity>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.homeTeamLogo }}
style={styles.teamLogo}
/>
</View>
</View>
<ThemedText style={styles.teamName} numberOfLines={2}>
{match.eventHomeTeam}
@@ -133,11 +213,24 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
</View>
<View style={styles.teamInfo}>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.awayTeamLogo }}
style={styles.teamLogo}
/>
<View style={styles.teamLogoRow}>
<View style={styles.logoContainer}>
<Image
source={{ uri: match.awayTeamLogo }}
style={styles.teamLogo}
/>
</View>
<TouchableOpacity
onPress={() => toggleTeamFavorite(match.awayTeamKey, false)}
disabled={awayFavLoading}
style={styles.starBtnRight}
>
<IconSymbol
name={isAwayFav ? "star" : "star-outline"}
size={20}
color={isAwayFav ? "#FFD700" : "rgba(255,255,255,0.5)"}
/>
</TouchableOpacity>
</View>
<ThemedText style={styles.teamName} numberOfLines={2}>
{match.eventAwayTeam}
@@ -202,13 +295,26 @@ const styles = StyleSheet.create({
flex: 1,
alignItems: "center",
},
teamLogoRow: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
marginBottom: 10,
},
logoContainer: {
width: 70,
height: 70,
marginBottom: 10,
justifyContent: "center",
alignItems: "center",
},
starBtnLeft: {
padding: 8,
marginRight: -4,
},
starBtnRight: {
padding: 8,
marginLeft: -4,
},
teamLogo: {
width: 60,
height: 60,