From e0a56710d0ed54d300f15b73f1c9758d1508cc32 Mon Sep 17 00:00:00 2001 From: imeepos Date: Wed, 21 Jan 2026 12:06:46 +0800 Subject: [PATCH] feat: integrate UI components into Video tab Replace inline LoadingState, ErrorState, and FooterLoading components with reusable UI components (LoadingState, ErrorState, RefreshControl, PaginationLoader). Add retry functionality to ErrorState and maintain consistent styling with #FFE500 color theme. Co-Authored-By: Claude Opus 4.5 --- app/(tabs)/video.test.tsx | 6 +++++ app/(tabs)/video.tsx | 55 +++++++++++++++------------------------ 2 files changed, 27 insertions(+), 34 deletions(-) diff --git a/app/(tabs)/video.test.tsx b/app/(tabs)/video.test.tsx index 4727fcd..d9d36c8 100644 --- a/app/(tabs)/video.test.tsx +++ b/app/(tabs)/video.test.tsx @@ -41,6 +41,12 @@ jest.mock('@/components/icon', () => ({ WhiteStarIcon: 'WhiteStarIcon', })) +// Mock UI components +jest.mock('@/components/LoadingState', () => 'LoadingState') +jest.mock('@/components/ErrorState', () => 'ErrorState') +jest.mock('@/components/RefreshControl', () => 'RefreshControl') +jest.mock('@/components/PaginationLoader', () => 'PaginationLoader') + // Mock hooks jest.mock('@/hooks', () => ({ useTemplates: jest.fn(() => ({ diff --git a/app/(tabs)/video.tsx b/app/(tabs)/video.tsx index 334f9ec..4b513bc 100644 --- a/app/(tabs)/video.tsx +++ b/app/(tabs)/video.tsx @@ -7,8 +7,6 @@ import { FlatList, Pressable, StatusBar as RNStatusBar, - ActivityIndicator, - RefreshControl, Platform, } from 'react-native' import { StatusBar } from 'expo-status-bar' @@ -19,6 +17,10 @@ import { useTranslation } from 'react-i18next' import { SameStyleIcon, WhiteStarIcon } from '@/components/icon' import { useRouter } from 'expo-router' import { useTemplates, type TemplateDetail } from '@/hooks' +import LoadingState from '@/components/LoadingState' +import ErrorState from '@/components/ErrorState' +import RefreshControl from '@/components/RefreshControl' +import PaginationLoader from '@/components/PaginationLoader' const { width: screenWidth, height: screenHeight } = Dimensions.get('window') const TAB_BAR_HEIGHT = 83 @@ -38,23 +40,6 @@ const Layout = ({ children }: { children: React.ReactNode }) => ( ) -const LoadingState = () => ( - - - - 加载中... - - -) - -const ErrorState = () => ( - - - 加载失败,请下拉刷新重试 - - -) - const EmptyState = () => ( @@ -63,12 +48,6 @@ const EmptyState = () => ( ) -const FooterLoading = () => ( - - - -) - // 计算图片显示尺寸 const calculateImageSize = ( imageSize: { width: number; height: number } | null, @@ -207,8 +186,22 @@ export default function VideoScreen() { hasMore, }) - if (loading && templates.length === 0) return - if (error && templates.length === 0) return + if (loading && templates.length === 0) { + return ( + + + + ) + } + + if (error && templates.length === 0) { + return ( + + + + ) + } + if (!loading && filteredTemplates.length === 0) return return ( @@ -228,13 +221,11 @@ export default function VideoScreen() { } onEndReached={handleLoadMore} onEndReachedThreshold={0.1} - ListFooterComponent={loading ? : null} + ListFooterComponent={loading ? : null} maxToRenderPerBatch={5} windowSize={7} initialNumToRender={3} @@ -259,10 +250,6 @@ const styles = StyleSheet.create({ fontSize: 14, textAlign: 'center', }, - footerLoading: { - paddingVertical: 20, - alignItems: 'center', - }, videoContainer: { width: screenWidth, position: 'relative',