|
|
@ -1,4 +1,4 @@ |
|
|
|
import React, { useCallback, useState, useRef, useEffect } from "react"; |
|
|
|
import React, { useCallback, useState, useRef, useEffect, useMemo } from "react"; |
|
|
|
import { |
|
|
|
import { |
|
|
|
View, |
|
|
|
View, |
|
|
|
Text, |
|
|
|
Text, |
|
|
@ -42,6 +42,7 @@ import useUserStore from "../store/user"; |
|
|
|
import * as ImagePicker from "expo-image-picker"; |
|
|
|
import * as ImagePicker from "expo-image-picker"; |
|
|
|
import * as FileSystem from "expo-file-system"; |
|
|
|
import * as FileSystem from "expo-file-system"; |
|
|
|
import { useGlobalStore } from "../store/useGlobalStore"; |
|
|
|
import { useGlobalStore } from "../store/useGlobalStore"; |
|
|
|
|
|
|
|
import { getCurrentLanguage } from '../i18n'; |
|
|
|
// 为图标定义类型
|
|
|
|
// 为图标定义类型
|
|
|
|
type IconProps = { |
|
|
|
type IconProps = { |
|
|
|
name: string; |
|
|
|
name: string; |
|
|
@ -316,27 +317,11 @@ export const HomeScreen = () => { |
|
|
|
const [showCategoryModal, setShowCategoryModal] = useState(false); |
|
|
|
const [showCategoryModal, setShowCategoryModal] = useState(false); |
|
|
|
const [showImagePickerModal, setShowImagePickerModal] = useState(false); |
|
|
|
const [showImagePickerModal, setShowImagePickerModal] = useState(false); |
|
|
|
const [selectedCategory, setSelectedCategory] = useState("Bijoux"); |
|
|
|
const [selectedCategory, setSelectedCategory] = useState("Bijoux"); |
|
|
|
const [selectedHorizontalCategory, setSelectedHorizontalCategory] = |
|
|
|
const [selectedHorizontalCategory, setSelectedHorizontalCategory] = useState("Tous"); |
|
|
|
useState("Tous"); |
|
|
|
|
|
|
|
const [refreshing, setRefreshing] = useState(false); |
|
|
|
|
|
|
|
const [loading, setLoading] = useState(true); // 添加加载状态
|
|
|
|
|
|
|
|
const horizontalScrollRef = useRef<ScrollView>(null); |
|
|
|
|
|
|
|
const userStore = useUserStore(); |
|
|
|
const userStore = useUserStore(); |
|
|
|
const [searchParams, setSearchParams] = useState<ProductParams>({ |
|
|
|
const { country, currency } = useGlobalStore(); |
|
|
|
keyword: "pen", |
|
|
|
|
|
|
|
page: 1, |
|
|
|
|
|
|
|
page_size: 10, |
|
|
|
|
|
|
|
sort_order: "desc", |
|
|
|
|
|
|
|
sort_by: "default", |
|
|
|
|
|
|
|
language: "en", |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
const [products, setProducts] = useState<Product[]>([]); |
|
|
|
|
|
|
|
const [hasMore, setHasMore] = useState(true); |
|
|
|
|
|
|
|
const [isLoadingMore, setIsLoadingMore] = useState(false); |
|
|
|
|
|
|
|
const [totalProducts, setTotalProducts] = useState(0); |
|
|
|
|
|
|
|
const [initialLoadComplete, setInitialLoadComplete] = useState(false); |
|
|
|
|
|
|
|
const [currentPage, setCurrentPage] = useState(1); // 添加当前页码状态
|
|
|
|
|
|
|
|
const flatListRef = useRef<FlatList>(null); |
|
|
|
const flatListRef = useRef<FlatList>(null); |
|
|
|
|
|
|
|
const horizontalScrollRef = useRef<ScrollView>(null); |
|
|
|
const data = [ |
|
|
|
const data = [ |
|
|
|
{ |
|
|
|
{ |
|
|
|
imgUrl: require("../../assets/img/banner en (5)_compressed.png"), |
|
|
|
imgUrl: require("../../assets/img/banner en (5)_compressed.png"), |
|
|
@ -351,95 +336,221 @@ export const HomeScreen = () => { |
|
|
|
add: "CompanyScreen", |
|
|
|
add: "CompanyScreen", |
|
|
|
}, |
|
|
|
}, |
|
|
|
]; |
|
|
|
]; |
|
|
|
const [galleryUsed, setGalleryUsed] = useState(false); // 标记是否使用过相册
|
|
|
|
const [galleryUsed, setGalleryUsed] = useState(false); |
|
|
|
const [loadingPlaceholders, setLoadingPlaceholders] = useState(0); // 添加占位符数量状态
|
|
|
|
const [hotTerms, setHotTerms] = useState<string[]>([]); |
|
|
|
const getProductData = async (isLoadMore = false) => { |
|
|
|
const [isLoadingHotTerms, setIsLoadingHotTerms] = useState(false); |
|
|
|
if (isLoadMore) { |
|
|
|
|
|
|
|
setIsLoadingMore(true); |
|
|
|
// 直接在组件中实现分页加载逻辑
|
|
|
|
|
|
|
|
const [products, setProducts] = useState<Product[]>([]); |
|
|
|
|
|
|
|
const [loading, setLoading] = useState(true); |
|
|
|
|
|
|
|
const [loadingMore, setLoadingMore] = useState(false); |
|
|
|
|
|
|
|
const [hasMore, setHasMore] = useState(true); |
|
|
|
|
|
|
|
const [refreshing, setRefreshing] = useState(false); |
|
|
|
|
|
|
|
const [currentPage, setCurrentPage] = useState(1); |
|
|
|
|
|
|
|
const [loadingPlaceholders, setLoadingPlaceholders] = useState(0); |
|
|
|
|
|
|
|
const [totalItems, setTotalItems] = useState(0); |
|
|
|
|
|
|
|
const [params, setParams] = useState<ProductParams>({ |
|
|
|
|
|
|
|
keyword: "pen", // 初始关键词,将在获取热门关键词后更新
|
|
|
|
|
|
|
|
sort_order: "desc", |
|
|
|
|
|
|
|
sort_by: "default", |
|
|
|
|
|
|
|
language: getCurrentLanguage(), |
|
|
|
|
|
|
|
page: 1, |
|
|
|
|
|
|
|
page_size: 10, |
|
|
|
|
|
|
|
...(userStore.user?.user_id ? { user_id: userStore.user.user_id } : {}), |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取热门关键词并初始化产品列表
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
const initApp = async () => { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
// 获取热门关键词
|
|
|
|
|
|
|
|
const response = await productApi.getHotTerms(); |
|
|
|
|
|
|
|
const terms = response.terms || []; |
|
|
|
|
|
|
|
setHotTerms(terms); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 如果获取到了热门关键词,使用随机关键词
|
|
|
|
|
|
|
|
if (terms.length > 0) { |
|
|
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * terms.length); |
|
|
|
|
|
|
|
const randomKeyword = terms[randomIndex]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 更新参数
|
|
|
|
|
|
|
|
setParams(prev => ({ |
|
|
|
|
|
|
|
...prev, |
|
|
|
|
|
|
|
keyword: randomKeyword |
|
|
|
|
|
|
|
})); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取第一页数据
|
|
|
|
|
|
|
|
await fetchInitialProducts(randomKeyword); |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
setLoading(true); |
|
|
|
// 如果没有热门关键词,使用默认关键词"pen"
|
|
|
|
|
|
|
|
await fetchInitialProducts("pen"); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
console.error("初始化失败:", error); |
|
|
|
|
|
|
|
// 出错时使用默认关键词
|
|
|
|
|
|
|
|
await fetchInitialProducts("pen"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
initApp(); |
|
|
|
|
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取随机关键词
|
|
|
|
|
|
|
|
const getRandomKeyword = useCallback(() => { |
|
|
|
|
|
|
|
if (hotTerms.length === 0) return "pen"; |
|
|
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * hotTerms.length); |
|
|
|
|
|
|
|
const keyword = hotTerms[randomIndex]; |
|
|
|
|
|
|
|
console.log("获取随机关键词:", keyword); |
|
|
|
|
|
|
|
return keyword; |
|
|
|
|
|
|
|
}, [hotTerms]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取初始产品数据(第一页及额外的三页)
|
|
|
|
|
|
|
|
const fetchInitialProducts = useCallback(async (keyword: string) => { |
|
|
|
|
|
|
|
setLoading(true); |
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
try { |
|
|
|
const currentParams = { |
|
|
|
// 第一页请求参数
|
|
|
|
...searchParams, |
|
|
|
const initialParams = { |
|
|
|
page: isLoadMore ? currentPage + 1 : 1, |
|
|
|
...params, |
|
|
|
...(userStore.user?.user_id ? { user_id: userStore.user.user_id } : {}), |
|
|
|
keyword, |
|
|
|
|
|
|
|
page: 1, |
|
|
|
|
|
|
|
page_size: 10 |
|
|
|
}; |
|
|
|
}; |
|
|
|
const res = await productApi.getSearchProducts(currentParams); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setTotalProducts(res.total || 0); |
|
|
|
// 获取第一页数据
|
|
|
|
|
|
|
|
const firstPageRes = await productApi.getSearchProducts(initialParams); |
|
|
|
|
|
|
|
setProducts(firstPageRes.products); |
|
|
|
|
|
|
|
setTotalItems(firstPageRes.total || 0); |
|
|
|
|
|
|
|
|
|
|
|
if (isLoadMore) { |
|
|
|
if (hotTerms.length > 0) { |
|
|
|
setProducts(prev => [...prev, ...res.products]); |
|
|
|
// 存储已使用的关键词,避免重复
|
|
|
|
setCurrentPage(prev => prev + 1); |
|
|
|
const usedKeywords = new Set([keyword]); |
|
|
|
} else { |
|
|
|
|
|
|
|
setProducts(res.products); |
|
|
|
// 创建获取唯一关键词的函数
|
|
|
|
setCurrentPage(1); |
|
|
|
const getUniqueKeyword = () => { |
|
|
|
|
|
|
|
// 如果热门关键词数量不足,或者已经用完所有关键词,返回随机关键词
|
|
|
|
|
|
|
|
if (hotTerms.length <= usedKeywords.size || hotTerms.length <= 1) { |
|
|
|
|
|
|
|
return hotTerms[Math.floor(Math.random() * hotTerms.length)]; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const currentTotal = isLoadMore ? products.length + res.products.length : res.products.length; |
|
|
|
// 尝试获取未使用过的关键词
|
|
|
|
setHasMore(currentTotal < (res.total || 0)); |
|
|
|
let attempts = 0; |
|
|
|
|
|
|
|
while (attempts < 10) { // 最多尝试10次
|
|
|
|
|
|
|
|
const randomIndex = Math.floor(Math.random() * hotTerms.length); |
|
|
|
|
|
|
|
const candidateKeyword = hotTerms[randomIndex]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!usedKeywords.has(candidateKeyword)) { |
|
|
|
|
|
|
|
usedKeywords.add(candidateKeyword); |
|
|
|
|
|
|
|
return candidateKeyword; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (!isLoadMore && !initialLoadComplete) { |
|
|
|
attempts++; |
|
|
|
setInitialLoadComplete(true); |
|
|
|
} |
|
|
|
const remainingParams = { |
|
|
|
|
|
|
|
...currentParams, |
|
|
|
// 如果无法找到唯一关键词,返回随机关键词
|
|
|
|
page: 2, |
|
|
|
return hotTerms[Math.floor(Math.random() * hotTerms.length)]; |
|
|
|
page_size: 30 |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用不同关键词加载额外的3页数据
|
|
|
|
|
|
|
|
const remainingRequests = Array.from({ length: 3 }, async (_, index) => { |
|
|
|
|
|
|
|
// 获取唯一的随机关键词
|
|
|
|
|
|
|
|
const pageKeyword = getUniqueKeyword(); |
|
|
|
|
|
|
|
const pageParams = { |
|
|
|
|
|
|
|
...params, |
|
|
|
|
|
|
|
keyword: pageKeyword, |
|
|
|
|
|
|
|
page: index + 2, |
|
|
|
|
|
|
|
page_size: 10 |
|
|
|
}; |
|
|
|
}; |
|
|
|
const remainingRes = await productApi.getSearchProducts(remainingParams); |
|
|
|
return productApi.getSearchProducts(pageParams); |
|
|
|
setProducts(prev => { |
|
|
|
|
|
|
|
const newProducts = [...prev, ...remainingRes.products]; |
|
|
|
|
|
|
|
setHasMore(newProducts.length < (res.total || 0)); |
|
|
|
|
|
|
|
return newProducts; |
|
|
|
|
|
|
|
}); |
|
|
|
}); |
|
|
|
setCurrentPage(2); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 并行获取额外数据
|
|
|
|
|
|
|
|
const additionalResults = await Promise.all(remainingRequests); |
|
|
|
|
|
|
|
const additionalProducts = additionalResults.flatMap(result => result.products); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 合并所有产品
|
|
|
|
|
|
|
|
setProducts(prev => [...prev, ...additionalProducts]); |
|
|
|
|
|
|
|
setCurrentPage(4); |
|
|
|
|
|
|
|
setHasMore(firstPageRes.products.length + additionalProducts.length < (firstPageRes.total || 0)); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
// 如果没有热门关键词,只使用第一页数据
|
|
|
|
|
|
|
|
setCurrentPage(1); |
|
|
|
|
|
|
|
setHasMore(firstPageRes.products.length < (firstPageRes.total || 0)); |
|
|
|
|
|
|
|
} |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
console.error("Error fetching products:", error); |
|
|
|
console.error("获取产品数据失败:", error); |
|
|
|
} finally { |
|
|
|
} finally { |
|
|
|
if (isLoadMore) { |
|
|
|
|
|
|
|
setIsLoadingMore(false); |
|
|
|
|
|
|
|
setLoadingPlaceholders(0); // 清除占位符
|
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
setTimeout(() => { |
|
|
|
|
|
|
|
setLoading(false); |
|
|
|
setLoading(false); |
|
|
|
}, 300); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
}, [params, hotTerms]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 加载更多产品
|
|
|
|
|
|
|
|
const handleLoadMore = useCallback(() => { |
|
|
|
|
|
|
|
if (!hasMore || loadingMore || hotTerms.length === 0) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setLoadingMore(true); |
|
|
|
|
|
|
|
setLoadingPlaceholders(10); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用新的随机关键词
|
|
|
|
|
|
|
|
const newKeyword = getRandomKeyword(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 准备请求参数
|
|
|
|
|
|
|
|
const loadMoreParams = { |
|
|
|
|
|
|
|
...params, |
|
|
|
|
|
|
|
keyword: newKeyword, |
|
|
|
|
|
|
|
page: currentPage + 1, |
|
|
|
|
|
|
|
page_size: 10 |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取下一页数据
|
|
|
|
|
|
|
|
productApi.getSearchProducts(loadMoreParams) |
|
|
|
|
|
|
|
.then(res => { |
|
|
|
|
|
|
|
setProducts(prev => [...prev, ...res.products]); |
|
|
|
|
|
|
|
setCurrentPage(prev => prev + 1); |
|
|
|
|
|
|
|
setHasMore((products.length + res.products.length) < (res.total || 0)); |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.catch(error => { |
|
|
|
|
|
|
|
console.error("加载更多失败:", error); |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
.finally(() => { |
|
|
|
|
|
|
|
setLoadingMore(false); |
|
|
|
|
|
|
|
setLoadingPlaceholders(0); |
|
|
|
|
|
|
|
}); |
|
|
|
|
|
|
|
}, [hasMore, loadingMore, hotTerms, getRandomKeyword, params, currentPage, products.length]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新产品列表
|
|
|
|
|
|
|
|
const handleRefresh = useCallback(async () => { |
|
|
|
|
|
|
|
if (hotTerms.length === 0) return; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
setRefreshing(true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
// 使用新的随机关键词
|
|
|
|
|
|
|
|
const refreshKeyword = getRandomKeyword(); |
|
|
|
|
|
|
|
console.log("刷新,使用关键词:", refreshKeyword); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 重新获取初始数据
|
|
|
|
|
|
|
|
await fetchInitialProducts(refreshKeyword); |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
console.error("刷新失败:", error); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
setRefreshing(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [hotTerms, getRandomKeyword, fetchInitialProducts]); |
|
|
|
|
|
|
|
|
|
|
|
const handleProductPress = useCallback( |
|
|
|
const handleProductPress = useCallback( |
|
|
|
(item: Product) => { |
|
|
|
(item: Product) => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
navigation.navigate("ProductDetail", { |
|
|
|
navigation.navigate("ProductDetail", { |
|
|
|
offer_id: item.offer_id, |
|
|
|
offer_id: item.offer_id, |
|
|
|
searchKeyword: searchParams.keyword, |
|
|
|
searchKeyword: params.keyword, |
|
|
|
price: item.min_price, |
|
|
|
price: item.min_price, |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, |
|
|
|
}, |
|
|
|
[navigation] |
|
|
|
[navigation] |
|
|
|
); |
|
|
|
); |
|
|
|
const onRefresh = useCallback(async () => { |
|
|
|
|
|
|
|
setRefreshing(true); |
|
|
|
|
|
|
|
setInitialLoadComplete(false); // 重置初始加载标记
|
|
|
|
|
|
|
|
setCurrentPage(1); // 重置页码
|
|
|
|
|
|
|
|
setSearchParams(prev => ({ ...prev, page_size: 10 })); // 只重置每页数量
|
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
await getProductData(); |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
console.error("Error fetching products:", error); |
|
|
|
|
|
|
|
} finally { |
|
|
|
|
|
|
|
setRefreshing(false); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, [searchParams]); |
|
|
|
|
|
|
|
const { country, currency, language } = useGlobalStore(); |
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
|
|
|
|
console.log("userStore.user", userStore.user); |
|
|
|
|
|
|
|
getProductData(); |
|
|
|
|
|
|
|
}, [userStore.user, country, currency, language]); |
|
|
|
|
|
|
|
const categories = [ |
|
|
|
const categories = [ |
|
|
|
"Tous", |
|
|
|
"Tous", |
|
|
|
"Bijoux", |
|
|
|
"Bijoux", |
|
|
@ -453,6 +564,7 @@ export const HomeScreen = () => { |
|
|
|
"Hygiène et Soins pour le corps", |
|
|
|
"Hygiène et Soins pour le corps", |
|
|
|
"Maquillage", |
|
|
|
"Maquillage", |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
const defaultSubcategories: SubcategoryItem[] = [ |
|
|
|
const defaultSubcategories: SubcategoryItem[] = [ |
|
|
|
{ id: 1, title: "Jewelry", icon: "diamond-outline" }, |
|
|
|
{ id: 1, title: "Jewelry", icon: "diamond-outline" }, |
|
|
|
{ id: 2, title: "Earrings", icon: "ear-outline" }, |
|
|
|
{ id: 2, title: "Earrings", icon: "ear-outline" }, |
|
|
@ -461,6 +573,7 @@ export const HomeScreen = () => { |
|
|
|
{ id: 5, title: "Earrings", icon: "ear-outline" }, |
|
|
|
{ id: 5, title: "Earrings", icon: "ear-outline" }, |
|
|
|
{ id: 6, title: "Bracelet", icon: "watch-outline" }, |
|
|
|
{ id: 6, title: "Bracelet", icon: "watch-outline" }, |
|
|
|
]; |
|
|
|
]; |
|
|
|
|
|
|
|
|
|
|
|
const categoryContent: CategoryContentType = { |
|
|
|
const categoryContent: CategoryContentType = { |
|
|
|
Tous: [], |
|
|
|
Tous: [], |
|
|
|
Bijoux: defaultSubcategories, |
|
|
|
Bijoux: defaultSubcategories, |
|
|
@ -474,38 +587,37 @@ export const HomeScreen = () => { |
|
|
|
"Hygiène et Soins pour le corps": defaultSubcategories, |
|
|
|
"Hygiène et Soins pour le corps": defaultSubcategories, |
|
|
|
Maquillage: defaultSubcategories, |
|
|
|
Maquillage: defaultSubcategories, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
useEffect(() => { |
|
|
|
useEffect(() => { |
|
|
|
// Ensure the content is available when category changes
|
|
|
|
|
|
|
|
if (!categoryContent[selectedHorizontalCategory]) { |
|
|
|
if (!categoryContent[selectedHorizontalCategory]) { |
|
|
|
setSelectedHorizontalCategory("Tous"); |
|
|
|
setSelectedHorizontalCategory("Tous"); |
|
|
|
} |
|
|
|
} |
|
|
|
}, [selectedHorizontalCategory]); |
|
|
|
}, [selectedHorizontalCategory]); |
|
|
|
// 导航到搜索页面 - 使用useCallback优化函数引用
|
|
|
|
|
|
|
|
const navigateToSearch = useCallback(() => { |
|
|
|
const navigateToSearch = useCallback(() => { |
|
|
|
// 使用InteractionManager延迟执行导航操作,确保当前交互和动画已完成
|
|
|
|
|
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
navigation.navigate("Search"); |
|
|
|
navigation.navigate("Search"); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, [navigation]); |
|
|
|
}, [navigation]); |
|
|
|
|
|
|
|
|
|
|
|
const navigateToShippingDetails = useCallback(() => { |
|
|
|
const navigateToShippingDetails = useCallback(() => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
navigation.navigate("ShippingDetailsSection"); |
|
|
|
navigation.navigate("ShippingDetailsSection"); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, [navigation]); |
|
|
|
}, [navigation]); |
|
|
|
|
|
|
|
|
|
|
|
const navigateToInquiry = useCallback(() => { |
|
|
|
const navigateToInquiry = useCallback(() => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
InteractionManager.runAfterInteractions(() => { |
|
|
|
navigation.navigate("InquiryScreen"); |
|
|
|
navigation.navigate("InquiryScreen"); |
|
|
|
}); |
|
|
|
}); |
|
|
|
}, [navigation]); |
|
|
|
}, [navigation]); |
|
|
|
|
|
|
|
|
|
|
|
const scrollToCategory = (category: string) => { |
|
|
|
const scrollToCategory = (category: string) => { |
|
|
|
const categoryIndex = categories.findIndex((c) => c === category); |
|
|
|
const categoryIndex = categories.findIndex((c) => c === category); |
|
|
|
if (categoryIndex !== -1 && horizontalScrollRef.current) { |
|
|
|
if (categoryIndex !== -1 && horizontalScrollRef.current) { |
|
|
|
const firstFourKeys = Object.keys(categoryContent).slice( |
|
|
|
const firstFourKeys = Object.keys(categoryContent).slice(0, categoryIndex - 1); |
|
|
|
0, |
|
|
|
|
|
|
|
categoryIndex - 1 |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
let str = ""; |
|
|
|
let str = ""; |
|
|
|
firstFourKeys.forEach((key, index) => { |
|
|
|
firstFourKeys.forEach((key) => { |
|
|
|
str += key; |
|
|
|
str += key; |
|
|
|
}); |
|
|
|
}); |
|
|
|
horizontalScrollRef.current.scrollTo({ |
|
|
|
horizontalScrollRef.current.scrollTo({ |
|
|
@ -514,7 +626,7 @@ export const HomeScreen = () => { |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
// 渲染产品列表项
|
|
|
|
|
|
|
|
const renderProductItem = ({ item }: { item: Product }) => ( |
|
|
|
const renderProductItem = ({ item }: { item: Product }) => ( |
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
|
onPress={() => handleProductPress(item)} |
|
|
|
onPress={() => handleProductPress(item)} |
|
|
@ -538,19 +650,13 @@ export const HomeScreen = () => { |
|
|
|
<View style={styles.vipButtonContainer}> |
|
|
|
<View style={styles.vipButtonContainer}> |
|
|
|
<TouchableOpacity style={styles.vipButton}> |
|
|
|
<TouchableOpacity style={styles.vipButton}> |
|
|
|
<Text style={styles.vipButtonText}>VIP</Text> |
|
|
|
<Text style={styles.vipButtonText}>VIP</Text> |
|
|
|
<Text style={styles.vipLabelBold}> |
|
|
|
<Text style={styles.vipLabelBold}>{userStore.user?.vip_level}</Text> |
|
|
|
{userStore.user?.vip_level} |
|
|
|
|
|
|
|
</Text> |
|
|
|
|
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
)} |
|
|
|
)} |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
<View style={styles.beautyProductCard}> |
|
|
|
<View style={styles.beautyProductCard}> |
|
|
|
<Text |
|
|
|
<Text style={styles.beautyProductTitle} numberOfLines={2} ellipsizeMode="tail"> |
|
|
|
style={styles.beautyProductTitle} |
|
|
|
|
|
|
|
numberOfLines={2} |
|
|
|
|
|
|
|
ellipsizeMode="tail" |
|
|
|
|
|
|
|
> |
|
|
|
|
|
|
|
{getSubjectTransLanguage(item)} |
|
|
|
{getSubjectTransLanguage(item)} |
|
|
|
</Text> |
|
|
|
</Text> |
|
|
|
<View style={styles.beautyProductInfoRow}> |
|
|
|
<View style={styles.beautyProductInfoRow}> |
|
|
@ -562,27 +668,18 @@ export const HomeScreen = () => { |
|
|
|
</Text> |
|
|
|
</Text> |
|
|
|
)} |
|
|
|
)} |
|
|
|
<View style={styles.priceContainer}> |
|
|
|
<View style={styles.priceContainer}> |
|
|
|
<Text style={styles.highlightedText}> |
|
|
|
<Text style={styles.highlightedText}>{item.min_price || "0"}</Text> |
|
|
|
{item.min_price || "0"} |
|
|
|
<Text style={styles.highlightedText1}>{item.currency || "FCFA"}</Text> |
|
|
|
</Text> |
|
|
|
|
|
|
|
<Text style={styles.highlightedText1}> |
|
|
|
|
|
|
|
{item.currency || "FCFA"} |
|
|
|
|
|
|
|
</Text> |
|
|
|
|
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
<Text style={styles.beautySalesInfo}> |
|
|
|
<Text style={styles.beautySalesInfo}>{item.sold_out || "0"}+ ventes</Text> |
|
|
|
{item.sold_out || "0"}+ ventes |
|
|
|
|
|
|
|
</Text> |
|
|
|
|
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
// 渲染骨架屏网格
|
|
|
|
|
|
|
|
const renderSkeletonGrid = useCallback(() => { |
|
|
|
const renderSkeletonGrid = useCallback(() => { |
|
|
|
// 创建骨架屏数组
|
|
|
|
|
|
|
|
const skeletonArray = Array(8).fill(null); |
|
|
|
const skeletonArray = Array(8).fill(null); |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
<View style={styles.skeletonContainer}> |
|
|
|
<View style={styles.skeletonContainer}> |
|
|
|
<FlatList |
|
|
|
<FlatList |
|
|
@ -598,82 +695,34 @@ export const HomeScreen = () => { |
|
|
|
); |
|
|
|
); |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 清理expo-image-picker临时文件
|
|
|
|
|
|
|
|
const cleanupImagePickerCache = async () => { |
|
|
|
const cleanupImagePickerCache = async () => { |
|
|
|
try { |
|
|
|
try { |
|
|
|
// Skip cache cleanup on web platform
|
|
|
|
|
|
|
|
if (Platform.OS === 'web') { |
|
|
|
if (Platform.OS === 'web') { |
|
|
|
console.log('Cache cleanup skipped on web platform'); |
|
|
|
console.log('Cache cleanup skipped on web platform'); |
|
|
|
setGalleryUsed(false); |
|
|
|
setGalleryUsed(false); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 相册选择后清理临时缓存
|
|
|
|
|
|
|
|
const cacheDir = `${FileSystem.cacheDirectory}ImagePicker`; |
|
|
|
const cacheDir = `${FileSystem.cacheDirectory}ImagePicker`; |
|
|
|
await FileSystem.deleteAsync(cacheDir, { idempotent: true }); |
|
|
|
await FileSystem.deleteAsync(cacheDir, { idempotent: true }); |
|
|
|
console.log("已清理ImagePicker缓存"); |
|
|
|
console.log("已清理ImagePicker缓存"); |
|
|
|
|
|
|
|
|
|
|
|
// 立即重置状态,无需用户干预
|
|
|
|
|
|
|
|
setGalleryUsed(false); |
|
|
|
setGalleryUsed(false); |
|
|
|
} catch (error) { |
|
|
|
} catch (error) { |
|
|
|
console.log("清理缓存错误", error); |
|
|
|
console.log("清理缓存错误", error); |
|
|
|
// Even if cleanup fails, reset the state
|
|
|
|
|
|
|
|
setGalleryUsed(false); |
|
|
|
setGalleryUsed(false); |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 将图片URI转换为FormData
|
|
|
|
|
|
|
|
const uriToFormData = async (uri: string) => { |
|
|
|
|
|
|
|
try { |
|
|
|
|
|
|
|
// 创建FormData对象
|
|
|
|
|
|
|
|
const formData = new FormData(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 获取文件名
|
|
|
|
|
|
|
|
const filename = uri.split("/").pop() || "image.jpg"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 判断文件类型(mime type)
|
|
|
|
|
|
|
|
const match = /\.(\w+)$/.exec(filename); |
|
|
|
|
|
|
|
const type = match ? `image/${match[1]}` : "image/jpeg"; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 处理iOS路径前缀
|
|
|
|
|
|
|
|
const imageUri = Platform.OS === "ios" ? uri.replace("file://", "") : uri; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 将图片转换为Blob
|
|
|
|
|
|
|
|
const imageFetchResponse = await fetch(imageUri); |
|
|
|
|
|
|
|
const imageBlob = await imageFetchResponse.blob(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 添加图片到FormData
|
|
|
|
|
|
|
|
formData.append("image", imageBlob, filename); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log("FormData 详情:"); |
|
|
|
|
|
|
|
console.log("- 图片URI:", uri); |
|
|
|
|
|
|
|
console.log("- 文件名:", filename); |
|
|
|
|
|
|
|
console.log("- 文件类型:", type); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return formData; |
|
|
|
|
|
|
|
} catch (error) { |
|
|
|
|
|
|
|
console.error("创建FormData错误:", error); |
|
|
|
|
|
|
|
throw error; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 处理从相册选择
|
|
|
|
|
|
|
|
const handleChooseFromGallery = useCallback(async () => { |
|
|
|
const handleChooseFromGallery = useCallback(async () => { |
|
|
|
console.log("handleChooseFromGallery"); |
|
|
|
|
|
|
|
setShowImagePickerModal(false); |
|
|
|
setShowImagePickerModal(false); |
|
|
|
|
|
|
|
|
|
|
|
// 等待模态窗关闭后再执行
|
|
|
|
|
|
|
|
setTimeout(async () => { |
|
|
|
setTimeout(async () => { |
|
|
|
try { |
|
|
|
try { |
|
|
|
// 请求相册权限
|
|
|
|
const permissionResult = await ImagePicker.requestMediaLibraryPermissionsAsync(); |
|
|
|
const permissionResult = |
|
|
|
|
|
|
|
await ImagePicker.requestMediaLibraryPermissionsAsync(); |
|
|
|
|
|
|
|
if (permissionResult.status !== "granted") { |
|
|
|
if (permissionResult.status !== "granted") { |
|
|
|
console.log("相册权限被拒绝"); |
|
|
|
console.log("相册权限被拒绝"); |
|
|
|
return; |
|
|
|
return; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// 打开相册
|
|
|
|
|
|
|
|
const result = await ImagePicker.launchImageLibraryAsync({ |
|
|
|
const result = await ImagePicker.launchImageLibraryAsync({ |
|
|
|
mediaTypes: ImagePicker.MediaTypeOptions.Images, |
|
|
|
mediaTypes: ImagePicker.MediaTypeOptions.Images, |
|
|
|
allowsEditing: true, |
|
|
|
allowsEditing: true, |
|
|
@ -682,32 +731,24 @@ export const HomeScreen = () => { |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (!result.canceled && result.assets && result.assets.length > 0) { |
|
|
|
if (!result.canceled && result.assets && result.assets.length > 0) { |
|
|
|
console.log("相册选择成功:", result.assets[0].uri); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
await cleanupImagePickerCache(); |
|
|
|
await cleanupImagePickerCache(); |
|
|
|
navigation.navigate("ImageSearchResultScreen", { |
|
|
|
navigation.navigate("ImageSearchResultScreen", { |
|
|
|
image: result.assets[0].uri, |
|
|
|
image: result.assets[0].uri, |
|
|
|
type: 1, |
|
|
|
type: 1, |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error: any) { |
|
|
|
} catch (error) { |
|
|
|
console.error("相册错误:", error); |
|
|
|
console.error("相册错误:", error); |
|
|
|
// 出错时也清理缓存
|
|
|
|
|
|
|
|
await cleanupImagePickerCache(); |
|
|
|
await cleanupImagePickerCache(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, 500); |
|
|
|
}, 500); |
|
|
|
}, [userStore.user]); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 处理相机拍照 - 简化版本,不再需要处理galleryUsed
|
|
|
|
|
|
|
|
const handleTakePhoto = useCallback(async () => { |
|
|
|
const handleTakePhoto = useCallback(async () => { |
|
|
|
console.log("handleTakePhoto"); |
|
|
|
|
|
|
|
setShowImagePickerModal(false); |
|
|
|
setShowImagePickerModal(false); |
|
|
|
|
|
|
|
|
|
|
|
// 等待模态窗关闭后再执行
|
|
|
|
|
|
|
|
setTimeout(async () => { |
|
|
|
setTimeout(async () => { |
|
|
|
try { |
|
|
|
try { |
|
|
|
const permissionResult = |
|
|
|
const permissionResult = await ImagePicker.requestCameraPermissionsAsync(); |
|
|
|
await ImagePicker.requestCameraPermissionsAsync(); |
|
|
|
|
|
|
|
if (permissionResult.status !== "granted") { |
|
|
|
if (permissionResult.status !== "granted") { |
|
|
|
console.log("相机权限被拒绝"); |
|
|
|
console.log("相机权限被拒绝"); |
|
|
|
return; |
|
|
|
return; |
|
|
@ -721,68 +762,34 @@ export const HomeScreen = () => { |
|
|
|
}); |
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
if (!result.canceled && result.assets && result.assets.length > 0) { |
|
|
|
if (!result.canceled && result.assets && result.assets.length > 0) { |
|
|
|
console.log("拍照成功:", result.assets[0].uri); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 使用后清理缓存
|
|
|
|
|
|
|
|
await cleanupImagePickerCache(); |
|
|
|
await cleanupImagePickerCache(); |
|
|
|
// 将图片URI转换为FormData
|
|
|
|
|
|
|
|
navigation.navigate("ImageSearchResultScreen", { |
|
|
|
navigation.navigate("ImageSearchResultScreen", { |
|
|
|
image: result.assets[0].uri, |
|
|
|
image: result.assets[0].uri, |
|
|
|
type: 1, |
|
|
|
type: 1, |
|
|
|
}); |
|
|
|
}); |
|
|
|
} |
|
|
|
} |
|
|
|
} catch (error: any) { |
|
|
|
} catch (error) { |
|
|
|
console.error("相机错误:", error); |
|
|
|
console.error("相机错误:", error); |
|
|
|
// 出错时也清理缓存
|
|
|
|
|
|
|
|
await cleanupImagePickerCache(); |
|
|
|
await cleanupImagePickerCache(); |
|
|
|
} |
|
|
|
} |
|
|
|
}, 500); |
|
|
|
}, 500); |
|
|
|
}, [userStore.user]); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 重置应用状态函数
|
|
|
|
|
|
|
|
const resetAppState = useCallback(() => { |
|
|
|
const resetAppState = useCallback(() => { |
|
|
|
// 重置标记
|
|
|
|
|
|
|
|
setGalleryUsed(false); |
|
|
|
setGalleryUsed(false); |
|
|
|
|
|
|
|
|
|
|
|
// 清理缓存
|
|
|
|
|
|
|
|
cleanupImagePickerCache(); |
|
|
|
cleanupImagePickerCache(); |
|
|
|
|
|
|
|
|
|
|
|
// 提示用户
|
|
|
|
|
|
|
|
Alert.alert("已重置", "现在您可以使用相机功能了"); |
|
|
|
Alert.alert("已重置", "现在您可以使用相机功能了"); |
|
|
|
}, []); |
|
|
|
}, []); |
|
|
|
|
|
|
|
|
|
|
|
// 修改加载更多函数
|
|
|
|
|
|
|
|
const loadMore = () => { |
|
|
|
|
|
|
|
if (!hasMore || isLoadingMore) { |
|
|
|
|
|
|
|
console.log('不加载更多:', { hasMore, isLoadingMore }); |
|
|
|
|
|
|
|
return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
console.log('开始加载更多, 当前页码:', currentPage); |
|
|
|
|
|
|
|
setLoadingPlaceholders(10); // 设置10个占位符
|
|
|
|
|
|
|
|
getProductData(true); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 修改滚动到底部处理函数
|
|
|
|
|
|
|
|
const handleEndReached = () => { |
|
|
|
|
|
|
|
console.log('触发加载更多'); |
|
|
|
|
|
|
|
loadMore(); |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 修改渲染函数
|
|
|
|
|
|
|
|
const renderItem = ({ item, index }: { item: Product; index: number }) => { |
|
|
|
const renderItem = ({ item, index }: { item: Product; index: number }) => { |
|
|
|
// 如果是占位符
|
|
|
|
|
|
|
|
if (index >= products.length && index < products.length + loadingPlaceholders) { |
|
|
|
if (index >= products.length && index < products.length + loadingPlaceholders) { |
|
|
|
return <ProductSkeleton />; |
|
|
|
return <ProductSkeleton />; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return renderProductItem({ item }); |
|
|
|
return renderProductItem({ item }); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
// 渲染列表头部内容
|
|
|
|
|
|
|
|
const renderHeader = () => ( |
|
|
|
const renderHeader = () => ( |
|
|
|
<> |
|
|
|
<> |
|
|
|
{/* 轮播图 */} |
|
|
|
|
|
|
|
<View style={styles.swiperContainer}> |
|
|
|
<View style={styles.swiperContainer}> |
|
|
|
<Carousel |
|
|
|
<Carousel |
|
|
|
loop |
|
|
|
loop |
|
|
@ -815,19 +822,6 @@ export const HomeScreen = () => { |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
)} |
|
|
|
)} |
|
|
|
/> |
|
|
|
/> |
|
|
|
{/* 自定义指示器 */} |
|
|
|
|
|
|
|
{/* <View style={styles.indicatorContainer}> |
|
|
|
|
|
|
|
{data.map((_, index) => ( |
|
|
|
|
|
|
|
<View |
|
|
|
|
|
|
|
key={index} |
|
|
|
|
|
|
|
style={[ |
|
|
|
|
|
|
|
styles.indicator, |
|
|
|
|
|
|
|
activeIndex === index ? styles.activeIndicator : styles.inactiveIndicator, |
|
|
|
|
|
|
|
]} |
|
|
|
|
|
|
|
/> |
|
|
|
|
|
|
|
))} |
|
|
|
|
|
|
|
</View> */} |
|
|
|
|
|
|
|
{/* 搜索栏 - 定位在轮播图上方 */} |
|
|
|
|
|
|
|
<View style={styles.searchOverlay}> |
|
|
|
<View style={styles.searchOverlay}> |
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
|
style={styles.searchBar} |
|
|
|
style={styles.searchBar} |
|
|
@ -845,9 +839,7 @@ export const HomeScreen = () => { |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
{/* 内容区域 */} |
|
|
|
|
|
|
|
<View style={styles.bannerContainer}> |
|
|
|
<View style={styles.bannerContainer}> |
|
|
|
{/* 左侧区域 - 上下两个 */} |
|
|
|
|
|
|
|
<View style={styles.leftContainer}> |
|
|
|
<View style={styles.leftContainer}> |
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
|
style={styles.leftTopItem} |
|
|
|
style={styles.leftTopItem} |
|
|
@ -868,7 +860,6 @@ export const HomeScreen = () => { |
|
|
|
/> |
|
|
|
/> |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
{/* 右侧区域 - 一个 */} |
|
|
|
|
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
|
style={styles.rightContainer} |
|
|
|
style={styles.rightContainer} |
|
|
|
onPress={navigateToInquiry} |
|
|
|
onPress={navigateToInquiry} |
|
|
@ -894,16 +885,14 @@ export const HomeScreen = () => { |
|
|
|
key={index} |
|
|
|
key={index} |
|
|
|
style={[ |
|
|
|
style={[ |
|
|
|
styles.categoryItem, |
|
|
|
styles.categoryItem, |
|
|
|
selectedHorizontalCategory === category && |
|
|
|
selectedHorizontalCategory === category && styles.categoryItemActive, |
|
|
|
styles.categoryItemActive, |
|
|
|
|
|
|
|
]} |
|
|
|
]} |
|
|
|
onPress={() => setSelectedHorizontalCategory(category)} |
|
|
|
onPress={() => setSelectedHorizontalCategory(category)} |
|
|
|
> |
|
|
|
> |
|
|
|
<Text |
|
|
|
<Text |
|
|
|
style={[ |
|
|
|
style={[ |
|
|
|
styles.categoryText, |
|
|
|
styles.categoryText, |
|
|
|
selectedHorizontalCategory === category && |
|
|
|
selectedHorizontalCategory === category && styles.categoryTextActive, |
|
|
|
styles.categoryTextActive, |
|
|
|
|
|
|
|
]} |
|
|
|
]} |
|
|
|
> |
|
|
|
> |
|
|
|
{category} |
|
|
|
{category} |
|
|
@ -924,7 +913,6 @@ export const HomeScreen = () => { |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
{/* Subcategory Content */} |
|
|
|
|
|
|
|
{selectedHorizontalCategory && |
|
|
|
{selectedHorizontalCategory && |
|
|
|
categoryContent[selectedHorizontalCategory] && |
|
|
|
categoryContent[selectedHorizontalCategory] && |
|
|
|
categoryContent[selectedHorizontalCategory].length > 0 ? ( |
|
|
|
categoryContent[selectedHorizontalCategory].length > 0 ? ( |
|
|
@ -983,7 +971,7 @@ export const HomeScreen = () => { |
|
|
|
backgroundColor: "transparent", |
|
|
|
backgroundColor: "transparent", |
|
|
|
}} |
|
|
|
}} |
|
|
|
ListHeaderComponent={renderHeader} |
|
|
|
ListHeaderComponent={renderHeader} |
|
|
|
onEndReached={handleEndReached} |
|
|
|
onEndReached={handleLoadMore} |
|
|
|
onEndReachedThreshold={3} |
|
|
|
onEndReachedThreshold={3} |
|
|
|
ListFooterComponent={() => ( |
|
|
|
ListFooterComponent={() => ( |
|
|
|
!hasMore && !loadingPlaceholders ? ( |
|
|
|
!hasMore && !loadingPlaceholders ? ( |
|
|
@ -995,7 +983,7 @@ export const HomeScreen = () => { |
|
|
|
refreshControl={ |
|
|
|
refreshControl={ |
|
|
|
<RefreshControl |
|
|
|
<RefreshControl |
|
|
|
refreshing={refreshing} |
|
|
|
refreshing={refreshing} |
|
|
|
onRefresh={onRefresh} |
|
|
|
onRefresh={handleRefresh} |
|
|
|
colors={["#ff5100"]} |
|
|
|
colors={["#ff5100"]} |
|
|
|
tintColor="#ff5100" |
|
|
|
tintColor="#ff5100" |
|
|
|
progressBackgroundColor="transparent" |
|
|
|
progressBackgroundColor="transparent" |
|
|
@ -1004,7 +992,6 @@ export const HomeScreen = () => { |
|
|
|
/> |
|
|
|
/> |
|
|
|
)} |
|
|
|
)} |
|
|
|
|
|
|
|
|
|
|
|
{/* Categories Modal */} |
|
|
|
|
|
|
|
<Modal |
|
|
|
<Modal |
|
|
|
visible={showCategoryModal} |
|
|
|
visible={showCategoryModal} |
|
|
|
animationType="slide" |
|
|
|
animationType="slide" |
|
|
@ -1046,8 +1033,7 @@ export const HomeScreen = () => { |
|
|
|
<Text |
|
|
|
<Text |
|
|
|
style={[ |
|
|
|
style={[ |
|
|
|
styles.categoryModalText, |
|
|
|
styles.categoryModalText, |
|
|
|
selectedCategory === category && |
|
|
|
selectedCategory === category && styles.selectedCategoryText, |
|
|
|
styles.selectedCategoryText, |
|
|
|
|
|
|
|
]} |
|
|
|
]} |
|
|
|
> |
|
|
|
> |
|
|
|
{category} |
|
|
|
{category} |
|
|
@ -1062,7 +1048,6 @@ export const HomeScreen = () => { |
|
|
|
</View> |
|
|
|
</View> |
|
|
|
</Modal> |
|
|
|
</Modal> |
|
|
|
|
|
|
|
|
|
|
|
{/* Image Picker Modal */} |
|
|
|
|
|
|
|
<Modal |
|
|
|
<Modal |
|
|
|
visible={showImagePickerModal} |
|
|
|
visible={showImagePickerModal} |
|
|
|
animationType="slide" |
|
|
|
animationType="slide" |
|
|
@ -1076,7 +1061,6 @@ export const HomeScreen = () => { |
|
|
|
> |
|
|
|
> |
|
|
|
<View style={styles.imagePickerContent}> |
|
|
|
<View style={styles.imagePickerContent}> |
|
|
|
{!galleryUsed ? ( |
|
|
|
{!galleryUsed ? ( |
|
|
|
// 正常状态,显示相机选项
|
|
|
|
|
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
|
style={styles.imagePickerOption} |
|
|
|
style={styles.imagePickerOption} |
|
|
|
onPress={handleTakePhoto} |
|
|
|
onPress={handleTakePhoto} |
|
|
@ -1089,7 +1073,6 @@ export const HomeScreen = () => { |
|
|
|
<Text style={styles.imagePickerText}>拍照</Text> |
|
|
|
<Text style={styles.imagePickerText}>拍照</Text> |
|
|
|
</TouchableOpacity> |
|
|
|
</TouchableOpacity> |
|
|
|
) : ( |
|
|
|
) : ( |
|
|
|
// 已使用相册状态,显示重置选项
|
|
|
|
|
|
|
|
<TouchableOpacity |
|
|
|
<TouchableOpacity |
|
|
|
style={styles.imagePickerOption} |
|
|
|
style={styles.imagePickerOption} |
|
|
|
onPress={resetAppState} |
|
|
|
onPress={resetAppState} |
|
|
|