添加图标和球类选择
This commit is contained in:
@@ -2,7 +2,9 @@ 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 { Modal, Pressable, ScrollView, StyleSheet, View } from "react-native";
|
||||
import { SafeAreaView } from "react-native-safe-area-context";
|
||||
|
||||
@@ -13,42 +15,86 @@ interface SelectionOption {
|
||||
icon?: string; // 图标名称
|
||||
}
|
||||
|
||||
// 运动名称到图标的映射
|
||||
const getSportIcon = (label: string, icon?: string): string => {
|
||||
// 如果提供了 icon 字段,尝试直接使用
|
||||
if (icon) {
|
||||
// 如果 icon 已经是 Ionicons 格式,直接返回
|
||||
if (icon.includes("-")) {
|
||||
return icon;
|
||||
}
|
||||
}
|
||||
// 运动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-outline";
|
||||
return "football";
|
||||
}
|
||||
if (labelLower.includes("篮球") || labelLower.includes("basketball")) {
|
||||
return "basketball-outline";
|
||||
return "basketball";
|
||||
}
|
||||
if (labelLower.includes("板球") || labelLower.includes("cricket")) {
|
||||
return "baseball-outline";
|
||||
return "cricket";
|
||||
}
|
||||
if (labelLower.includes("网球") || labelLower.includes("tennis")) {
|
||||
return "tennisball-outline";
|
||||
return "tennis";
|
||||
}
|
||||
if (labelLower.includes("棒球") || labelLower.includes("baseball")) {
|
||||
return "baseball-outline";
|
||||
return "baseball";
|
||||
}
|
||||
if (labelLower.includes("羽毛球") || labelLower.includes("badminton")) {
|
||||
return "ellipse-outline";
|
||||
return "badminton";
|
||||
}
|
||||
if (labelLower.includes("斯诺克") || labelLower.includes("snooker")) {
|
||||
return "radio-button-on-outline";
|
||||
return "snooker";
|
||||
}
|
||||
if (labelLower.includes("排球") || labelLower.includes("volleyball")) {
|
||||
return "volleyball";
|
||||
}
|
||||
|
||||
// 默认图标
|
||||
return "ellipse-outline";
|
||||
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 {
|
||||
@@ -69,6 +115,7 @@ export function SelectionModal({
|
||||
selectedValue,
|
||||
}: SelectionModalProps) {
|
||||
const { theme } = useTheme();
|
||||
const { t } = useTranslation();
|
||||
const isDark = theme === "dark";
|
||||
const bg = isDark ? "#1C1C1E" : "#FFFFFF";
|
||||
const text = isDark ? "#FFFFFF" : "#000000";
|
||||
@@ -99,6 +146,11 @@ export function SelectionModal({
|
||||
const isSelected = selectedValue === opt.value;
|
||||
const optionBg = isDark ? "#2C2C2E" : "#F5F5F5";
|
||||
const iconBg = isDark ? "#3A3A3C" : "#E5E5EA";
|
||||
|
||||
// 获取运动键用于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 (
|
||||
<Pressable
|
||||
@@ -114,10 +166,10 @@ export function SelectionModal({
|
||||
>
|
||||
{/* 左侧图标 */}
|
||||
<View style={[styles.iconContainer, { backgroundColor: iconBg }]}>
|
||||
<IconSymbol
|
||||
name={getSportIcon(opt.label, opt.icon) as any}
|
||||
size={24}
|
||||
color={isSelected ? Colors.light.tint : text}
|
||||
<Image
|
||||
source={getSportIconSource(opt.label, isSelected, sportId)}
|
||||
style={styles.iconImage}
|
||||
contentFit="contain"
|
||||
/>
|
||||
</View>
|
||||
|
||||
@@ -129,10 +181,10 @@ export function SelectionModal({
|
||||
{ fontWeight: isSelected ? "600" : "400" },
|
||||
]}
|
||||
>
|
||||
{opt.label}
|
||||
{sportName}
|
||||
</ThemedText>
|
||||
<ThemedText style={styles.statusText}>
|
||||
{isSelected ? "已选择" : "点击切换"}
|
||||
{isSelected ? t("selection.selected") : t("selection.click_to_toggle")}
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
@@ -168,7 +220,7 @@ const styles = StyleSheet.create({
|
||||
borderTopLeftRadius: 20,
|
||||
borderTopRightRadius: 20,
|
||||
padding: 20,
|
||||
maxHeight: "70%",
|
||||
height: "55%",
|
||||
},
|
||||
header: {
|
||||
flexDirection: "row",
|
||||
@@ -205,11 +257,9 @@ const styles = StyleSheet.create({
|
||||
justifyContent: "center",
|
||||
marginRight: 12,
|
||||
},
|
||||
iconPlaceholder: {
|
||||
width: 24,
|
||||
height: 24,
|
||||
borderRadius: 12,
|
||||
backgroundColor: "#999",
|
||||
iconImage: {
|
||||
width: 32,
|
||||
height: 32,
|
||||
},
|
||||
content: {
|
||||
flex: 1,
|
||||
|
||||
Reference in New Issue
Block a user