diff --git a/app/(tabs)/generate.tsx b/app/(tabs)/generate.tsx index 4ace44e..eae8e9f 100644 --- a/app/(tabs)/generate.tsx +++ b/app/(tabs)/generate.tsx @@ -1,19 +1,20 @@ -import React, { memo, useCallback, useMemo, useState, useEffect } from 'react' -import { Block, Text, Img, Input, VideoBox } from '@/@share/components' -import { imgPicker } from '@/@share/apis/imgPicker' -import Svg, { Defs, Pattern, Rect, Circle } from 'react-native-svg' +import { FontAwesome, Fontisto, Ionicons } from '@expo/vector-icons' +import { useRouter } from 'expo-router' +import React, { memo, useCallback, useEffect, useMemo, useState } from 'react' +import { ActivityIndicator } from 'react-native' import { ScrollView } from 'react-native-gesture-handler' import { useAnimatedStyle } from 'react-native-reanimated' -import { FontAwesome, Fontisto, Ionicons } from '@expo/vector-icons' -import { screenHeight, screenWidth } from '@/utils' -import { useRouter } from 'expo-router' -import { useRecommendedTemplates } from '@/hooks/data/use-recommended-templates' -import { useCategories } from '@/hooks/data/use-categories' -import { useTemplates } from '@/hooks/data/use-templates' -import { ActivityIndicator } from 'react-native' -import { ApiError } from '@/lib/types' import { useSafeAreaInsets } from 'react-native-safe-area-context' +import Svg, { Circle, Defs, Pattern, Rect } from 'react-native-svg' + +import { imgPicker } from '@/@share/apis/imgPicker' +import { Block, Img, Input, Text, VideoBox } from '@/@share/components' import BannerSection from '@/components/BannerSection' +import { useCategories } from '@/hooks/data/use-categories' +import { useRecommendedTemplates } from '@/hooks/data/use-recommended-templates' +import { useTemplates } from '@/hooks/data/use-templates' +import { type ApiError } from '@/lib/types' +import { screenHeight, screenWidth } from '@/utils' export default function Index() { const router = useRouter() @@ -43,7 +44,9 @@ export default function Index() { const recommended = recommendedTemplates.data?.templates || [] const regular = templates.data?.templates || [] - const all = selectedCategoryId ? regular : [...recommended.map((r: RecommendedTemplate) => r.template).filter(Boolean), ...regular] + const all = selectedCategoryId + ? regular + : [...recommended.map((r: RecommendedTemplate) => r.template).filter(Boolean), ...regular] return all.map( (t: any): Template => ({ @@ -128,17 +131,23 @@ export default function Index() {
- + - {categoryList.length > 0 && } + {categoryList.length > 0 && ( + + )} @@ -158,17 +167,17 @@ export default function Index() { type BannerProps = { bgVideo: string } const Banner = memo(function Banner({ bgVideo }) { return ( - - + + - + - - + + - + @@ -183,17 +192,17 @@ type HeaderProps = { onSearch: () => void } const Header = memo(function Header({ onSearch }) { return ( - - - 创造终端 + + + 创造终端 GEN_STUDIO - - + + ) @@ -210,26 +219,26 @@ const UploadCard = memo(function UploadCard({ variant, img, onP return ( {isMe ? ( - + ) : ( - + 朋友 )} - + {img ? ( - + ) : ( {isMe ? ( - + + ) : ( - + + )} @@ -251,8 +260,8 @@ type UploadSectionProps = { const UploadSection = memo(function UploadSection({ meImg, friendImg, onPickMe, onPickFriend }) { return ( - - + + ) }) @@ -263,21 +272,21 @@ type PromptSectionProps = { } const PromptSection = memo(function PromptSection({ prompt, onChangePrompt }) { return ( - + - - 提示词 + + 提示词 @@ -301,7 +310,7 @@ type TemplateItemProps = { const TemplateItem = memo(function TemplateItem({ item, itemWidth, isSelected, onSelect }) { return ( (function TemplateItem({ item, itemW }} onClick={onSelect} > - + {isSelected && } {isSelected && } - + {item.name} {item.type === 'video' && ( - - + + )} @@ -337,7 +346,7 @@ type CategoryChipProps = { const CategoryChip = memo(function CategoryChip({ name, isSelected, onSelect }) { return ( {name} @@ -346,17 +355,22 @@ const CategoryChip = memo(function CategoryChip({ name, isSel }) type CategoryFilterProps = { - categories: Array<{ id: string; name: string }> + categories: { id: string; name: string }[] selectedId: string onSelect: (id: string) => void } const CategoryFilter = memo(function CategoryFilter({ categories, selectedId, onSelect }) { return ( - - onSelect('')} /> + + onSelect('')} /> {categories.map((cat) => ( - onSelect(cat.id)} /> + onSelect(cat.id)} + /> ))} @@ -393,25 +407,32 @@ const TemplateSection = memo(function TemplateSection({ return ( - - + + 视频模版 - + 换一波 {loading ? ( - + ) : error ? ( 加载失败 {onRetry && ( - + 重试 )} @@ -424,7 +445,15 @@ const TemplateSection = memo(function TemplateSection({ {templates.map((item) => { const isSelected = selectedTemplateId === item.id - return onSelectTemplate(item)} /> + return ( + onSelectTemplate(item)} + /> + ) })} )} @@ -436,12 +465,12 @@ type GenerateSectionProps = { onGenerate: () => void } const GenerateSection = memo(function GenerateSection({ onGenerate }) { const insets = useSafeAreaInsets() return ( - + {/* 左侧文字 */} @@ -450,9 +479,9 @@ const GenerateSection = memo(function GenerateSection({ on {/* 右侧 Goo 标签 */} - - - 3 Goo + + + 3 Goo diff --git a/app/(tabs)/index.tsx b/app/(tabs)/index.tsx index c73d392..4e3615e 100644 --- a/app/(tabs)/index.tsx +++ b/app/(tabs)/index.tsx @@ -9,15 +9,21 @@ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from ' import { ActivityIndicator, RefreshControl, TextInput } from 'react-native' import BannerSection from '@/components/BannerSection' -import { useAigcTask } from '@/hooks/actions/use-aigc-task' +import { useTemplateActions } from '@/hooks/actions/use-template-actions' import { useAuth } from '@/hooks/core/use-auth' import { useUserBalance } from '@/hooks/core/use-user-balance' +import { useTemplates } from '@/hooks/data' import { useFavoriteTemplates } from '@/hooks/data/use-favorite-templates' import { usePublicTemplates } from '@/hooks/data/use-public-templates' -import { useTemplates } from '@/hooks/data/use-templates' import { screenWidth } from '@/utils' import { cn } from '@/utils/cn' +const BACKGROUND_VIDEOS = [ + 'https://cdn.roasmax.cn/material/b46f380532e14cf58dd350dbacc7c34a.mp4', + 'https://cdn.roasmax.cn/material/992e6c5d940c42feb71c27e556b754c0.mp4', + 'https://cdn.roasmax.cn/material/e4947477843f4067be7c37569a33d17b.mp4', +] + type MediaItem = { id: string type: 'image' | 'video' @@ -324,7 +330,7 @@ export default function Sync() { execute: loadPublicTemplates, } = usePublicTemplates() const { data: favoritesData, loading: favoritesLoading, execute: loadFavorites } = useFavoriteTemplates() - const { submitTask, startPolling } = useAigcTask() + const { runTemplate } = useTemplateActions() const [searchText, setSearchText] = useState('') @@ -365,7 +371,7 @@ export default function Sync() { useEffect(() => { if (isAuthenticated && user?.id) { - loadBalance(user.id) + loadBalance() } }, [isAuthenticated, user?.id]) @@ -604,39 +610,25 @@ export default function Sync() { onCancel={() => Toast.hideModal()} onConfirm={async () => { Toast.hideModal() - - const { taskId, error } = await submitTask({ - model_name: 'default', - prompt: `生成与 ${selectedItem.id} 相似的内容`, - img_url: selectedItem.url, + // 要传 扣费返回的凭证 + const { generationId, error } = await runTemplate({ + templateId: selectedItem.id, + data: {}, + originalUrl: selectedItem.url, }) - if (error) { - Toast.show({ title: `提交失败: ${error.message}` }) + if (error || !generationId) { + Toast.show({ title: error?.message || '生成失败' }) return } - if (taskId) { - Toast.show({ - title: '任务提交成功,正在生成中...', - duration: 30e3, - }) - startPolling( - taskId, - (result) => { - Toast.show({ title: '生成成功!' }) - if (user?.id) loadBalance(user.id) - }, - (error) => { - Toast.show({ title: `生成失败: ${error.message}` }) - }, - ) - } + Toast.show({ title: '生成成功!' }) + if (user?.id) loadBalance() }} />, {}, ) - }, [isAuthenticated, balance, selectedItem, submitTask, startPolling, user?.id, loadBalance]) + }, [isAuthenticated, balance, selectedItem, runTemplate, user?.id, loadBalance]) const openSearch = useCallback(() => setIsSearchOpen(true), []) const closeSearch = useCallback(() => { diff --git a/app/generateVideo.tsx b/app/generateVideo.tsx index 0fc9a02..e404113 100644 --- a/app/generateVideo.tsx +++ b/app/generateVideo.tsx @@ -176,7 +176,7 @@ export default function GenerateVideoScreen() { ]) if (user?.id) { - loadBalance(user.id) + loadBalance() } } diff --git a/app/generationRecord.tsx b/app/generationRecord.tsx index 2bd2e8e..a63b167 100644 --- a/app/generationRecord.tsx +++ b/app/generationRecord.tsx @@ -49,7 +49,7 @@ export default function GenerationRecordScreen() { useEffect(() => { if (user?.id) { - loadBalance(user.id) + loadBalance() } }, [user?.id]) @@ -110,7 +110,7 @@ export default function GenerationRecordScreen() { } else { Alert.alert('生成成功', '视频已生成完成') if (user?.id) { - loadBalance(user.id) + loadBalance() } if (newGeneration?.id) { router.replace({ @@ -315,7 +315,7 @@ const styles = StyleSheet.create({ alignItems: 'center', paddingHorizontal: 16, marginBottom: 8, - gap:4, + gap: 4, }, categoryIcon: { width: 16,