添加角球设置功能,更新状态管理和界面显示逻辑

This commit is contained in:
yuchenglong
2026-01-20 13:56:58 +08:00
parent fa13b3c17d
commit bb3cb3b821
6 changed files with 151 additions and 5 deletions

View File

@@ -37,7 +37,12 @@ const BOOKMAKERS = [
export default function ProfileScreen() { export default function ProfileScreen() {
const { theme, toggleTheme, setTheme, isSystemTheme, useSystemTheme } = const { theme, toggleTheme, setTheme, isSystemTheme, useSystemTheme } =
useTheme(); useTheme();
const { state, updateOddsSettings, updateCardsSettings } = useAppState(); const {
state,
updateOddsSettings,
updateCardsSettings,
updateCornerSettings,
} = useAppState();
const { t, i18n } = useTranslation(); const { t, i18n } = useTranslation();
const router = useRouter(); const router = useRouter();
const isDark = theme === "dark"; const isDark = theme === "dark";
@@ -62,6 +67,13 @@ export default function ProfileScreen() {
}); });
}; };
const toggleCorners = () => {
updateCornerSettings({
...state.cornerSettings,
enabled: !state.cornerSettings.enabled,
});
};
const selectBookmaker = (name: string) => { const selectBookmaker = (name: string) => {
const current = state.oddsSettings.selectedBookmakers; const current = state.oddsSettings.selectedBookmakers;
let next: string[]; let next: string[];
@@ -468,6 +480,38 @@ export default function ProfileScreen() {
</View> </View>
</View> </View>
<ThemedText style={styles.sectionTitle}>
{t("settings.corner_title")}
</ThemedText>
<View
style={[
styles.section,
{ backgroundColor: isDark ? "#1c1c1e" : "#fff" },
]}
>
<View style={styles.settingItem}>
<View style={styles.settingLabel}>
<IconSymbol
name="flag"
size={20}
color={iconColor}
style={{ marginRight: 10 }}
/>
<ThemedText>{t("settings.corner_show")}</ThemedText>
</View>
<View style={styles.settingControl}>
<TouchableOpacity onPress={toggleCorners} style={styles.button}>
<ThemedText>
{state.cornerSettings.enabled
? t("settings.corner_enabled")
: t("settings.corner_disabled")}
</ThemedText>
</TouchableOpacity>
</View>
</View>
</View>
{/* <ThemedText style={styles.sectionTitle}>登录</ThemedText> {/* <ThemedText style={styles.sectionTitle}>登录</ThemedText>
<View <View

View File

@@ -38,6 +38,7 @@ export function MatchCard({
const oddsSettings = state.oddsSettings; const oddsSettings = state.oddsSettings;
const cardsSettings = state.cardsSettings; const cardsSettings = state.cardsSettings;
const cornerSettings = state.cornerSettings;
useEffect(() => { useEffect(() => {
if ( if (
@@ -59,9 +60,13 @@ export function MatchCard({
match.odds, match.odds,
]); ]);
// Fetch live score detail for cards info // Fetch live score detail for cards and corners info
useEffect(() => { useEffect(() => {
if (cardsSettings.enabled && isLive && match.leagueKey) { if (
(cardsSettings.enabled || cornerSettings.enabled) &&
isLive &&
match.leagueKey
) {
fetchLiveScore(match.sportId || 1, Number(match.leagueKey)) fetchLiveScore(match.sportId || 1, Number(match.leagueKey))
.then((matches) => { .then((matches) => {
const detail = matches.find((m) => String(m.event_key) === match.id); const detail = matches.find((m) => String(m.event_key) === match.id);
@@ -71,7 +76,13 @@ export function MatchCard({
}) })
.catch((err) => console.log("Fetch live detail for cards error:", err)); .catch((err) => console.log("Fetch live detail for cards error:", err));
} }
}, [cardsSettings.enabled, match.id, match.leagueKey, match.sportId]); }, [
cardsSettings.enabled,
cornerSettings.enabled,
match.id,
match.leagueKey,
match.sportId,
]);
// 当外部传入的 match.fav 改变时,更新内部状态 // 当外部传入的 match.fav 改变时,更新内部状态
useEffect(() => { useEffect(() => {
@@ -158,6 +169,26 @@ export function MatchCard({
return { homeYellow, homeRed, awayYellow, awayRed }; return { homeYellow, homeRed, awayYellow, awayRed };
}, [liveDetail, cardsSettings.enabled]); }, [liveDetail, cardsSettings.enabled]);
const extraStats = React.useMemo(() => {
if (!liveDetail?.statistics || !cornerSettings.enabled) {
return { home: "", away: "" };
}
const corners = liveDetail.statistics.find((s) => s.type === "Corners");
if (corners) {
return { home: corners.home, away: corners.away };
}
const dangerousAttacks = liveDetail.statistics.find(
(s) => s.type === "Dangerous Attacks",
);
if (dangerousAttacks) {
return { home: dangerousAttacks.home, away: dangerousAttacks.away };
}
return { home: "", away: "" };
}, [liveDetail, cornerSettings.enabled]);
const handlePress = () => { const handlePress = () => {
if (onPress) { if (onPress) {
onPress(match); onPress(match);
@@ -384,6 +415,17 @@ export function MatchCard({
<View style={styles.scoreBoxPlaceholder} /> <View style={styles.scoreBoxPlaceholder} />
)} )}
{(extraStats.home !== "" || extraStats.away !== "") && (
<View style={styles.extraStatsColumn}>
<ThemedText style={styles.extraStatText}>
{extraStats.home}
</ThemedText>
<ThemedText style={styles.extraStatText}>
{extraStats.away}
</ThemedText>
</View>
)}
<TouchableOpacity <TouchableOpacity
onPress={(e) => { onPress={(e) => {
e.stopPropagation(); e.stopPropagation();
@@ -539,6 +581,17 @@ const styles = StyleSheet.create({
cardBadgeRed: { cardBadgeRed: {
backgroundColor: "#FF3B30", backgroundColor: "#FF3B30",
}, },
extraStatsColumn: {
alignItems: "center",
justifyContent: "space-between",
height: 48,
paddingVertical: 2,
},
extraStatText: {
fontSize: 12,
fontWeight: "500",
opacity: 0.6,
},
cardBadgeText: { cardBadgeText: {
fontSize: 10, fontSize: 10,
fontWeight: "900", fontWeight: "900",

View File

@@ -1,4 +1,9 @@
import { CardsSettings, OddsSettings, storage } from "@/lib/storage"; import {
CardsSettings,
CornerSettings,
OddsSettings,
storage,
} from "@/lib/storage";
import React, { import React, {
createContext, createContext,
ReactNode, ReactNode,
@@ -14,6 +19,7 @@ interface AppState {
timezone: string; timezone: string;
oddsSettings: OddsSettings; oddsSettings: OddsSettings;
cardsSettings: CardsSettings; cardsSettings: CardsSettings;
cornerSettings: CornerSettings;
} }
interface AppStateContextType { interface AppStateContextType {
@@ -24,6 +30,7 @@ interface AppStateContextType {
updateTimezone: (timezone: string) => void; updateTimezone: (timezone: string) => void;
updateOddsSettings: (settings: OddsSettings) => void; updateOddsSettings: (settings: OddsSettings) => void;
updateCardsSettings: (settings: CardsSettings) => void; updateCardsSettings: (settings: CardsSettings) => void;
updateCornerSettings: (settings: CornerSettings) => void;
} }
const AppStateContext = createContext<AppStateContextType | undefined>( const AppStateContext = createContext<AppStateContextType | undefined>(
@@ -38,6 +45,7 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
timezone: "UTC", timezone: "UTC",
oddsSettings: { enabled: false, selectedBookmakers: [] }, oddsSettings: { enabled: false, selectedBookmakers: [] },
cardsSettings: { enabled: false }, cardsSettings: { enabled: false },
cornerSettings: { enabled: false },
}); });
useEffect(() => { useEffect(() => {
@@ -48,6 +56,9 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
storage.getCardsSettings().then((settings) => { storage.getCardsSettings().then((settings) => {
setState((prev) => ({ ...prev, cardsSettings: settings })); setState((prev) => ({ ...prev, cardsSettings: settings }));
}); });
storage.getCornerSettings().then((settings) => {
setState((prev) => ({ ...prev, cornerSettings: settings }));
});
}, []); }, []);
const updateSportId = (sportId: number | null) => { const updateSportId = (sportId: number | null) => {
@@ -76,6 +87,11 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
storage.setCardsSettings(settings); storage.setCardsSettings(settings);
}; };
const updateCornerSettings = (settings: CornerSettings) => {
setState((prev) => ({ ...prev, cornerSettings: settings }));
storage.setCornerSettings(settings);
};
return ( return (
<AppStateContext.Provider <AppStateContext.Provider
value={{ value={{
@@ -86,6 +102,7 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
updateTimezone, updateTimezone,
updateOddsSettings, updateOddsSettings,
updateCardsSettings, updateCardsSettings,
updateCornerSettings,
}} }}
> >
{children} {children}

View File

@@ -36,6 +36,10 @@
"cards_show": "Show Cards", "cards_show": "Show Cards",
"cards_enabled": "On", "cards_enabled": "On",
"cards_disabled": "Off", "cards_disabled": "Off",
"corner_title": "Corner Settings",
"corner_show": "Show Corners",
"corner_enabled": "On",
"corner_disabled": "Off",
"login": "Login", "login": "Login",
"click_to_login": "Click to login", "click_to_login": "Click to login",
"logout": "Logout", "logout": "Logout",

View File

@@ -36,6 +36,10 @@
"cards_show": "显示红黄牌", "cards_show": "显示红黄牌",
"cards_enabled": "开启", "cards_enabled": "开启",
"cards_disabled": "关闭", "cards_disabled": "关闭",
"corner_title": "角球设置",
"corner_show": "显示角球",
"corner_enabled": "开启",
"corner_disabled": "关闭",
"login": "登录", "login": "登录",
"click_to_login": "点击登录", "click_to_login": "点击登录",
"logout": "登出", "logout": "登出",

View File

@@ -7,6 +7,7 @@ const STORAGE_KEYS = {
USER: "user", USER: "user",
ODDS_SETTINGS: "odds_settings", ODDS_SETTINGS: "odds_settings",
CARDS_SETTINGS: "cards_settings", CARDS_SETTINGS: "cards_settings",
CORNER_SETTINGS: "corner_settings",
}; };
export interface OddsSettings { export interface OddsSettings {
@@ -18,6 +19,10 @@ export interface CardsSettings {
enabled: boolean; enabled: boolean;
} }
export interface CornerSettings {
enabled: boolean;
}
export const storage = { export const storage = {
async setAccessToken(token: string): Promise<void> { async setAccessToken(token: string): Promise<void> {
await AsyncStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, token); await AsyncStorage.setItem(STORAGE_KEYS.ACCESS_TOKEN, token);
@@ -83,6 +88,25 @@ export const storage = {
} }
}, },
async setCornerSettings(settings: CornerSettings): Promise<void> {
await AsyncStorage.setItem(
STORAGE_KEYS.CORNER_SETTINGS,
JSON.stringify(settings),
);
},
async getCornerSettings(): Promise<CornerSettings> {
const settingsStr = await AsyncStorage.getItem(
STORAGE_KEYS.CORNER_SETTINGS,
);
if (!settingsStr) return { enabled: false };
try {
return JSON.parse(settingsStr) as CornerSettings;
} catch {
return { enabled: false };
}
},
async clear(): Promise<void> { async clear(): Promise<void> {
await AsyncStorage.multiRemove([ await AsyncStorage.multiRemove([
STORAGE_KEYS.ACCESS_TOKEN, STORAGE_KEYS.ACCESS_TOKEN,