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 <noreply@anthropic.com>
This commit is contained in:
imeepos 2026-01-21 12:06:46 +08:00
parent 141ccabe06
commit e0a56710d0
2 changed files with 27 additions and 34 deletions

View File

@ -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(() => ({

View File

@ -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 }) => (
</SafeAreaView>
)
const LoadingState = () => (
<Layout>
<View style={styles.centerContainer}>
<ActivityIndicator size="large" color="#FFE500" />
<Text style={styles.messageText}>...</Text>
</View>
</Layout>
)
const ErrorState = () => (
<Layout>
<View style={styles.centerContainer}>
<Text style={styles.messageText}></Text>
</View>
</Layout>
)
const EmptyState = () => (
<Layout>
<View style={styles.centerContainer}>
@ -63,12 +48,6 @@ const EmptyState = () => (
</Layout>
)
const FooterLoading = () => (
<View style={styles.footerLoading}>
<ActivityIndicator size="small" color="#FFE500" />
</View>
)
// 计算图片显示尺寸
const calculateImageSize = (
imageSize: { width: number; height: number } | null,
@ -207,8 +186,22 @@ export default function VideoScreen() {
hasMore,
})
if (loading && templates.length === 0) return <LoadingState />
if (error && templates.length === 0) return <ErrorState />
if (loading && templates.length === 0) {
return (
<Layout>
<LoadingState color="#FFE500" message="加载中..." />
</Layout>
)
}
if (error && templates.length === 0) {
return (
<Layout>
<ErrorState message="加载失败,请下拉刷新重试" onRetry={handleRefresh} />
</Layout>
)
}
if (!loading && filteredTemplates.length === 0) return <EmptyState />
return (
@ -228,13 +221,11 @@ export default function VideoScreen() {
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor="#FFE500"
colors={['#FFE500']}
/>
}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.1}
ListFooterComponent={loading ? <FooterLoading /> : null}
ListFooterComponent={loading ? <PaginationLoader color="#FFE500" /> : 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',