diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx
index b6d010b..63ddec3 100644
--- a/app/(tabs)/index.tsx
+++ b/app/(tabs)/index.tsx
@@ -390,7 +390,7 @@ export default function HomeScreen() {
awayTeamName: item.event_away_team,
homeTeamLogo: item.home_team_logo || "",
awayTeamLogo: item.away_team_logo || "",
- scoreText: item.event_halftime_result || "0 - 0",
+ scoreText: item.event_final_result || item.event_halftime_result || "0 - 0",
fav: false,
sportId: sportId,
isLive: true,
diff --git a/app/(tabs)/live.tsx b/app/(tabs)/live.tsx
index df4659a..f8074e4 100644
--- a/app/(tabs)/live.tsx
+++ b/app/(tabs)/live.tsx
@@ -66,7 +66,7 @@ export default function LiveScreen() {
homeTeamLogo: item.home_team_logo,
awayTeamLogo: item.away_team_logo,
meta: item.event_status,
- scoreText: item.event_final_result || "0 - 0",
+ scoreText: item.event_final_result || item.event_halftime_result || "0 - 0",
fav: false,
leagueId: item.league_key,
sportId: state.selectedSportId ?? undefined,
@@ -157,7 +157,7 @@ export default function LiveScreen() {
contentContainerStyle={styles.listContent}
ListEmptyComponent={
- {t("home.no_matches")}
+ {t("home.no_matches_live")}
}
/>
diff --git a/app/live-detail/[id].tsx b/app/live-detail/[id].tsx
index cabe529..7c7b116 100644
--- a/app/live-detail/[id].tsx
+++ b/app/live-detail/[id].tsx
@@ -90,19 +90,23 @@ export default function LiveDetailScreen() {
eventType: "",
eventToss: "",
eventManOfMatch: "",
- scores: match.scores,
- stats: match.statistics,
+ scores: Array.isArray(match.scores) && match.scores.length > 0 && 'type' in match.scores[0]
+ ? match.scores as { type: string; home: string; away: string; }[]
+ : undefined,
+ stats: Array.isArray(match.statistics) && match.statistics.length > 0 && 'type' in match.statistics[0]
+ ? match.statistics as { type: string; home: string; away: string; }[]
+ : undefined,
players: match.player_statistics
? {
- home_team: (match.player_statistics.home_team || []).map((p) => ({
- ...p,
- player_oncourt: p.player_oncourt || undefined,
- })),
- away_team: (match.player_statistics.away_team || []).map((p) => ({
- ...p,
- player_oncourt: p.player_oncourt || undefined,
- })),
- }
+ home_team: (match.player_statistics.home_team || []).map((p) => ({
+ ...p,
+ player_oncourt: p.player_oncourt || undefined,
+ })),
+ away_team: (match.player_statistics.away_team || []).map((p) => ({
+ ...p,
+ player_oncourt: p.player_oncourt || undefined,
+ })),
+ }
: undefined,
},
};
diff --git a/app/search.tsx b/app/search.tsx
index ece5b1c..d0cddb7 100644
--- a/app/search.tsx
+++ b/app/search.tsx
@@ -113,8 +113,10 @@ export default function SearchScreen() {
const { t } = useTranslation();
const insets = useSafeAreaInsets();
const isDark = theme === "dark";
+ const textColor = isDark ? "#FFFFFF" : "#000000";
const cardBg = isDark ? "#1C1C1E" : "#FFFFFF";
- const borderColor = isDark ? "#2C2C2E" : "rgba(0,0,0,0.06)";
+ const borderColor = isDark ? "#2C2C2E" : "rgba(0,0,0,0.1)";
+ const pageBg = isDark ? Colors.dark.background : "#f2f2f7";
const { state } = useAppState();
const [searchType, setSearchType] = useState("all");
@@ -485,7 +487,7 @@ export default function SearchScreen() {
+
-
- router.back()}
- >
-
-
-
- {t("search.title")}
-
- {t("search.subtitle")}
-
-
-
-
{renderSearchBar()}
@@ -792,39 +773,6 @@ const styles = StyleSheet.create({
container: {
flex: 1,
},
- nav: {
- flexDirection: "row",
- alignItems: "center",
- gap: 10,
- paddingHorizontal: 12,
- paddingBottom: 12,
- position: "sticky",
- top: 0,
- zIndex: 40,
- },
- iconBtn: {
- width: 38,
- height: 38,
- borderRadius: 14,
- alignItems: "center",
- justifyContent: "center",
- borderWidth: 1,
- },
- brand: {
- flex: 1,
- minWidth: 0,
- gap: 2,
- },
- brandTitle: {
- fontSize: 18,
- fontWeight: "700",
- letterSpacing: 0.2,
- },
- brandSub: {
- fontSize: 12,
- opacity: 0.5,
- fontWeight: "600",
- },
content: {
flex: 1,
},
@@ -862,7 +810,7 @@ const styles = StyleSheet.create({
},
chip: {
paddingHorizontal: 14,
- paddingVertical: 8,
+ paddingVertical: 6,
borderRadius: 999,
borderWidth: 1,
},
@@ -920,14 +868,14 @@ const styles = StyleSheet.create({
alignItems: "center",
gap: 12,
padding: 12,
- borderRadius: 18,
+ borderRadius: 10,
borderWidth: 1,
marginBottom: 10,
},
logoDot: {
width: 34,
height: 34,
- borderRadius: 14,
+ borderRadius: 8,
alignItems: "center",
justifyContent: "center",
borderWidth: 1,
diff --git a/assets/empty/country_dark.svg b/assets/empty/country_dark.svg
new file mode 100644
index 0000000..0a6a8f1
--- /dev/null
+++ b/assets/empty/country_dark.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/assets/empty/country_light.svg b/assets/empty/country_light.svg
new file mode 100644
index 0000000..cb93f82
--- /dev/null
+++ b/assets/empty/country_light.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/assets/empty/league_dark.svg b/assets/empty/league_dark.svg
new file mode 100644
index 0000000..7ed3cdd
--- /dev/null
+++ b/assets/empty/league_dark.svg
@@ -0,0 +1,7 @@
+
diff --git a/assets/empty/league_light.svg b/assets/empty/league_light.svg
new file mode 100644
index 0000000..933632e
--- /dev/null
+++ b/assets/empty/league_light.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/assets/empty/player_dark.svg b/assets/empty/player_dark.svg
new file mode 100644
index 0000000..e96d625
--- /dev/null
+++ b/assets/empty/player_dark.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/assets/empty/player_light.svg b/assets/empty/player_light.svg
new file mode 100644
index 0000000..cca3a47
--- /dev/null
+++ b/assets/empty/player_light.svg
@@ -0,0 +1,5 @@
+
\ No newline at end of file
diff --git a/assets/empty/team_dark.svg b/assets/empty/team_dark.svg
new file mode 100644
index 0000000..fe15a8b
--- /dev/null
+++ b/assets/empty/team_dark.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/empty/team_light.svg b/assets/empty/team_light.svg
new file mode 100644
index 0000000..f7c166c
--- /dev/null
+++ b/assets/empty/team_light.svg
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/assets/league_dark.svg b/assets/league_dark.svg
new file mode 100644
index 0000000..9937644
--- /dev/null
+++ b/assets/league_dark.svg
@@ -0,0 +1,7 @@
+
\ No newline at end of file
diff --git a/components/empty-placeholder.tsx b/components/empty-placeholder.tsx
new file mode 100644
index 0000000..e6b51e9
--- /dev/null
+++ b/components/empty-placeholder.tsx
@@ -0,0 +1,34 @@
+import { useTheme } from "@/context/ThemeContext";
+import { Image } from "expo-image";
+import React from "react";
+
+interface EmptyPlaceholderProps {
+ type: "team" | "league" | "player" | "country";
+ size?: number;
+}
+
+const imageMap: { [key: string]: any } = {
+ team_light: require("@/assets/empty/team_light.svg"),
+ team_dark: require("@/assets/empty/team_dark.svg"),
+ league_light: require("@/assets/empty/league_light.svg"),
+ league_dark: require("@/assets/empty/league_dark.svg"),
+ player_light: require("@/assets/empty/player_light.svg"),
+ player_dark: require("@/assets/empty/player_dark.svg"),
+ country_light: require("@/assets/empty/country_light.svg"),
+ country_dark: require("@/assets/empty/country_dark.svg"),
+};
+
+export function EmptyPlaceholder({ type, size = 64 }: EmptyPlaceholderProps) {
+ const { theme } = useTheme();
+ const isDark = theme === "dark";
+ const suffix = isDark ? "_dark" : "_light";
+ const imageKey = `${type}${suffix}`;
+
+ return (
+
+ );
+}
diff --git a/components/league-modal.tsx b/components/league-modal.tsx
index 2e113cf..f08196f 100644
--- a/components/league-modal.tsx
+++ b/components/league-modal.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
@@ -47,14 +48,14 @@ export function LeagueModal({
>
{/* 左侧图标 */}
- {league.logo ? (
+ {league.logo && league.logo.trim() !== "" && !league.logo.includes("placehold") ? (
) : (
-
+
)}
diff --git a/components/live-detail/live-league-info.tsx b/components/live-detail/live-league-info.tsx
index 74bb8af..36a4d35 100644
--- a/components/live-detail/live-league-info.tsx
+++ b/components/live-detail/live-league-info.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { LiveScoreMatch } from "@/types/api";
@@ -23,15 +24,13 @@ export function LiveLeagueInfo({ match }: LiveLeagueInfoProps) {
activeOpacity={0.7}
>
- {match.league_logo ? (
+ {match.league_logo && match.league_logo.trim() !== "" && !match.league_logo.includes("placehold") ? (
) : (
-
-
-
+
)}
{match.league_name}
diff --git a/components/live-detail/live-score-header.tsx b/components/live-detail/live-score-header.tsx
index c69d854..b46d980 100644
--- a/components/live-detail/live-score-header.tsx
+++ b/components/live-detail/live-score-header.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { addFavorite, checkFavorite, removeFavorite } from "@/lib/api";
@@ -265,10 +266,14 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
/>
-
+ {homeLogo && homeLogo.trim() !== "" && !homeLogo.includes("placehold") ? (
+
+ ) : (
+
+ )}
@@ -318,10 +323,14 @@ export function LiveScoreHeader({ match, topInset }: LiveScoreHeaderProps) {
-
+ {awayLogo && awayLogo.trim() !== "" && !awayLogo.includes("placehold") ? (
+
+ ) : (
+
+ )}
toggleTeamFavorite(match.away_team_key, false)}
@@ -437,7 +446,7 @@ const styles = StyleSheet.create({
},
scoreValue: {
color: "#000",
- fontSize: 25,
+ fontSize: 20,
fontWeight: "700",
lineHeight: 30,
letterSpacing: 1,
diff --git a/components/match-card-league.tsx b/components/match-card-league.tsx
index b1ca1d8..549d031 100644
--- a/components/match-card-league.tsx
+++ b/components/match-card-league.tsx
@@ -1,12 +1,11 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
import { useAppState } from "@/context/AppStateContext";
import { useTheme } from "@/context/ThemeContext";
import { addFavorite, removeFavorite } from "@/lib/api";
-import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
import { Match } from "@/types/api";
-import { LinearGradient } from "expo-linear-gradient";
import { useRouter } from "expo-router";
import React, { useState } from "react";
import { Image, Pressable, StyleSheet, TouchableOpacity, View } from "react-native";
@@ -182,13 +181,10 @@ export function MatchCardLeague({
{(() => {
- const teamName = isTennis ? (match as any).eventFirstPlayer : (match.home || match.homeTeamName);
const logoUri = isTennis
? (match as any).eventFirstPlayerLogo
: ((match as any).homeLogo || match.homeTeamLogo);
const hasLogo = logoUri && logoUri.trim() !== "" && !logoUri.includes("placehold");
- const gradient = getLogoGradient(teamName || "");
- const initials = getInitials(teamName || "");
return hasLogo ? (
) : (
-
- {initials}
-
+
);
})()}
@@ -217,13 +206,10 @@ export function MatchCardLeague({
{(() => {
- const teamName = isTennis ? (match as any).eventSecondPlayer : (match.away || match.awayTeamName);
const logoUri = isTennis
? (match as any).eventSecondPlayerLogo
: ((match as any).awayLogo || match.awayTeamLogo);
const hasLogo = logoUri && logoUri.trim() !== "" && !logoUri.includes("placehold");
- const gradient = getLogoGradient(teamName || "");
- const initials = getInitials(teamName || "");
return hasLogo ? (
) : (
-
- {initials}
-
+
);
})()}
@@ -386,7 +365,7 @@ const styles = StyleSheet.create({
gap: 6,
},
scoreBox: {
- width: 36,
+ width: 45,
height: 54,
borderRadius: 8,
borderWidth: 1.5,
@@ -416,7 +395,7 @@ const styles = StyleSheet.create({
color: "#FF9500",
},
scoreBoxPlaceholder: {
- width: 36,
+ width: 45,
height: 54,
},
favoriteButton: {
diff --git a/components/match-card.tsx b/components/match-card.tsx
index 38a2988..808b675 100644
--- a/components/match-card.tsx
+++ b/components/match-card.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
@@ -467,13 +468,16 @@ export function MatchCard({
-
+ {homeLogo && homeLogo.trim() !== "" && !homeLogo.includes("placehold") ? (
+ {}}
+ />
+ ) : (
+
+ )}
-
+ {awayLogo && awayLogo.trim() !== "" && !awayLogo.includes("placehold") ? (
+ {}}
+ />
+ ) : (
+
+ )}
{row.logo && row.logo.trim() !== "" && !row.logo.includes("placehold") ? (
- ) : null}
+ ) : (
+
+ )}
{row.name}
diff --git a/components/match-detail/basketball/basketball-stats.tsx b/components/match-detail/basketball/basketball-stats.tsx
index 8dfc759..a8c269c 100644
--- a/components/match-detail/basketball/basketball-stats.tsx
+++ b/components/match-detail/basketball/basketball-stats.tsx
@@ -1,9 +1,8 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
-import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
import { MatchDetailData } from "@/types/api";
import { Image } from "expo-image";
-import { LinearGradient } from "expo-linear-gradient";
import React, { useMemo, useState } from "react";
import {
ScrollView,
@@ -161,10 +160,6 @@ export function BasketballStats({ data, isDark }: BasketballStatsProps) {
const awayTeamLogo = match.awayTeamLogo || "";
const hasHomeLogo = homeTeamLogo && homeTeamLogo.trim() !== "" && !homeTeamLogo.includes("placehold");
const hasAwayLogo = awayTeamLogo && awayTeamLogo.trim() !== "" && !awayTeamLogo.includes("placehold");
- const homeGradient = getLogoGradient(homeTeamName);
- const awayGradient = getLogoGradient(awayTeamName);
- const homeInitials = getInitials(homeTeamName);
- const awayInitials = getInitials(awayTeamName);
return (
@@ -199,12 +194,7 @@ export function BasketballStats({ data, isDark }: BasketballStatsProps) {
{hasHomeLogo ? (
) : (
-
- {homeInitials}
-
+
)}
) : (
-
- {awayInitials}
-
+
)}
diff --git a/components/match-detail/football/football-score-table.tsx b/components/match-detail/football/football-score-table.tsx
index a3714a2..06d93fe 100644
--- a/components/match-detail/football/football-score-table.tsx
+++ b/components/match-detail/football/football-score-table.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { MatchDetailData } from "@/types/api";
import React from "react";
@@ -89,7 +90,11 @@ export function FootballScoreTable({ data, isDark }: FootballScoreTableProps) {
{rows.map((row, idx) => (
-
+ {row.logo && row.logo.trim() !== "" && !row.logo.includes("placehold") ? (
+
+ ) : (
+
+ )}
{row.name}
diff --git a/components/match-detail/league-info.tsx b/components/match-detail/league-info.tsx
index 4416b0d..2339b9a 100644
--- a/components/match-detail/league-info.tsx
+++ b/components/match-detail/league-info.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { MatchDetailData } from "@/types/api";
@@ -25,12 +26,10 @@ export function LeagueInfo({ data, isDark }: LeagueInfoProps) {
activeOpacity={0.7}
>
- {match.leagueLogo ? (
+ {match.leagueLogo && match.leagueLogo.trim() !== "" && !match.leagueLogo.includes("placehold") ? (
) : (
-
-
-
+
)}
{match.leagueName}
diff --git a/components/match-detail/score-header.tsx b/components/match-detail/score-header.tsx
index 4c68a7e..dac928b 100644
--- a/components/match-detail/score-header.tsx
+++ b/components/match-detail/score-header.tsx
@@ -1,7 +1,7 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { addFavorite, checkFavorite, removeFavorite } from "@/lib/api";
-import { getInitials, getLogoGradient } from "@/lib/avatar-utils";
import { storage } from "@/lib/storage";
import { MatchDetailData } from "@/types/api";
import { LinearGradient } from "expo-linear-gradient";
@@ -170,10 +170,6 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
const hasFirstLogo = firstPlayerLogo && firstPlayerLogo.trim() !== "" && !firstPlayerLogo.includes("placehold");
const hasSecondLogo = secondPlayerLogo && secondPlayerLogo.trim() !== "" && !secondPlayerLogo.includes("placehold");
- const firstGradient = getLogoGradient(firstPlayerName || "");
- const secondGradient = getLogoGradient(secondPlayerName || "");
- const firstInitials = getInitials(firstPlayerName || "");
- const secondInitials = getInitials(secondPlayerName || "");
return (
) : (
-
- {firstInitials}
-
+
)}
@@ -283,14 +272,7 @@ export function ScoreHeader({ data, isDark, topInset }: ScoreHeaderProps) {
style={styles.teamLogo}
/>
) : (
-
- {secondInitials}
-
+
)}
{(() => {
const hasLogo = league.logo && league.logo.trim() !== "" && !league.logo.includes("placehold");
- const gradient = getLogoGradient(league.name || "");
- const initials = getInitials(league.name || "");
return hasLogo ? (
) : (
-
- {initials}
-
+
);
})()}
diff --git a/components/upcoming-match-card.tsx b/components/upcoming-match-card.tsx
index fd23993..70a0bc6 100644
--- a/components/upcoming-match-card.tsx
+++ b/components/upcoming-match-card.tsx
@@ -1,3 +1,4 @@
+import { EmptyPlaceholder } from "@/components/empty-placeholder";
import { ThemedText } from "@/components/themed-text";
import { IconSymbol } from "@/components/ui/icon-symbol";
import { Colors } from "@/constants/theme";
@@ -122,12 +123,14 @@ export function UpcomingMatchCard({
- {match.homeTeamLogo && (
+ {match.homeTeamLogo && match.homeTeamLogo.trim() !== "" && !match.homeTeamLogo.includes("placehold") ? (
+ ) : (
+
)}
- {match.awayTeamLogo && (
+ {match.awayTeamLogo && match.awayTeamLogo.trim() !== "" && !match.awayTeamLogo.includes("placehold") ? (
+ ) : (
+
)}