import { ThemedText } from "@/components/themed-text"; import { IconSymbol } from "@/components/ui/icon-symbol"; import { Colors } from "@/constants/theme"; import { useTheme } from "@/context/ThemeContext"; import { Image } from "expo-image"; import React from "react"; import { useTranslation } from "react-i18next"; import { FlatList, Modal, Pressable, StyleSheet, View } from "react-native"; import { SafeAreaView } from "react-native-safe-area-context"; interface SelectionOption { id: number | string; label: string; value: any; icon?: string; // 图标名称 } // 运动ID到运动键的映射(支持8种运动) // 根据API文档:1:足球, 2:篮球, 3:网球, 4:板球 // 扩展为8种:1:足球, 2:篮球, 3:网球, 4:板球, 5:棒球, 6:羽毛球, 7:斯诺克, 8:排球 const getSportKeyById = (id: number): string => { const sportMap: { [key: number]: string } = { 1: "football", 2: "basketball", 3: "tennis", 4: "cricket", 5: "baseball", 6: "badminton", 7: "snooker", 8: "volleyball", }; return sportMap[id] || "football"; }; // 运动名称到图标文件名的映射(支持8种运动) const getSportIconName = (label: string, id?: number): string => { // 优先使用ID if (id !== undefined) { return getSportKeyById(id); } const labelLower = label.toLowerCase(); if (labelLower.includes("足球") || labelLower.includes("football") || labelLower.includes("soccer")) { return "football"; } if (labelLower.includes("篮球") || labelLower.includes("basketball")) { return "basketball"; } if (labelLower.includes("板球") || labelLower.includes("cricket")) { return "cricket"; } if (labelLower.includes("网球") || labelLower.includes("tennis")) { return "tennis"; } if (labelLower.includes("棒球") || labelLower.includes("baseball")) { return "baseball"; } if (labelLower.includes("羽毛球") || labelLower.includes("badminton")) { return "badminton"; } if (labelLower.includes("斯诺克") || labelLower.includes("snooker")) { return "snooker"; } if (labelLower.includes("排球") || labelLower.includes("volleyball")) { return "volleyball"; } // 默认图标 return "football"; }; // 获取图标资源 const getSportIconSource = (label: string, isSelected: boolean, id?: number) => { const iconName = getSportIconName(label, id); const state = isSelected ? "active" : "inactive"; // 使用 require 动态导入图标(8种运动) const iconMap: { [key: string]: any } = { "football_active": require("@/assets/balls/football_active.svg"), "football_inactive": require("@/assets/balls/football_inactive.svg"), "basketball_active": require("@/assets/balls/basketball_active.svg"), "basketball_inactive": require("@/assets/balls/basketball_inactive.svg"), "cricket_active": require("@/assets/balls/cricket_active.svg"), "cricket_inactive": require("@/assets/balls/cricket_inactive.svg"), "tennis_active": require("@/assets/balls/tennis_active.svg"), "tennis_inactive": require("@/assets/balls/tennis_inactive.svg"), "baseball_active": require("@/assets/balls/baseball_active.svg"), "baseball_inactive": require("@/assets/balls/baseball_inactive.svg"), "badminton_active": require("@/assets/balls/badminton_active.svg"), "badminton_inactive": require("@/assets/balls/badminton_inactive.svg"), "snooker_active": require("@/assets/balls/snooker_active.svg"), "snooker_inactive": require("@/assets/balls/snooker_inactive.svg"), "volleyball_active": require("@/assets/balls/football_active.svg"), // 使用football作为默认,因为volleyball图标不存在 "volleyball_inactive": require("@/assets/balls/football_inactive.svg"), }; return iconMap[`${iconName}_${state}`] || iconMap["football_inactive"]; }; interface SelectionModalProps { visible: boolean; onClose: () => void; title: string; options: SelectionOption[]; onSelect: (value: any) => void; selectedValue: any; } export function SelectionModal({ visible, onClose, title, options, onSelect, selectedValue, }: SelectionModalProps) { const { theme } = useTheme(); const { t } = useTranslation(); const isDark = theme === "dark"; const bg = isDark ? "#1C1C1E" : "#FFFFFF"; const text = isDark ? "#FFFFFF" : "#000000"; const optionBg = isDark ? "#2C2C2E" : "#F5F5F5"; const iconBg = isDark ? "#3A3A3C" : "#E5E5EA"; const renderOption = ({ item: opt }: { item: SelectionOption }) => { const isSelected = selectedValue === opt.value; // 获取运动键用于i18n和图标 const sportId = typeof opt.id === "number" ? opt.id : undefined; const sportKey = sportId ? getSportKeyById(sportId) : getSportIconName(opt.label, sportId); const sportName = t(`sports.${sportKey}`, { defaultValue: opt.label }); return ( { onSelect(opt.value); onClose(); }} > {/* 左侧图标 */} {/* 中间内容 */} {sportName} {isSelected ? t("selection.selected") : t("selection.click_to_toggle")} {/* 右侧指示点 */} ); }; return ( {title} item.id.toString()} showsVerticalScrollIndicator={false} contentContainerStyle={styles.listContent} removeClippedSubviews={true} maxToRenderPerBatch={10} updateCellsBatchingPeriod={50} windowSize={10} initialNumToRender={10} /> ); } const styles = StyleSheet.create({ overlay: { flex: 1, backgroundColor: "rgba(0,0,0,0.5)", }, sheet: { borderTopLeftRadius: 20, borderTopRightRadius: 20, padding: 20, height: "55%", }, header: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", marginBottom: 20, }, title: { fontSize: 18, fontWeight: "600", }, closeButton: { width: 32, height: 32, alignItems: "center", justifyContent: "center", }, listContent: { paddingBottom: 20, }, option: { flexDirection: "row", alignItems: "center", paddingVertical: 16, paddingHorizontal: 16, marginBottom: 12, borderRadius: 12, }, iconContainer: { width: 48, height: 48, borderRadius: 24, alignItems: "center", justifyContent: "center", marginRight: 12, }, iconImage: { width: 32, height: 32, }, content: { flex: 1, }, optionLabel: { fontSize: 16, marginBottom: 4, }, statusText: { fontSize: 12, opacity: 0.6, }, indicator: { width: 8, height: 8, borderRadius: 4, marginLeft: 12, }, });