fix: bug
This commit is contained in:
parent
dcdab410c6
commit
76ce6fb1db
|
|
@ -1 +0,0 @@
|
||||||
{ "recommendations": ["expo.vscode-expo-tools"] }
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
{
|
|
||||||
"editor.codeActionsOnSave": {
|
|
||||||
"source.fixAll": "explicit",
|
|
||||||
"source.organizeImports": "explicit",
|
|
||||||
"source.sortMembers": "explicit"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,10 +1,12 @@
|
||||||
import { Image } from 'expo-image'
|
import { FlashList } from '@shopify/flash-list';
|
||||||
import { VideoView, useVideoPlayer } from 'expo-video'
|
import { Image } from 'expo-image';
|
||||||
import { LinearGradient } from 'expo-linear-gradient'
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
import { useRouter, useLocalSearchParams } from 'expo-router'
|
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||||
import { StatusBar } from 'expo-status-bar'
|
import { StatusBar } from 'expo-status-bar';
|
||||||
import { useEffect, useRef, useState } from 'react'
|
import { VideoView, useVideoPlayer } from 'expo-video';
|
||||||
import { useTranslation } from 'react-i18next'
|
import { memo as ReactMemo, useEffect, useRef, useState } from 'react';
|
||||||
|
import React from 'react';
|
||||||
|
import { useTranslation } from 'react-i18next';
|
||||||
import {
|
import {
|
||||||
Dimensions,
|
Dimensions,
|
||||||
Platform,
|
Platform,
|
||||||
|
|
@ -14,16 +16,70 @@ import {
|
||||||
StyleSheet,
|
StyleSheet,
|
||||||
Text,
|
Text,
|
||||||
View
|
View
|
||||||
} from 'react-native'
|
} from 'react-native';
|
||||||
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context'
|
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||||
|
|
||||||
import { DownArrowIcon, PointsIcon, SearchIcon, WhiteStarIcon } from '@/components/icon'
|
import { DownArrowIcon, PointsIcon, SearchIcon, WhiteStarIcon } from '@/components/icon';
|
||||||
import { HomeSkeleton } from '@/components/skeleton/HomeSkeleton'
|
import { HomeSkeleton } from '@/components/skeleton/HomeSkeleton';
|
||||||
import { useActivates } from '@/hooks/use-activates'
|
import { useActivates } from '@/hooks/use-activates';
|
||||||
import { useCategories } from '@/hooks/use-categories'
|
import { useCategories } from '@/hooks/use-categories';
|
||||||
|
|
||||||
const { width: screenWidth } = Dimensions.get('window')
|
const { width: screenWidth } = Dimensions.get('window')
|
||||||
|
|
||||||
|
// 卡片组件 - 使用 useCallback 缓存以优化 FlashList 性能
|
||||||
|
const Card = ReactMemo(({ card, cardWidth, t, onPress }: {
|
||||||
|
card: any
|
||||||
|
cardWidth: number
|
||||||
|
t: any
|
||||||
|
onPress: (id: string) => void
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<Pressable
|
||||||
|
style={[styles.card, { width: cardWidth }]}
|
||||||
|
onPress={() => onPress(card.id)}
|
||||||
|
>
|
||||||
|
<View
|
||||||
|
style={[
|
||||||
|
styles.cardImageContainer,
|
||||||
|
{ height: card.height || cardWidth * 1.2 },
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
{card.isVideo ? (
|
||||||
|
<VideoPreview source={card.image.uri} style={styles.cardImage} />
|
||||||
|
) : (
|
||||||
|
<Image
|
||||||
|
source={card.image}
|
||||||
|
style={styles.cardImage}
|
||||||
|
contentFit="cover"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<LinearGradient
|
||||||
|
colors={['rgba(17, 17, 17, 0)', 'rgba(17, 17, 17, 0.9)']}
|
||||||
|
start={{ x: 0, y: 0 }}
|
||||||
|
end={{ x: 0, y: 1 }}
|
||||||
|
style={styles.cardImageGradient}
|
||||||
|
/>
|
||||||
|
{card.isHot ? (
|
||||||
|
<View style={styles.hotBadge}>
|
||||||
|
<Text style={styles.hotEmoji}>🔥</Text>
|
||||||
|
<Text style={styles.hotText}>{t('home.hotTemplate')}</Text>
|
||||||
|
</View>
|
||||||
|
) : (
|
||||||
|
<View style={styles.hotBadge}>
|
||||||
|
<WhiteStarIcon />
|
||||||
|
<Text style={styles.hotText}>
|
||||||
|
{card.users}{t('home.peopleUsed')}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
)}
|
||||||
|
<Text style={styles.cardTitle} numberOfLines={1}>
|
||||||
|
{card.title}
|
||||||
|
</Text>
|
||||||
|
</View>
|
||||||
|
</Pressable>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
// 视频预览组件
|
// 视频预览组件
|
||||||
function VideoPreview({ source, style }: { source: string; style: any }) {
|
function VideoPreview({ source, style }: { source: string; style: any }) {
|
||||||
const player = useVideoPlayer(source, (player) => {
|
const player = useVideoPlayer(source, (player) => {
|
||||||
|
|
@ -332,7 +388,7 @@ export default function HomeScreen() {
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 内容网格 */}
|
{/* 内容网格 - 使用 FlashList 优化性能 */}
|
||||||
{!showLoading && !showEmptyState && !showEmptyTemplates && (
|
{!showLoading && !showEmptyState && !showEmptyTemplates && (
|
||||||
<View
|
<View
|
||||||
style={styles.gridContainer}
|
style={styles.gridContainer}
|
||||||
|
|
@ -341,61 +397,28 @@ export default function HomeScreen() {
|
||||||
setGridWidth(width)
|
setGridWidth(width)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{displayCardData.map((card, index) => (
|
<FlashList
|
||||||
<Pressable
|
data={displayCardData}
|
||||||
key={card.id}
|
renderItem={({ item, index }) => (
|
||||||
style={[
|
<Card
|
||||||
styles.card,
|
card={item}
|
||||||
{ width: cardWidth },
|
cardWidth={cardWidth}
|
||||||
index % 2 === 0 ? styles.cardLeft : styles.cardRight,
|
t={t}
|
||||||
]}
|
onPress={(id) => {
|
||||||
onPress={() => {
|
|
||||||
router.push({
|
router.push({
|
||||||
pathname: '/templateDetail' as any,
|
pathname: '/templateDetail' as any,
|
||||||
params: { id: card.id.toString() },
|
params: { id: id.toString() },
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
|
||||||
<View
|
|
||||||
style={[
|
|
||||||
styles.cardImageContainer,
|
|
||||||
{ height: card.height || cardWidth * 1.2 },
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
{card.isVideo ? (
|
|
||||||
<VideoPreview source={card.image.uri} style={styles.cardImage} />
|
|
||||||
) : (
|
|
||||||
<Image
|
|
||||||
source={card.image}
|
|
||||||
style={styles.cardImage}
|
|
||||||
contentFit="cover"
|
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<LinearGradient
|
keyExtractor={(item) => item.id}
|
||||||
colors={['rgba(17, 17, 17, 0)', 'rgba(17, 17, 17, 0.9)']}
|
numColumns={2}
|
||||||
start={{ x: 0, y: 0 }}
|
estimatedItemSize={cardWidth * 1.2 + 60}
|
||||||
end={{ x: 0, y: 1 }}
|
showsVerticalScrollIndicator={false}
|
||||||
style={styles.cardImageGradient}
|
contentContainerStyle={styles.flashListContent}
|
||||||
|
scrollEventThrottle={Platform.OS === 'ios' ? 16 : 50}
|
||||||
/>
|
/>
|
||||||
{card.isHot ? (
|
|
||||||
<View style={styles.hotBadge}>
|
|
||||||
<Text style={styles.hotEmoji}>🔥</Text>
|
|
||||||
<Text style={styles.hotText}>{t('home.hotTemplate')}</Text>
|
|
||||||
</View>
|
|
||||||
) : (
|
|
||||||
<View style={styles.hotBadge}>
|
|
||||||
<WhiteStarIcon />
|
|
||||||
<Text style={styles.hotText}>
|
|
||||||
{card.users}{t('home.peopleUsed')}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
)}
|
|
||||||
<Text style={styles.cardTitle} numberOfLines={1}>
|
|
||||||
{card.title}
|
|
||||||
</Text>
|
|
||||||
</View>
|
|
||||||
</Pressable>
|
|
||||||
))}
|
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
@ -622,12 +645,10 @@ const styles = StyleSheet.create({
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
marginBottom: 12,
|
marginBottom: 12,
|
||||||
|
paddingHorizontal: 5,
|
||||||
},
|
},
|
||||||
cardLeft: {
|
flashListContent: {
|
||||||
marginRight: 0,
|
gap: 10,
|
||||||
},
|
|
||||||
cardRight: {
|
|
||||||
marginLeft: 0,
|
|
||||||
},
|
},
|
||||||
cardImageContainer: {
|
cardImageContainer: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
|
|
|
||||||
7
bun.lock
7
bun.lock
|
|
@ -15,6 +15,7 @@
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
"@repo/core": "1.0.2",
|
"@repo/core": "1.0.2",
|
||||||
"@repo/sdk": "1.0.7",
|
"@repo/sdk": "1.0.7",
|
||||||
|
"@shopify/flash-list": "^1.7.3",
|
||||||
"@stripe/react-stripe-js": "^5.4.1",
|
"@stripe/react-stripe-js": "^5.4.1",
|
||||||
"@stripe/stripe-js": "^8.5.3",
|
"@stripe/stripe-js": "^8.5.3",
|
||||||
"@stripe/stripe-react-native": "^0.57.0",
|
"@stripe/stripe-react-native": "^0.57.0",
|
||||||
|
|
@ -631,6 +632,8 @@
|
||||||
|
|
||||||
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
|
"@rtsao/scc": ["@rtsao/scc@1.1.0", "", {}, "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g=="],
|
||||||
|
|
||||||
|
"@shopify/flash-list": ["@shopify/flash-list@1.8.3", "", { "dependencies": { "recyclerlistview": "4.2.3", "tslib": "2.8.1" }, "peerDependencies": { "@babel/runtime": "*", "react": "*", "react-native": "*" } }, "sha512-vXuj6JyuMjONVOXjEhWFeaONPuWN/53Cl2LeyeM8TZ0JzUcNU+BE6iyga1/yyJeDf0K7YPgAE/PcUX2+DM1LiA=="],
|
||||||
|
|
||||||
"@simplewebauthn/browser": ["@simplewebauthn/browser@13.2.2", "", {}, "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA=="],
|
"@simplewebauthn/browser": ["@simplewebauthn/browser@13.2.2", "", {}, "sha512-FNW1oLQpTJyqG5kkDg5ZsotvWgmBaC6jCHR7Ej0qUNep36Wl9tj2eZu7J5rP+uhXgHaLk+QQ3lqcw2vS5MX1IA=="],
|
||||||
|
|
||||||
"@simplewebauthn/server": ["@simplewebauthn/server@13.2.2", "", { "dependencies": { "@hexagon/base64": "^1.1.27", "@levischuck/tiny-cbor": "^0.2.2", "@peculiar/asn1-android": "^2.3.10", "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-x509": "^2.3.8", "@peculiar/x509": "^1.13.0" } }, "sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA=="],
|
"@simplewebauthn/server": ["@simplewebauthn/server@13.2.2", "", { "dependencies": { "@hexagon/base64": "^1.1.27", "@levischuck/tiny-cbor": "^0.2.2", "@peculiar/asn1-android": "^2.3.10", "@peculiar/asn1-ecc": "^2.3.8", "@peculiar/asn1-rsa": "^2.3.8", "@peculiar/asn1-schema": "^2.3.8", "@peculiar/asn1-x509": "^2.3.8", "@peculiar/x509": "^1.13.0" } }, "sha512-HcWLW28yTMGXpwE9VLx9J+N2KEUaELadLrkPEEI9tpI5la70xNEVEsu/C+m3u7uoq4FulLqZQhgBCzR9IZhFpA=="],
|
||||||
|
|
@ -1823,6 +1826,8 @@
|
||||||
|
|
||||||
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
"readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="],
|
||||||
|
|
||||||
|
"recyclerlistview": ["recyclerlistview@4.2.3", "", { "dependencies": { "lodash.debounce": "4.0.8", "prop-types": "15.8.1", "ts-object-utils": "0.0.5" }, "peerDependencies": { "react": ">= 15.2.1", "react-native": ">= 0.30.0" } }, "sha512-STR/wj/FyT8EMsBzzhZ1l2goYirMkIgfV3gYEPxI3Kf3lOnu6f7Dryhyw7/IkQrgX5xtTcDrZMqytvteH9rL3g=="],
|
||||||
|
|
||||||
"reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="],
|
"reflect-metadata": ["reflect-metadata@0.2.2", "", {}, "sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q=="],
|
||||||
|
|
||||||
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
"reflect.getprototypeof": ["reflect.getprototypeof@1.0.10", "", { "dependencies": { "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-abstract": "^1.23.9", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", "get-intrinsic": "^1.2.7", "get-proto": "^1.0.1", "which-builtin-type": "^1.2.1" } }, "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw=="],
|
||||||
|
|
@ -2035,6 +2040,8 @@
|
||||||
|
|
||||||
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
|
"ts-interface-checker": ["ts-interface-checker@0.1.13", "", {}, "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="],
|
||||||
|
|
||||||
|
"ts-object-utils": ["ts-object-utils@0.0.5", "", {}, "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA=="],
|
||||||
|
|
||||||
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
|
"tsconfig-paths": ["tsconfig-paths@3.15.0", "", { "dependencies": { "@types/json5": "^0.0.29", "json5": "^1.0.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" } }, "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg=="],
|
||||||
|
|
||||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,7 @@
|
||||||
"@react-navigation/bottom-tabs": "^7.4.0",
|
"@react-navigation/bottom-tabs": "^7.4.0",
|
||||||
"@react-navigation/elements": "^2.6.3",
|
"@react-navigation/elements": "^2.6.3",
|
||||||
"@react-navigation/native": "^7.1.8",
|
"@react-navigation/native": "^7.1.8",
|
||||||
|
"@shopify/flash-list": "^1.7.3",
|
||||||
"@stripe/react-stripe-js": "^5.4.1",
|
"@stripe/react-stripe-js": "^5.4.1",
|
||||||
"@stripe/stripe-js": "^8.5.3",
|
"@stripe/stripe-js": "^8.5.3",
|
||||||
"@stripe/stripe-react-native": "^0.57.0",
|
"@stripe/stripe-react-native": "^0.57.0",
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue