import React, { useEffect, useCallback, useRef, useState } from "react"; import { View, StyleSheet, ActivityIndicator, FlatList, Pressable, Animated, StatusBar, Platform, BackHandler, ToastAndroid } from "react-native"; import { useSafeAreaInsets } from "react-native-safe-area-context"; import { ThemedView } from "@/components/ThemedView"; import { ThemedText } from "@/components/ThemedText"; import { api } from "@/services/api"; import VideoCard from "@/components/VideoCard"; import { useFocusEffect, useRouter } from "expo-router"; import { Search, Settings, LogOut, Heart } from "lucide-react-native"; import { StyledButton } from "@/components/StyledButton"; import useHomeStore, { RowItem, Category } from "@/stores/homeStore"; import useAuthStore from "@/stores/authStore"; import CustomScrollView from "@/components/CustomScrollView"; import { useResponsiveLayout } from "@/hooks/useResponsiveLayout"; import { getCommonResponsiveStyles } from "@/utils/ResponsiveStyles"; import ResponsiveNavigation from "@/components/navigation/ResponsiveNavigation"; import { useApiConfig, getApiConfigErrorMessage } from "@/hooks/useApiConfig"; import { Colors } from "@/constants/Colors"; const LOAD_MORE_THRESHOLD = 200; export default function HomeScreen() { const router = useRouter(); const colorScheme = "dark"; const [selectedTag, setSelectedTag] = useState(null); const fadeAnim = useRef(new Animated.Value(0)).current; const insets = useSafeAreaInsets(); // 响应式布局配置 const responsiveConfig = useResponsiveLayout(); const commonStyles = getCommonResponsiveStyles(responsiveConfig); const { deviceType, spacing } = responsiveConfig; const { categories, selectedCategory, contentData, loading, loadingMore, error, fetchInitialData, loadMoreData, selectCategory, refreshPlayRecords, clearError, } = useHomeStore(); const { isLoggedIn, logout } = useAuthStore(); const apiConfigStatus = useApiConfig(); useFocusEffect( useCallback(() => { refreshPlayRecords(); }, [refreshPlayRecords]) ); // 双击返回退出逻辑(只限当前页面) const backPressTimeRef = useRef(null); useFocusEffect( useCallback(() => { const handleBackPress = () => { const now = Date.now(); // 如果还没按过返回键,或距离上次超过2秒 if (!backPressTimeRef.current || now - backPressTimeRef.current > 2000) { backPressTimeRef.current = now; ToastAndroid.show("再按一次返回键退出", ToastAndroid.SHORT); return true; // 拦截返回事件,不退出 } // 两次返回键间隔小于2秒,退出应用 BackHandler.exitApp(); return true; }; // 仅限 Android 平台启用此功能 if (Platform.OS === "android") { const backHandler = BackHandler.addEventListener("hardwareBackPress", handleBackPress); // 返回首页时重置状态 return () => { backHandler.remove(); backPressTimeRef.current = null; }; } }, []) ); // 统一的数据获取逻辑 useEffect(() => { if (!selectedCategory) return; // 如果是容器分类且没有选择标签,设置默认标签 if (selectedCategory.tags && !selectedCategory.tag) { const defaultTag = selectedCategory.tags[0]; setSelectedTag(defaultTag); selectCategory({ ...selectedCategory, tag: defaultTag }); return; } // 只有在API配置完成且分类有效时才获取数据 if (apiConfigStatus.isConfigured && !apiConfigStatus.needsConfiguration) { // 对于有标签的分类,需要确保有标签才获取数据 if (selectedCategory.tags && selectedCategory.tag) { fetchInitialData(); } // 对于无标签的分类,直接获取数据 else if (!selectedCategory.tags) { fetchInitialData(); } } }, [ selectedCategory, selectedCategory?.tag, apiConfigStatus.isConfigured, apiConfigStatus.needsConfiguration, fetchInitialData, selectCategory, ]); // 清除错误状态的逻辑 useEffect(() => { if (apiConfigStatus.needsConfiguration && error) { clearError(); } }, [apiConfigStatus.needsConfiguration, error, clearError]); useEffect(() => { if (!loading && contentData.length > 0) { Animated.timing(fadeAnim, { toValue: 1, duration: 300, useNativeDriver: true, }).start(); } else if (loading) { fadeAnim.setValue(0); } }, [loading, contentData.length, fadeAnim]); const handleCategorySelect = (category: Category) => { setSelectedTag(null); selectCategory(category); }; const handleTagSelect = (tag: string) => { setSelectedTag(tag); if (selectedCategory) { const categoryWithTag = { ...selectedCategory, tag: tag }; selectCategory(categoryWithTag); } }; const renderCategory = ({ item }: { item: Category }) => { const isSelected = selectedCategory?.title === item.title; return ( handleCategorySelect(item)} isSelected={isSelected} style={dynamicStyles.categoryButton} textStyle={dynamicStyles.categoryText} /> ); }; const renderContentItem = ({ item }: { item: RowItem; index: number }) => ( ); const renderFooter = () => { if (!loadingMore) return null; return ; }; // 检查是否需要显示API配置提示 const shouldShowApiConfig = apiConfigStatus.needsConfiguration && selectedCategory && !selectedCategory.tags; // TV端和平板端的顶部导航 const renderHeader = () => { if (deviceType === "mobile") { // 移动端不显示顶部导航,使用底部Tab导航 return null; } return ( 首页 router.push("/live")}> {({ focused }) => ( 直播 )} router.push("/favorites")} variant="ghost"> router.push({ pathname: "/search" })} variant="ghost" > router.push("/settings")} variant="ghost"> {isLoggedIn && ( )} ); }; // 动态样式 const dynamicStyles = StyleSheet.create({ container: { flex: 1, paddingTop: deviceType === "mobile" ? insets.top : deviceType === "tablet" ? insets.top + 20 : 40, }, headerContainer: { flexDirection: "row", justifyContent: "space-between", alignItems: "center", paddingHorizontal: spacing * 1.5, marginBottom: spacing, }, headerTitle: { fontSize: deviceType === "mobile" ? 24 : deviceType === "tablet" ? 28 : 32, fontWeight: "bold", paddingTop: 16, }, rightHeaderButtons: { flexDirection: "row", alignItems: "center", }, iconButton: { borderRadius: 30, marginLeft: spacing / 2, }, categoryContainer: { paddingBottom: spacing / 2, }, categoryListContent: { paddingHorizontal: spacing, }, categoryButton: { paddingHorizontal: deviceType === "tv" ? spacing / 4 : spacing / 2, paddingVertical: spacing / 2, borderRadius: deviceType === "mobile" ? 6 : 8, marginHorizontal: deviceType === "tv" ? spacing / 4 : spacing / 2, // TV端使用更小的间距 }, categoryText: { fontSize: deviceType === "mobile" ? 14 : 16, fontWeight: "500", }, contentContainer: { flex: 1, }, }); const content = ( {/* 状态栏 */} {deviceType === "mobile" && } {/* 顶部导航 */} {renderHeader()} {/* 分类选择器 */} item.title} horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={dynamicStyles.categoryListContent} /> {/* 子分类标签 */} {selectedCategory && selectedCategory.tags && ( { const isSelected = selectedTag === item; return ( handleTagSelect(item)} isSelected={isSelected} style={dynamicStyles.categoryButton} textStyle={dynamicStyles.categoryText} variant="ghost" /> ); }} keyExtractor={(item) => item} horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={dynamicStyles.categoryListContent} /> )} {/* 内容网格 */} {shouldShowApiConfig ? ( {getApiConfigErrorMessage(apiConfigStatus)} ) : apiConfigStatus.isValidating ? ( 正在验证服务器配置... ) : apiConfigStatus.error && !apiConfigStatus.isValid ? ( {apiConfigStatus.error} ) : loading ? ( ) : error ? ( {error} ) : ( )} ); // 根据设备类型决定是否包装在响应式导航中 if (deviceType === "tv") { return content; } return {content}; }