import React, { useEffect, useState } from 'react'
import {
View,
Text,
StyleSheet,
Dimensions,
Pressable,
StatusBar as RNStatusBar,
Alert,
ScrollView,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
import { Image } from 'expo-image'
import { useRouter, useLocalSearchParams } from 'expo-router'
import { useTranslation } from 'react-i18next'
import { LinearGradient } from 'expo-linear-gradient'
import { LeftArrowIcon, DeleteIcon, EditIcon, ChangeIcon, WhiteStarIcon } from '@/components/icon'
import { DeleteConfirmDialog } from '@/components/ui/delete-confirm-dialog'
import LoadingState from '@/components/LoadingState'
import ErrorState from '@/components/ErrorState'
import { VideoPlayer } from '@/components/ui/video'
import {
useGenerationDetail,
useDeleteGeneration,
useRerunGeneration,
useDownloadMedia,
} from '@/hooks'
const { width: screenWidth } = Dimensions.get('window')
export default function GenerationRecordScreen() {
const { t } = useTranslation()
const router = useRouter()
const params = useLocalSearchParams()
const generationId = params.id as string
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false)
const { data: generation, loading, error, execute } = useGenerationDetail()
const { deleteGeneration, loading: deleting } = useDeleteGeneration()
const { rerun, loading: rerunning } = useRerunGeneration()
const { download, loading: downloading, progress } = useDownloadMedia()
useEffect(() => {
if (generationId) {
execute({ id: generationId })
}
}, [generationId, execute])
const handleDelete = async () => {
if (!generation) return
const { error } = await deleteGeneration(generation.id)
if (error) {
Alert.alert(t('common.error'), error.message || t('generationRecord.deleteError'))
} else {
Alert.alert(t('common.success'), t('generationRecord.deleteSuccess'))
router.back()
}
setDeleteDialogOpen(false)
}
const handleRerun = async () => {
if (!generation) return
const { generationId: newGenerationId, error } = await rerun(generation.id)
if (error) {
Alert.alert(t('common.error'), error.message || t('generationRecord.rerunError'))
} else if (newGenerationId) {
Alert.alert(t('common.success'), t('generationRecord.rerunSuccess'))
// 跳转到新的生成记录详情页
router.replace({
pathname: '/generationRecord',
params: { id: newGenerationId },
})
}
}
const handleTryAgain = () => {
if (!generation?.template) return
router.push({
pathname: '/generateVideo' as any,
params: { templateId: generation.template.id },
})
}
const handleDownload = async () => {
if (!generation?.resultUrl?.[0]) return
const url = generation.resultUrl[0]
const mediaType = generation.type === 'VIDEO' ? 'video' : 'image'
const { success, error } = await download(url, mediaType)
if (success) {
Alert.alert(t('common.success'), t('generationRecord.downloadSuccess'))
} else {
const errorMessage = error === 'Permission denied'
? t('generationRecord.permissionDenied')
: t('generationRecord.downloadError')
Alert.alert(t('common.error'), errorMessage)
}
}
const getStatusText = (status: string) => {
switch (status?.toLowerCase()) {
case 'completed':
case 'success':
return t('generationRecord.statusCompleted')
case 'pending':
case 'processing':
return t('generationRecord.statusPending')
case 'failed':
case 'error':
return t('generationRecord.statusFailed')
default:
return status
}
}
const getStatusColor = (status: string) => {
switch (status?.toLowerCase()) {
case 'completed':
case 'success':
return '#4ADE80'
case 'pending':
case 'processing':
return '#FF9966'
case 'failed':
case 'error':
return '#FF6B6B'
default:
return '#8A8A8A'
}
}
const formatDate = (date: Date | string) => {
const d = new Date(date)
return d.toLocaleString()
}
if (!generationId) {
return (
router.back()}>
{t('generationRecord.title')}
)
}
if (loading) {
return (
router.back()}>
{t('generationRecord.title')}
)
}
if (error || !generation) {
return (
router.back()}>
{t('generationRecord.title')}
execute({ id: generationId })}
/>
)
}
const hasResult = generation.resultUrl && generation.resultUrl.length > 0
const isVideo = generation.type === 'VIDEO'
const resultUrl = generation.resultUrl?.[0]
return (
router.back()}>
{t('generationRecord.title')}
{/* 模板信息 */}
{generation.template?.title || t('generationRecord.aiVideo')}
{/* 生成结果预览 */}
{t('generationRecord.generationResult')}
{hasResult ? (
{isVideo ? (
) : (
)}
) : (
{t('generationRecord.noResult')}
)}
{/* 状态信息 */}
{t('generationRecord.status')}
{getStatusText(generation.status)}
{t('generationRecord.createdAt')}
{formatDate(generation.createdAt)}
{/* 操作按钮 */}
{/* 下载按钮 - 主要操作使用渐变色 */}
{hasResult && (
{downloading
? `${t('generationRecord.downloading')} ${Math.round(progress * 100)}%`
: t('generationRecord.download')}
)}
{/* 次要操作按钮行 */}
{/* 重新生成按钮 */}
{t('generationRecord.regenerate')}
{/* 再来一次按钮 */}
{generation.template && (
{t('generationRecord.reEdit')}
)}
{/* 删除按钮 */}
setDeleteDialogOpen(true)}
disabled={deleting}
>
)
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#090A0B',
},
scrollContent: {
paddingBottom: 40,
},
header: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 12,
paddingTop: 16,
paddingBottom: 20,
},
backButton: {
width: 22,
height: 22,
alignItems: 'center',
justifyContent: 'center',
},
headerTitle: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '600',
flex: 1,
textAlign: 'center',
},
headerSpacer: {
width: 22,
},
templateSection: {
flexDirection: 'row',
alignItems: 'center',
paddingHorizontal: 16,
marginBottom: 16,
gap: 8,
},
categoryIcon: {
width: 20,
height: 20,
alignItems: 'center',
justifyContent: 'center',
},
categoryText: {
color: '#F5F5F5',
fontSize: 16,
fontWeight: '600',
},
resultSection: {
paddingHorizontal: 12,
marginBottom: 20,
},
sectionTitle: {
color: '#8A8A8A',
fontSize: 13,
marginBottom: 12,
paddingHorizontal: 4,
},
mediaContainer: {
width: screenWidth - 24,
height: (screenWidth - 24) * 1.32,
borderRadius: 16,
overflow: 'hidden',
backgroundColor: '#1C1E22',
},
resultImage: {
width: '100%',
height: '100%',
},
noResultContainer: {
width: screenWidth - 24,
height: 200,
borderRadius: 16,
backgroundColor: '#1C1E22',
alignItems: 'center',
justifyContent: 'center',
},
noResultText: {
color: '#8A8A8A',
fontSize: 14,
},
infoSection: {
paddingHorizontal: 16,
marginBottom: 24,
gap: 12,
},
infoRow: {
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
infoLabel: {
color: '#8A8A8A',
fontSize: 14,
},
infoValue: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '500',
},
actionSection: {
paddingHorizontal: 12,
gap: 12,
},
// 主要按钮 - 渐变色
primaryButtonContainer: {
height: 48,
borderRadius: 12,
overflow: 'hidden',
},
gradientButton: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
borderRadius: 12,
},
primaryButtonText: {
color: '#FFFFFF',
fontSize: 16,
fontWeight: '600',
},
// 次要按钮行
secondaryButtonRow: {
flexDirection: 'row',
gap: 8,
},
secondaryButton: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
height: 48,
borderRadius: 12,
backgroundColor: '#262A31',
gap: 6,
},
secondaryButtonText: {
color: '#F5F5F5',
fontSize: 14,
fontWeight: '500',
},
deleteButton: {
width: 48,
height: 48,
borderRadius: 12,
backgroundColor: '#262A31',
alignItems: 'center',
justifyContent: 'center',
},
buttonDisabled: {
opacity: 0.5,
},
})