This commit is contained in:
imeepos
2026-01-16 15:16:49 +08:00
parent fce99a57bf
commit dcdab410c6
11 changed files with 292 additions and 124 deletions

View File

@@ -9,6 +9,7 @@ import {
StatusBar as RNStatusBar,
ActivityIndicator,
RefreshControl,
Platform,
} from 'react-native'
import { StatusBar } from 'expo-status-bar'
import { SafeAreaView } from 'react-native-safe-area-context'
@@ -72,7 +73,6 @@ const calculateImageSize = (
const VideoItem = memo(({ item, videoHeight }: { item: TemplateDetail; videoHeight: number }) => {
const { t } = useTranslation()
const router = useRouter()
const [isPlaying, setIsPlaying] = useState(false)
const [imageSize, setImageSize] = useState<{ width: number; height: number } | null>(null)
const handleImageLoad = useCallback((event: ImageLoadEventData) => {
@@ -91,21 +91,19 @@ const VideoItem = memo(({ item, videoHeight }: { item: TemplateDetail; videoHeig
const imageStyle = calculateImageSize(imageSize, videoHeight)
// 优先使用 WebP 格式(支持动画),回退到普通预览图
const displayUrl = item.webpPreviewUrl || item.previewUrl
return (
<View style={[styles.videoContainer, { height: videoHeight }]}>
<View style={styles.videoWrapper}>
<Image
source={{ uri: item.previewUrl }}
style={imageStyle}
contentFit="contain"
onLoad={handleImageLoad}
/>
{!isPlaying && (
<Pressable style={styles.playButton} onPress={() => setIsPlaying(true)}>
<View style={styles.playIcon}>
<View style={styles.playTriangle} />
</View>
</Pressable>
{displayUrl && (
<Image
source={{ uri: displayUrl }}
style={imageStyle}
contentFit="contain"
onLoad={handleImageLoad}
/>
)}
<View style={styles.thumbnailContainer}>
<Image source={{ uri: item.coverImageUrl }} style={styles.thumbnail} contentFit="cover" />
@@ -126,11 +124,12 @@ const VideoItem = memo(({ item, videoHeight }: { item: TemplateDetail; videoHeig
export default function VideoScreen() {
const flatListRef = useRef<FlatList>(null)
const videoHeight = screenHeight - TAB_BAR_HEIGHT
const PAGE_SIZE = 10 // 每页10个数据
const { templates, loading, error, execute, refetch, loadMore, hasMore } = useTemplates({
sortBy: 'likeCount',
sortOrder: 'desc',
page: 1,
limit: 20,
limit: PAGE_SIZE,
})
const [refreshing, setRefreshing] = useState(false)
@@ -145,9 +144,14 @@ export default function VideoScreen() {
}, [refetch])
const handleLoadMore = useCallback(() => {
if (!hasMore || loading) return
console.log('onEndReached triggered', { hasMore, loading, templatesLength: templates.length })
if (!hasMore || loading) {
console.log('LoadMore blocked', { hasMore, loading })
return
}
console.log('Loading more...')
loadMore()
}, [hasMore, loading, loadMore])
}, [hasMore, loading, loadMore, templates.length])
const renderItem = useCallback(({ item }: { item: TemplateDetail }) => (
<VideoItem item={item} videoHeight={videoHeight} />
@@ -186,8 +190,11 @@ export default function VideoScreen() {
/>
}
onEndReached={handleLoadMore}
onEndReachedThreshold={0.5}
onEndReachedThreshold={0.1}
ListFooterComponent={loading ? <FooterLoading /> : null}
maxToRenderPerBatch={5}
windowSize={7}
initialNumToRender={3}
/>
</Layout>
)
@@ -223,31 +230,6 @@ const styles = StyleSheet.create({
alignItems: 'center',
justifyContent: 'center',
},
playButton: {
...StyleSheet.absoluteFillObject,
alignItems: 'center',
justifyContent: 'center',
backgroundColor: 'rgba(0, 0, 0, 0.3)',
},
playIcon: {
width: 56,
height: 56,
borderRadius: 28,
backgroundColor: 'rgba(255, 255, 255, 0.85)',
alignItems: 'center',
justifyContent: 'center',
},
playTriangle: {
width: 0,
height: 0,
borderLeftWidth: 18,
borderTopWidth: 11,
borderBottomWidth: 11,
borderLeftColor: '#000000',
borderTopColor: 'transparent',
borderBottomColor: 'transparent',
marginLeft: 3,
},
thumbnailContainer: {
position: 'absolute',
left: 12,