添加图标和球类选择

This commit is contained in:
xianyi
2026-01-13 10:53:30 +08:00
parent bff2763013
commit 5bbbf1a132
25 changed files with 734 additions and 41 deletions

View File

@@ -52,13 +52,55 @@ export default function HomeScreen() {
const loadSports = async () => {
try {
const list = await fetchSports();
setSports(list);
if (list.length > 0) {
setSelectedSportId(list[0].id);
const apiList = await fetchSports();
// 创建8个运动的完整列表
const defaultSports: Sport[] = [
{ id: 1, name: "football", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 2, name: "basketball", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 3, name: "tennis", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 4, name: "cricket", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 5, name: "baseball", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 6, name: "badminton", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 7, name: "snooker", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 8, name: "volleyball", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
];
// 合并API返回的运动和默认列表
const sportsMap = new Map<number, Sport>();
apiList.forEach((sport) => {
sportsMap.set(sport.id, sport);
});
// 补充默认运动到8个
defaultSports.forEach((sport) => {
if (!sportsMap.has(sport.id)) {
sportsMap.set(sport.id, sport);
}
});
const allSports = Array.from(sportsMap.values())
.sort((a, b) => a.id - b.id)
.slice(0, 8);
setSports(allSports);
if (allSports.length > 0) {
setSelectedSportId(allSports[0].id);
}
} catch (e) {
console.error(e);
// API失败时使用默认8个运动
const defaultSports: Sport[] = [
{ id: 1, name: "football", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 2, name: "basketball", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 3, name: "tennis", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 4, name: "cricket", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 5, name: "baseball", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 6, name: "badminton", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 7, name: "snooker", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
{ id: 8, name: "volleyball", description: "", icon: "", isActive: true, updatedAt: "", createdAt: "" },
];
setSports(defaultSports);
setSelectedSportId(1);
}
};
@@ -77,6 +119,23 @@ export default function HomeScreen() {
const currentSport = sports.find((s) => s.id === selectedSportId);
// 获取当前运动的国际化名称
const getSportName = (sport: Sport | undefined): string => {
if (!sport) return t("home.select_sport");
const sportKeyMap: { [key: number]: string } = {
1: "football",
2: "basketball",
3: "tennis",
4: "cricket",
5: "baseball",
6: "badminton",
7: "snooker",
8: "volleyball",
};
const sportKey = sportKeyMap[sport.id] || sport.name.toLowerCase();
return t(`sports.${sportKey}`, { defaultValue: sport.name });
};
const renderHeader = () => (
<View style={styles.filterContainer}>
{/* Time Filter (Mock) */}
@@ -98,7 +157,7 @@ export default function HomeScreen() {
>
<IconSymbol name="football-outline" size={18} color={iconColor} />
<ThemedText style={styles.filterText}>
{currentSport ? currentSport.name : t("home.select_sport")}
{getSportName(currentSport)}
</ThemedText>
</TouchableOpacity>
@@ -148,12 +207,25 @@ export default function HomeScreen() {
visible={showSportModal}
onClose={() => setShowSportModal(false)}
title={t("home.select_sport")}
options={sports.map((s) => ({
id: s.id,
label: s.name,
value: s.id,
icon: s.icon, // 添加图标
}))}
options={sports.map((s) => {
const sportKeyMap: { [key: number]: string } = {
1: "football",
2: "basketball",
3: "tennis",
4: "cricket",
5: "baseball",
6: "badminton",
7: "snooker",
8: "volleyball",
};
const sportKey = sportKeyMap[s.id] || s.name.toLowerCase();
return {
id: s.id,
label: s.name, // 保留原始名称用于图标识别
value: s.id,
icon: s.icon,
};
})}
selectedValue={selectedSportId}
onSelect={setSelectedSportId}
/>

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#eef3f8"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.60"/>
<path d="M20 26c5 5 19 5 24 0" stroke="#aab3c2" stroke-width="3" fill="none" opacity=".85"/>
<path d="M22 38c6-10 18-12 22-4" stroke="#aab3c2" stroke-width="3" fill="none" opacity=".65"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#eef3f8"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.60"/>
<path d="M20 26c5 5 19 5 24 0" stroke="#aab3c2" stroke-width="3" fill="none" opacity=".85"/>
<path d="M22 38c6-10 18-12 22-4" stroke="#aab3c2" stroke-width="3" fill="none" opacity=".65"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#eef3f8"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.60"/>
<path d="M20 26c5 5 19 5 24 0" stroke="#aab3c2" stroke-width="3" fill="none" opacity=".85"/>
<path d="M22 38c6-10 18-12 22-4" stroke="#aab3c2" stroke-width="3" fill="none" opacity=".65"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e7eef7"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.55"/>
<path d="M16 18c8 8 10 18 8 28" stroke="#c43b3b" stroke-width="2.4" fill="none" opacity=".85"/>
<path d="M48 18c-8 8-10 18-8 28" stroke="#c43b3b" stroke-width="2.4" fill="none" opacity=".85"/>
<path d="M20 24c2 2 3 4 3 6" stroke="#c43b3b" stroke-width="2" opacity=".7"/>
<path d="M44 24c-2 2-3 4-3 6" stroke="#c43b3b" stroke-width="2" opacity=".7"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e7eef7"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.55"/>
<path d="M16 18c8 8 10 18 8 28" stroke="#c43b3b" stroke-width="2.4" fill="none" opacity=".85"/>
<path d="M48 18c-8 8-10 18-8 28" stroke="#c43b3b" stroke-width="2.4" fill="none" opacity=".85"/>
<path d="M20 24c2 2 3 4 3 6" stroke="#c43b3b" stroke-width="2" opacity=".7"/>
<path d="M44 24c-2 2-3 4-3 6" stroke="#c43b3b" stroke-width="2" opacity=".7"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e7eef7"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.55"/>
<path d="M16 18c8 8 10 18 8 28" stroke="#c43b3b" stroke-width="2.4" fill="none" opacity=".85"/>
<path d="M48 18c-8 8-10 18-8 28" stroke="#c43b3b" stroke-width="2.4" fill="none" opacity=".85"/>
<path d="M20 24c2 2 3 4 3 6" stroke="#c43b3b" stroke-width="2" opacity=".7"/>
<path d="M44 24c-2 2-3 4-3 6" stroke="#c43b3b" stroke-width="2" opacity=".7"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffb25c"/>
<stop offset="1" stop-color="#e8742f"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.75"/>
<path d="M12 32h40" stroke="#2b1a10" stroke-width="2.4" opacity=".65"/>
<path d="M32 12v40" stroke="#2b1a10" stroke-width="2.4" opacity=".65"/>
<path d="M20 16c7 6 12 14 12 16s-5 10-12 16" stroke="#2b1a10" stroke-width="2.2" fill="none" opacity=".6"/>
<path d="M44 16c-7 6-12 14-12 16s5 10 12 16" stroke="#2b1a10" stroke-width="2.2" fill="none" opacity=".6"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffb25c"/>
<stop offset="1" stop-color="#e8742f"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.75"/>
<path d="M12 32h40" stroke="#2b1a10" stroke-width="2.4" opacity=".65"/>
<path d="M32 12v40" stroke="#2b1a10" stroke-width="2.4" opacity=".65"/>
<path d="M20 16c7 6 12 14 12 16s-5 10-12 16" stroke="#2b1a10" stroke-width="2.2" fill="none" opacity=".6"/>
<path d="M44 16c-7 6-12 14-12 16s5 10 12 16" stroke="#2b1a10" stroke-width="2.2" fill="none" opacity=".6"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,27 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffb25c"/>
<stop offset="1" stop-color="#e8742f"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.75"/>
<path d="M12 32h40" stroke="#2b1a10" stroke-width="2.4" opacity=".65"/>
<path d="M32 12v40" stroke="#2b1a10" stroke-width="2.4" opacity=".65"/>
<path d="M20 16c7 6 12 14 12 16s-5 10-12 16" stroke="#2b1a10" stroke-width="2.2" fill="none" opacity=".6"/>
<path d="M44 16c-7 6-12 14-12 16s5 10 12 16" stroke="#2b1a10" stroke-width="2.2" fill="none" opacity=".6"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e8edf3"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.55"/>
<path d="M20 20c10 5 14 19 8 28" stroke="#cc2f2f" stroke-width="2.6" fill="none" opacity=".85"/>
<path d="M44 20c-10 5-14 19-8 28" stroke="#cc2f2f" stroke-width="2.6" fill="none" opacity=".85"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e8edf3"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.55"/>
<path d="M20 20c10 5 14 19 8 28" stroke="#cc2f2f" stroke-width="2.6" fill="none" opacity=".85"/>
<path d="M44 20c-10 5-14 19-8 28" stroke="#cc2f2f" stroke-width="2.6" fill="none" opacity=".85"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#e8edf3"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.55"/>
<path d="M20 20c10 5 14 19 8 28" stroke="#cc2f2f" stroke-width="2.6" fill="none" opacity=".85"/>
<path d="M44 20c-10 5-14 19-8 28" stroke="#cc2f2f" stroke-width="2.6" fill="none" opacity=".85"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#dfe6ee"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.9"/>
<path d="M32 18l7 5-3 8H28l-3-8 7-5Z" fill="#1b1f2a"/>
<path d="M32 18l-7 5-9-2" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".75"/>
<path d="M39 23l10 2 4 7" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".75"/>
<path d="M28 31l-8 6 2 10" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".6"/>
<path d="M36 31l8 6-2 10" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".6"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#dfe6ee"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.9"/>
<path d="M32 18l7 5-3 8H28l-3-8 7-5Z" fill="#1b1f2a"/>
<path d="M32 18l-7 5-9-2" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".75"/>
<path d="M39 23l10 2 4 7" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".75"/>
<path d="M28 31l-8 6 2 10" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".6"/>
<path d="M36 31l8 6-2 10" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".6"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,28 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#ffffff"/>
<stop offset="1" stop-color="#dfe6ee"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.9"/>
<path d="M32 18l7 5-3 8H28l-3-8 7-5Z" fill="#1b1f2a"/>
<path d="M32 18l-7 5-9-2" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".75"/>
<path d="M39 23l10 2 4 7" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".75"/>
<path d="M28 31l-8 6 2 10" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".6"/>
<path d="M36 31l8 6-2 10" stroke="#1b1f2a" stroke-width="2" fill="none" opacity=".6"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#2b2f38"/>
<stop offset="1" stop-color="#0a0c10"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.35"/>
<circle cx="24" cy="24" r="8" fill="#ffffff" fill-opacity=".16"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#ffffff" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 914 B

View File

@@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#2b2f38"/>
<stop offset="1" stop-color="#0a0c10"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.35"/>
<circle cx="24" cy="24" r="8" fill="#ffffff" fill-opacity=".16"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#ffffff" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 913 B

View File

@@ -0,0 +1,24 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#2b2f38"/>
<stop offset="1" stop-color="#0a0c10"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.35"/>
<circle cx="24" cy="24" r="8" fill="#ffffff" fill-opacity=".16"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#ffffff" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 915 B

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#d7ff62"/>
<stop offset="1" stop-color="#6fd53a"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="1.0">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.45"/>
<path d="M14 26c10 10 26 10 36 0" stroke="#f5ffd0" stroke-width="3" fill="none" opacity=".9"/>
<path d="M14 38c10-10 26-10 36 0" stroke="#f5ffd0" stroke-width="3" fill="none" opacity=".9"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.22" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#d7ff62"/>
<stop offset="1" stop-color="#6fd53a"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.5">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.45"/>
<path d="M14 26c10 10 26 10 36 0" stroke="#f5ffd0" stroke-width="3" fill="none" opacity=".9"/>
<path d="M14 38c10-10 26-10 36 0" stroke="#f5ffd0" stroke-width="3" fill="none" opacity=".9"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.1" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -0,0 +1,25 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
<defs>
<radialGradient id="g" cx="30%" cy="25%" r="70%">
<stop offset="0" stop-color="#d7ff62"/>
<stop offset="1" stop-color="#6fd53a"/>
</radialGradient>
<filter id="tex" x="-20%" y="-20%" width="140%" height="140%">
<feTurbulence type="fractalNoise" baseFrequency="0.9" numOctaves="2" stitchTiles="stitch" />
<feColorMatrix type="matrix" values="
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0 0.35
0 0 0 0.12 0" />
</filter>
</defs>
<g opacity="0.78">
<circle cx="32" cy="32" r="28" fill="url(#g)"/>
<circle cx="32" cy="32" r="28" filter="url(#tex)" opacity="0.45"/>
<path d="M14 26c10 10 26 10 36 0" stroke="#f5ffd0" stroke-width="3" fill="none" opacity=".9"/>
<path d="M14 38c10-10 26-10 36 0" stroke="#f5ffd0" stroke-width="3" fill="none" opacity=".9"/>
<circle cx="32" cy="32" r="28" fill="none" stroke="#0b0d12" stroke-opacity="0.16" stroke-width="2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -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";
@@ -100,6 +147,11 @@ export function SelectionModal({
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
key={opt.id}
@@ -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,

View File

@@ -55,5 +55,19 @@
"halftime": "Half: {{score}}",
"empty_h2h": "No H2H data",
"empty_chat": "Chat is not available"
},
"selection": {
"selected": "Selected",
"click_to_toggle": "Tap to switch"
},
"sports": {
"football": "Football",
"basketball": "Basketball",
"tennis": "Tennis",
"cricket": "Cricket",
"baseball": "Baseball",
"badminton": "Badminton",
"snooker": "Snooker",
"volleyball": "Volleyball"
}
}

View File

@@ -55,5 +55,19 @@
"halftime": "半场: {{score}}",
"empty_h2h": "暂无交锋数据",
"empty_chat": "聊天功能暂未开启"
},
"selection": {
"selected": "已选择",
"click_to_toggle": "点击切换"
},
"sports": {
"football": "足球",
"basketball": "篮球",
"tennis": "网球",
"cricket": "板球",
"baseball": "棒球",
"badminton": "羽毛球",
"snooker": "斯诺克",
"volleyball": "排球"
}
}