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

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() {
const { theme, toggleTheme, setTheme, isSystemTheme, useSystemTheme } =
useTheme();
const { state, updateOddsSettings, updateCardsSettings } = useAppState();
const {
state,
updateOddsSettings,
updateCardsSettings,
updateCornerSettings,
} = useAppState();
const { t, i18n } = useTranslation();
const router = useRouter();
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 current = state.oddsSettings.selectedBookmakers;
let next: string[];
@@ -468,6 +480,38 @@ export default function ProfileScreen() {
</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>
<View

View File

@@ -38,6 +38,7 @@ export function MatchCard({
const oddsSettings = state.oddsSettings;
const cardsSettings = state.cardsSettings;
const cornerSettings = state.cornerSettings;
useEffect(() => {
if (
@@ -59,9 +60,13 @@ export function MatchCard({
match.odds,
]);
// Fetch live score detail for cards info
// Fetch live score detail for cards and corners info
useEffect(() => {
if (cardsSettings.enabled && isLive && match.leagueKey) {
if (
(cardsSettings.enabled || cornerSettings.enabled) &&
isLive &&
match.leagueKey
) {
fetchLiveScore(match.sportId || 1, Number(match.leagueKey))
.then((matches) => {
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));
}
}, [cardsSettings.enabled, match.id, match.leagueKey, match.sportId]);
}, [
cardsSettings.enabled,
cornerSettings.enabled,
match.id,
match.leagueKey,
match.sportId,
]);
// 当外部传入的 match.fav 改变时,更新内部状态
useEffect(() => {
@@ -158,6 +169,26 @@ export function MatchCard({
return { homeYellow, homeRed, awayYellow, awayRed };
}, [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 = () => {
if (onPress) {
onPress(match);
@@ -384,6 +415,17 @@ export function MatchCard({
<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
onPress={(e) => {
e.stopPropagation();
@@ -539,6 +581,17 @@ const styles = StyleSheet.create({
cardBadgeRed: {
backgroundColor: "#FF3B30",
},
extraStatsColumn: {
alignItems: "center",
justifyContent: "space-between",
height: 48,
paddingVertical: 2,
},
extraStatText: {
fontSize: 12,
fontWeight: "500",
opacity: 0.6,
},
cardBadgeText: {
fontSize: 10,
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, {
createContext,
ReactNode,
@@ -14,6 +19,7 @@ interface AppState {
timezone: string;
oddsSettings: OddsSettings;
cardsSettings: CardsSettings;
cornerSettings: CornerSettings;
}
interface AppStateContextType {
@@ -24,6 +30,7 @@ interface AppStateContextType {
updateTimezone: (timezone: string) => void;
updateOddsSettings: (settings: OddsSettings) => void;
updateCardsSettings: (settings: CardsSettings) => void;
updateCornerSettings: (settings: CornerSettings) => void;
}
const AppStateContext = createContext<AppStateContextType | undefined>(
@@ -38,6 +45,7 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
timezone: "UTC",
oddsSettings: { enabled: false, selectedBookmakers: [] },
cardsSettings: { enabled: false },
cornerSettings: { enabled: false },
});
useEffect(() => {
@@ -48,6 +56,9 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
storage.getCardsSettings().then((settings) => {
setState((prev) => ({ ...prev, cardsSettings: settings }));
});
storage.getCornerSettings().then((settings) => {
setState((prev) => ({ ...prev, cornerSettings: settings }));
});
}, []);
const updateSportId = (sportId: number | null) => {
@@ -76,6 +87,11 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
storage.setCardsSettings(settings);
};
const updateCornerSettings = (settings: CornerSettings) => {
setState((prev) => ({ ...prev, cornerSettings: settings }));
storage.setCornerSettings(settings);
};
return (
<AppStateContext.Provider
value={{
@@ -86,6 +102,7 @@ export function AppStateProvider({ children }: { children: ReactNode }) {
updateTimezone,
updateOddsSettings,
updateCardsSettings,
updateCornerSettings,
}}
>
{children}

View File

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

View File

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

View File

@@ -7,6 +7,7 @@ const STORAGE_KEYS = {
USER: "user",
ODDS_SETTINGS: "odds_settings",
CARDS_SETTINGS: "cards_settings",
CORNER_SETTINGS: "corner_settings",
};
export interface OddsSettings {
@@ -18,6 +19,10 @@ export interface CardsSettings {
enabled: boolean;
}
export interface CornerSettings {
enabled: boolean;
}
export const storage = {
async setAccessToken(token: string): Promise<void> {
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> {
await AsyncStorage.multiRemove([
STORAGE_KEYS.ACCESS_TOKEN,