import { View, StyleSheet, ScrollView, TouchableOpacity, Share, Alert, Dimensions } from 'react-native'; import { ThemedView } from '@/components/themed-view'; import { ThemedText } from '@/components/themed-text'; import { TemplateGeneration } from '@/lib/types/template-run'; import { Image } from 'expo-image'; import { VideoPlayer } from '@/components/video/video-player'; import { useState } from 'react'; import * as FileSystem from 'expo-file-system'; import * as MediaLibrary from 'expo-media-library'; interface ResultDisplayProps { result: TemplateGeneration; onShare?: (url: string) => void; onDownload?: (url: string) => void; onRerun?: () => void; } const { width: screenWidth } = Dimensions.get('window'); export function ResultDisplay({ result, onShare, onDownload, onRerun }: ResultDisplayProps) { const [downloadingItems, setDownloadingItems] = useState>(new Set()); const [sharing, setSharing] = useState(false); const getTypeLabel = () => { switch (result.type) { case 'IMAGE': return '图片生成结果'; case 'VIDEO': return '视频生成结果'; case 'TEXT': return '文本生成结果'; default: return '生成结果'; } }; const getTypeIcon = () => { switch (result.type) { case 'IMAGE': return '🖼️'; case 'VIDEO': return '🎬'; case 'TEXT': return '📝'; default: return '📄'; } }; const handleShare = async (url: string) => { if (sharing) return; try { setSharing(true); if (onShare) { onShare(url); return; } await Share.share({ message: `查看生成的${result.type === 'IMAGE' ? '图片' : result.type === 'VIDEO' ? '视频' : '文本'}: ${url}`, url: url, }); } catch (error) { console.error('分享失败:', error); Alert.alert('分享失败', '无法分享此内容,请稍后重试'); } finally { setSharing(false); } }; const handleDownload = async (url: string, index: number) => { if (downloadingItems.has(index)) return; try { setDownloadingItems(prev => new Set(prev).add(index)); if (onDownload) { onDownload(url); return; } // 请求媒体库权限 const { status } = await MediaLibrary.requestPermissionsAsync(); if (status !== 'granted') { Alert.alert('权限请求', '需要媒体库权限才能保存文件'); return; } // 下载文件 const targetDirectory = FileSystem.Paths.document ?? FileSystem.Paths.cache; const destination = new FileSystem.File( targetDirectory, `generated_${Date.now()}_${index}.${getFileExtension(url)}` ); const downloadResult = await FileSystem.File.downloadFileAsync(url, destination); // 保存到媒体库 if (result.type === 'IMAGE') { await MediaLibrary.saveToLibraryAsync(downloadResult.uri); Alert.alert('保存成功', '图片已保存到相册'); } else if (result.type === 'VIDEO') { await MediaLibrary.saveToLibraryAsync(downloadResult.uri); Alert.alert('保存成功', '视频已保存到相册'); } } catch (error) { console.error('下载失败:', error); Alert.alert('下载失败', '无法保存文件,请检查网络连接'); } finally { setDownloadingItems(prev => { const newSet = new Set(prev); newSet.delete(index); return newSet; }); } }; const getFileExtension = (url: string): string => { const parts = url.split('.'); return parts[parts.length - 1] || 'jpg'; }; const renderMediaItem = (url: string, index: number) => { const isVideo = /\.(mp4|webm|ogg|mov|avi|mkv|flv)$/i.test(url); if (isVideo) { return ( { console.log(`视频 ${index} 加载完成:`, status); }} onError={(error) => { console.error(`视频 ${index} 加载失败:`, error); }} /> handleShare(url)} disabled={sharing} activeOpacity={0.8} > {sharing ? '分享中...' : '分享'} handleDownload(url, index)} disabled={downloadingItems.has(index)} activeOpacity={0.8} > {downloadingItems.has(index) ? '下载中...' : '下载'} ); } return ( handleShare(url)} disabled={sharing} activeOpacity={0.8} > {sharing ? '分享中...' : '分享'} handleDownload(url, index)} disabled={downloadingItems.has(index)} activeOpacity={0.8} > {downloadingItems.has(index) ? '下载中...' : '下载'} ); }; const renderTextContent = (url: string, index: number) => { return ( {url} handleShare(url)} disabled={sharing} activeOpacity={0.8} > {sharing ? '分享中...' : '分享'} { // 这里可以实现复制文本到剪贴板的功能 Alert.alert('复制成功', '文本已复制到剪贴板'); }} activeOpacity={0.8} > 复制 ); }; return ( {/* 结果头部 */} {getTypeIcon()} {getTypeLabel()} 文件数量 {result.resultUrl.length} {result.creditsCost && ( 消耗积分 {result.creditsCost} )} {/* 结果内容 */} {result.resultUrl.length === 0 ? ( 暂无生成结果 ) : ( result.resultUrl.map((url, index) => { if (result.type === 'TEXT') { return renderTextContent(url, index); } else { return renderMediaItem(url, index); } }) )} {/* 操作按钮 */} {onRerun && ( 🔄 重新生成 )} ); } const styles = StyleSheet.create({ container: { flex: 1, }, content: { padding: 20, }, header: { marginBottom: 24, }, titleContainer: { flexDirection: 'row', alignItems: 'center', marginBottom: 16, }, titleIcon: { fontSize: 24, marginRight: 8, }, title: { fontSize: 20, fontWeight: '600', }, stats: { flexDirection: 'row', gap: 20, }, statItem: { flex: 1, backgroundColor: 'rgba(0, 0, 0, 0.05)', borderRadius: 12, padding: 12, alignItems: 'center', }, statLabel: { fontSize: 12, opacity: 0.7, marginBottom: 4, }, statValue: { fontSize: 18, fontWeight: '600', }, results: { marginBottom: 24, }, emptyContainer: { alignItems: 'center', paddingVertical: 32, }, emptyText: { fontSize: 16, opacity: 0.6, }, mediaContainer: { marginBottom: 20, }, image: { width: '100%', height: screenWidth * 0.75, borderRadius: 12, backgroundColor: '#f0f0f0', }, mediaActions: { flexDirection: 'row', gap: 12, marginTop: 12, }, textContainer: { marginBottom: 20, }, textBox: { backgroundColor: 'rgba(0, 0, 0, 0.05)', borderRadius: 12, padding: 16, marginBottom: 12, minHeight: 100, }, textContent: { fontSize: 16, lineHeight: 24, }, textActions: { flexDirection: 'row', gap: 12, }, actionButton: { flex: 1, borderRadius: 8, paddingVertical: 12, paddingHorizontal: 16, alignItems: 'center', }, shareButton: { backgroundColor: 'rgba(0, 122, 255, 0.1)', borderWidth: 1, borderColor: 'rgba(0, 122, 255, 0.3)', }, downloadButton: { backgroundColor: 'rgba(52, 199, 89, 0.1)', borderWidth: 1, borderColor: 'rgba(52, 199, 89, 0.3)', }, copyButton: { backgroundColor: 'rgba(142, 142, 147, 0.1)', borderWidth: 1, borderColor: 'rgba(142, 142, 147, 0.3)', }, actionButtonText: { fontSize: 14, fontWeight: '600', }, footerActions: { alignItems: 'center', paddingTop: 20, borderTopWidth: 1, borderTopColor: 'rgba(0, 0, 0, 0.1)', }, rerunButton: { backgroundColor: 'rgba(78, 205, 196, 0.1)', borderRadius: 8, paddingVertical: 14, paddingHorizontal: 32, borderWidth: 1, borderColor: 'rgba(78, 205, 196, 0.3)', }, rerunButtonText: { fontSize: 16, fontWeight: '600', color: '#4ECDC4', }, });