expo-popcore-app/app/templateDetail.tsx

175 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect } from 'react'
import {
View,
Text,
StyleSheet,
Pressable,
StatusBar as RNStatusBar,
ActivityIndicator,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useRouter, useLocalSearchParams } from 'expo-router'
import { useTranslation } from 'react-i18next'
import { LeftArrowIcon } from '@/components/icon'
import SearchResultsGrid from '@/components/SearchResultsGrid'
import { useTemplateDetail, useTemplateGenerations, type TemplateGeneration } from '@/hooks'
const CARD_HEIGHTS = [214, 236, 200, 220, 210, 225]
export default function TemplateDetailScreen() {
const { t } = useTranslation()
const router = useRouter()
const params = useLocalSearchParams()
const templateId = typeof params.id === 'string' ? params.id : undefined
const { data: templateDetail, loading: templateLoading, error: templateError, execute: loadTemplateDetail } = useTemplateDetail()
const { generations, loading: generationsLoading, execute: loadGenerations } = useTemplateGenerations()
useEffect(() => {
if (templateId) {
loadTemplateDetail({ id: templateId })
loadGenerations({ templateId, page: 1, limit: 20 })
}
}, [templateId, loadTemplateDetail, loadGenerations])
// 直接使用 TemplateGeneration 数据,只添加必要的 height 字段
const displayData = generations.map((generation, index) => ({
...generation,
height: CARD_HEIGHTS[index % CARD_HEIGHTS.length],
title: generation.template?.title || generation.template?.titleEn || '',
image: generation.resultUrl?.[0] || generation.originalUrl || '',
}))
if (templateLoading && !templateDetail) {
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<View style={styles.centerContainer}>
<ActivityIndicator size="large" color="#FFE500" />
</View>
</SafeAreaView>
)
}
if (templateError && !templateDetail) {
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
<View style={styles.centerContainer}>
<Text style={styles.errorText}></Text>
<Pressable style={styles.retryButton} onPress={() => router.back()}>
<Text style={styles.retryButtonText}></Text>
</Pressable>
</View>
</SafeAreaView>
)
}
return (
<SafeAreaView style={styles.container} edges={['top']}>
<StatusBar style="light" />
<RNStatusBar barStyle="light-content" />
{/* 顶部导航栏 */}
<View style={styles.header}>
<Pressable
onPress={() => router.back()}
style={styles.backButton}
>
<LeftArrowIcon />
</Pressable>
</View>
{/* 标题区域 */}
<View style={styles.titleSection}>
<Text style={styles.mainTitle}>
{templateDetail?.title || templateDetail?.titleEn || t('templateDetail.title')}
</Text>
<Text style={styles.subTitle}>
{t('templateDetail.subtitle')}
</Text>
</View>
{/* 加载更多指示器 */}
{generationsLoading && generations.length > 0 && (
<View style={styles.loadingMoreContainer}>
<ActivityIndicator size="small" color="#FFE500" />
<Text style={styles.loadingMoreText}>...</Text>
</View>
)}
<SearchResultsGrid results={displayData} />
</SafeAreaView>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
centerContainer: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
gap: 12,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingTop: 12,
paddingHorizontal: 12,
paddingBottom: 24,
},
backButton: {
padding: 4,
},
titleSection: {
paddingHorizontal: 12,
paddingBottom: 24,
},
mainTitle: {
color: '#F5F5F5',
fontSize: 20,
fontWeight: '500',
marginBottom: 4,
},
subTitle: {
color: '#ABABAB',
fontSize: 14,
fontWeight: '400',
},
errorText: {
color: '#FFFFFF',
fontSize: 14,
textAlign: 'center',
},
retryButton: {
backgroundColor: '#FF6699',
paddingHorizontal: 24,
paddingVertical: 12,
borderRadius: 8,
},
retryButtonText: {
color: '#FFFFFF',
fontSize: 14,
fontWeight: '600',
},
loadingMoreContainer: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
gap: 8,
paddingVertical: 16,
},
loadingMoreText: {
color: '#ABABAB',
fontSize: 12,
},
})