This commit is contained in:
imeepos 2025-12-26 18:26:11 +08:00
parent 935b1e92a3
commit 9afe55b2d9
2 changed files with 14 additions and 82 deletions

View File

@ -7,13 +7,11 @@ 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, RecommendedTemplate } 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'
const CATEGORY_ID = `cmjmpwop30009dhdpu3qyfvuo`
const BACKGROUND_VIDEOS = [
'https://cdn.roasmax.cn/material/b46f380532e14cf58dd350dbacc7c34a.mp4',
'https://cdn.roasmax.cn/material/992e6c5d940c42feb71c27e556b754c0.mp4',
@ -201,39 +199,6 @@ const TemplateItem = memo<TemplateItemProps>(function TemplateItem({ item, itemW
)
})
type CategoryChipProps = {
name: string
isSelected: boolean
onSelect: () => void
}
const CategoryChip = memo<CategoryChipProps>(function CategoryChip({ name, isSelected, onSelect }) {
return (
<Block
className={`skew-x-[-6deg] border-[2px] px-[12px] py-[4px] ${isSelected ? 'border-accent bg-accent' : 'border-black bg-white'}`}
onClick={onSelect}
>
<Text className={`text-[10px] font-[900] italic ${isSelected ? 'text-black' : 'text-black/60'}`}>{name}</Text>
</Block>
)
})
type CategoryFilterProps = {
categories: Array<{ id: string; name: string }>
selectedId: string
onSelect: (id: string) => void
}
const CategoryFilter = memo<CategoryFilterProps>(function CategoryFilter({ categories, selectedId, onSelect }) {
return (
<Block className="mt-[16px]">
<ScrollView horizontal showsHorizontalScrollIndicator={false} contentContainerStyle={{ gap: 8 }}>
<CategoryChip name="全部" isSelected={selectedId === ''} onSelect={() => onSelect('')} />
{categories.map((cat) => (
<CategoryChip key={cat.id} name={cat.name} isSelected={selectedId === cat.id} onSelect={() => onSelect(cat.id)} />
))}
</ScrollView>
</Block>
)
})
type TemplateSectionProps = {
templates: Template[]
@ -334,33 +299,19 @@ export default function Index() {
const [prompt, setPrompt] = useState(`${env} update`)
const [selectedTemplateId, setSelectedTemplateId] = useState('')
const [selectedCategoryId, setSelectedCategoryId] = useState('')
const [meImg, setMeImg] = useState('')
const [friendImg, setFriendImg] = useState('')
const [bgVideo] = useState(() => BACKGROUND_VIDEOS[Math.floor(Math.random() * BACKGROUND_VIDEOS.length)])
const recommendedTemplates = useRecommendedTemplates()
const categories = useCategories()
const templates = useTemplates()
useEffect(() => {
recommendedTemplates.execute({ isActive: true })
categories.load({ isActive: true })
templates.execute({ categoryId: CATEGORY_ID, page: 1, limit: 12, sortBy: 'createdAt', sortOrder: 'desc' })
}, [])
useEffect(() => {
const params = selectedCategoryId ? { categoryId: selectedCategoryId, isActive: true } : { isActive: true }
templates.execute(params)
}, [selectedCategoryId])
const displayTemplates = useMemo(() => {
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 = regular
return all.map((t: any): Template => ({
id: t.id,
name: t.title,
@ -368,14 +319,7 @@ export default function Index() {
type: 'video' as const,
data: t,
}))
}, [recommendedTemplates.data, templates.data, selectedCategoryId])
const categoryList = useMemo(() => {
return (categories.data?.categories || []).map((c) => ({
id: c.id,
name: c.name,
}))
}, [categories.data])
}, [templates.data])
const selectedTemplate = useMemo(() => {
return displayTemplates.find((t) => t.id === selectedTemplateId)
@ -413,25 +357,15 @@ export default function Index() {
setSelectedTemplateId(t.id)
}, [])
const handleSelectCategory = useCallback((id: string) => {
setSelectedCategoryId(id)
setSelectedTemplateId('')
}, [])
const onPickMe = useCallback(() => pickImage('me'), [pickImage])
const onPickFriend = useCallback(() => pickImage('friend'), [pickImage])
const isLoading = templates.loading || recommendedTemplates.loading
const hasError = templates.error || recommendedTemplates.error
const isLoading = templates.loading
const hasError = templates.error
const handleRetry = useCallback(() => {
if (selectedCategoryId) {
templates.refetch({ categoryId: selectedCategoryId, isActive: true })
} else {
recommendedTemplates.refetch({ isActive: true })
templates.refetch({ isActive: true })
}
}, [selectedCategoryId, templates, recommendedTemplates])
templates.refetch({ categoryId: CATEGORY_ID, page: 1, limit: 12, sortBy: 'createdAt', sortOrder: 'desc' })
}, [])
return (
<Block className="relative flex-1 flex-col overflow-visible bg-black">
@ -444,9 +378,6 @@ export default function Index() {
<Block className="px-16px relative z-10 flex-1">
<UploadSection meImg={meImg} friendImg={friendImg} onPickMe={onPickMe} onPickFriend={onPickFriend} />
<PromptSection prompt={prompt} onChangePrompt={setPrompt} />
{categoryList.length > 0 && (
<CategoryFilter categories={categoryList} selectedId={selectedCategoryId} onSelect={handleSelectCategory} />
)}
<TemplateSection
templates={displayTemplates}
selectedTemplateId={selectedTemplateId}

View File

@ -7,7 +7,6 @@ import { LinearGradient } from 'expo-linear-gradient'
import Animated, { Easing, useAnimatedStyle, useSharedValue, withRepeat, withTiming } from 'react-native-reanimated'
import { router, useRouter } from 'expo-router'
import { IOS_UNIVERSAL_LINK } from '@/app.constants'
import { FlashList } from '@shopify/flash-list'
import { screenHeight, screenWidth } from '@/utils'
import { cn } from '@/utils/cn'
@ -26,6 +25,8 @@ const BACKGROUND_VIDEOS = [
'https://cdn.roasmax.cn/material/e4947477843f4067be7c37569a33d17b.mp4',
]
const CATEGORY_ID = `cat_iw83x5bg54fmjgvciju`
type MediaItem = {
id: string
type: 'image' | 'video'
@ -406,7 +407,7 @@ export default function Sync() {
newItems = data.favorites.filter((fav: GetUserFavoritesResponse['favorites'][number]) => fav.template && !fav.template.isDeleted).map((fav: GetUserFavoritesResponse['favorites'][number]) => transformTemplateToMediaItem(fav.template!))
} else if (activeTab === 'new') {
if (isAuthenticated) {
const { data, error } = await loadTemplates({ limit, page: 1, sortBy: 'createdAt', sortOrder: 'desc' })
const { data, error } = await loadTemplates({ limit, page: 1, categoryId: CATEGORY_ID, sortBy: 'createdAt', sortOrder: 'desc' })
if (error || !data?.templates) {
setHasMore(false)
return
@ -423,7 +424,7 @@ export default function Sync() {
}
} else {
if (isAuthenticated) {
const { data, error } = await loadTemplates({ limit, page: 1, sortBy: 'likeCount', sortOrder: 'desc' })
const { data, error } = await loadTemplates({ limit, page: 1, categoryId: CATEGORY_ID, sortBy: 'likeCount', sortOrder: 'desc' })
if (error || !data?.templates) {
setHasMore(false)
return
@ -490,7 +491,7 @@ export default function Sync() {
setHasMore(false)
return
}
const { data, error } = await loadTemplates({ limit, page: pageNum, sortBy: 'createdAt', sortOrder: 'desc' })
const { data, error } = await loadTemplates({ limit, page: pageNum, categoryId: CATEGORY_ID, sortBy: 'createdAt', sortOrder: 'desc' })
if (error || !data?.templates) {
setHasMore(false)
return
@ -501,7 +502,7 @@ export default function Sync() {
setHasMore(false)
return
}
const { data, error } = await loadTemplates({ limit, page: pageNum, sortBy: 'likeCount', sortOrder: 'desc' })
const { data, error } = await loadTemplates({ limit, page: pageNum, categoryId: CATEGORY_ID, sortBy: 'likeCount', sortOrder: 'desc' })
if (error || !data?.templates) {
setHasMore(false)
return