添加卡牌设置功能,更新状态管理和界面显示逻辑
This commit is contained in:
@@ -3,8 +3,13 @@ import { IconSymbol } from "@/components/ui/icon-symbol";
|
||||
import { Colors } from "@/constants/theme";
|
||||
import { useAppState } from "@/context/AppStateContext";
|
||||
import { useTheme } from "@/context/ThemeContext";
|
||||
import { addFavorite, fetchOdds, removeFavorite } from "@/lib/api";
|
||||
import { Match, OddsItem } from "@/types/api";
|
||||
import {
|
||||
addFavorite,
|
||||
fetchLiveScore,
|
||||
fetchOdds,
|
||||
removeFavorite,
|
||||
} from "@/lib/api";
|
||||
import { LiveScoreMatch, Match, OddsItem } from "@/types/api";
|
||||
import { Image } from "expo-image";
|
||||
import { LinearGradient } from "expo-linear-gradient";
|
||||
import { useRouter } from "expo-router";
|
||||
@@ -28,9 +33,11 @@ export function MatchCard({
|
||||
const [isFav, setIsFav] = useState(match.fav);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [odds, setOdds] = useState<OddsItem[]>(match.odds || []);
|
||||
const [liveDetail, setLiveDetail] = useState<LiveScoreMatch | null>(null);
|
||||
// console.log("MatchCard render:", JSON.stringify(match));
|
||||
|
||||
const oddsSettings = state.oddsSettings;
|
||||
const cardsSettings = state.cardsSettings;
|
||||
|
||||
useEffect(() => {
|
||||
if (
|
||||
@@ -52,6 +59,20 @@ export function MatchCard({
|
||||
match.odds,
|
||||
]);
|
||||
|
||||
// Fetch live score detail for cards info
|
||||
useEffect(() => {
|
||||
if (cardsSettings.enabled && isLive && match.leagueKey) {
|
||||
fetchLiveScore(match.sportId || 1, Number(match.leagueKey))
|
||||
.then((matches) => {
|
||||
const detail = matches.find((m) => String(m.event_key) === match.id);
|
||||
if (detail) {
|
||||
setLiveDetail(detail);
|
||||
}
|
||||
})
|
||||
.catch((err) => console.log("Fetch live detail for cards error:", err));
|
||||
}
|
||||
}, [cardsSettings.enabled, match.id, match.leagueKey, match.sportId]);
|
||||
|
||||
// 当外部传入的 match.fav 改变时,更新内部状态
|
||||
useEffect(() => {
|
||||
setIsFav(match.fav);
|
||||
@@ -90,10 +111,53 @@ export function MatchCard({
|
||||
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 };
|
||||
if (s === "0 - 0" || s === "0-0")
|
||||
return { home: "0", away: "0", hasScore: true };
|
||||
return { home: "", away: "", hasScore: false };
|
||||
}, [match.scoreText]);
|
||||
|
||||
const cardsCount = React.useMemo(() => {
|
||||
if (!liveDetail?.cards || !cardsSettings.enabled) {
|
||||
return { homeYellow: 0, homeRed: 0, awayYellow: 0, awayRed: 0 };
|
||||
}
|
||||
|
||||
let homeYellow = 0,
|
||||
homeRed = 0,
|
||||
awayYellow = 0,
|
||||
awayRed = 0;
|
||||
|
||||
liveDetail.cards.forEach((card) => {
|
||||
const cardType = (card.card || "").toLowerCase();
|
||||
const isYellow = cardType.includes("yellow");
|
||||
const isRed = cardType.includes("red");
|
||||
if (!isYellow && !isRed) return;
|
||||
|
||||
const info = (card.info || "").toLowerCase();
|
||||
const sideFromInfo = info.includes("home")
|
||||
? "home"
|
||||
: info.includes("away")
|
||||
? "away"
|
||||
: null;
|
||||
const sideFromFault = card.home_fault
|
||||
? "home"
|
||||
: card.away_fault
|
||||
? "away"
|
||||
: null;
|
||||
const side = sideFromInfo || sideFromFault;
|
||||
if (!side) return;
|
||||
|
||||
if (side === "home") {
|
||||
if (isYellow) homeYellow++;
|
||||
if (isRed) homeRed++;
|
||||
} else {
|
||||
if (isYellow) awayYellow++;
|
||||
if (isRed) awayRed++;
|
||||
}
|
||||
});
|
||||
|
||||
return { homeYellow, homeRed, awayYellow, awayRed };
|
||||
}, [liveDetail, cardsSettings.enabled]);
|
||||
|
||||
const handlePress = () => {
|
||||
if (onPress) {
|
||||
onPress(match);
|
||||
@@ -191,6 +255,30 @@ export function MatchCard({
|
||||
);
|
||||
};
|
||||
|
||||
const renderCardsInline = (yellow: number, red: number) => {
|
||||
if (!cardsSettings.enabled || !liveDetail) return null;
|
||||
if (yellow <= 0 && red <= 0) return null;
|
||||
|
||||
return (
|
||||
<View style={styles.cardsInline}>
|
||||
{yellow > 0 && (
|
||||
<View style={[styles.cardBadge, styles.cardBadgeYellow]}>
|
||||
<ThemedText
|
||||
style={[styles.cardBadgeText, styles.cardBadgeTextDark]}
|
||||
>
|
||||
{yellow}
|
||||
</ThemedText>
|
||||
</View>
|
||||
)}
|
||||
{red > 0 && (
|
||||
<View style={[styles.cardBadge, styles.cardBadgeRed]}>
|
||||
<ThemedText style={styles.cardBadgeText}>{red}</ThemedText>
|
||||
</View>
|
||||
)}
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
return (
|
||||
<Pressable
|
||||
onPress={handlePress}
|
||||
@@ -244,6 +332,7 @@ export function MatchCard({
|
||||
>
|
||||
{match.homeTeamName || match.home}
|
||||
</ThemedText>
|
||||
{renderCardsInline(cardsCount.homeYellow, cardsCount.homeRed)}
|
||||
</View>
|
||||
{renderOddsRow(oddsSettings.selectedBookmakers[0], true)}
|
||||
</View>
|
||||
@@ -265,6 +354,7 @@ export function MatchCard({
|
||||
>
|
||||
{match.awayTeamName || match.away}
|
||||
</ThemedText>
|
||||
{renderCardsInline(cardsCount.awayYellow, cardsCount.awayRed)}
|
||||
</View>
|
||||
{renderOddsRow(oddsSettings.selectedBookmakers[1], false)}
|
||||
</View>
|
||||
@@ -368,7 +458,7 @@ const styles = StyleSheet.create({
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
flex: 1,
|
||||
marginRight: 6,
|
||||
minWidth: 0,
|
||||
},
|
||||
teamLogo: {
|
||||
width: 22,
|
||||
@@ -379,6 +469,7 @@ const styles = StyleSheet.create({
|
||||
fontWeight: "600",
|
||||
marginLeft: 6,
|
||||
flex: 1,
|
||||
minWidth: 0,
|
||||
},
|
||||
bookmakerOddsRow: {
|
||||
flexDirection: "row",
|
||||
@@ -427,4 +518,34 @@ const styles = StyleSheet.create({
|
||||
width: 36,
|
||||
height: 54,
|
||||
},
|
||||
cardsInline: {
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 4,
|
||||
marginLeft: 6,
|
||||
flexShrink: 0,
|
||||
},
|
||||
cardBadge: {
|
||||
minWidth: 16,
|
||||
height: 16,
|
||||
borderRadius: 3,
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
paddingHorizontal: 3,
|
||||
},
|
||||
cardBadgeYellow: {
|
||||
backgroundColor: "#FFC400",
|
||||
},
|
||||
cardBadgeRed: {
|
||||
backgroundColor: "#FF3B30",
|
||||
},
|
||||
cardBadgeText: {
|
||||
fontSize: 10,
|
||||
fontWeight: "900",
|
||||
lineHeight: 12,
|
||||
color: "#fff",
|
||||
},
|
||||
cardBadgeTextDark: {
|
||||
color: "#000",
|
||||
},
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user