Browse Source

商品详情页拍照功能

main
Your Name 3 weeks ago
parent
commit
a86eb7db26
  1. 3
      app/locales/en/translation.json
  2. 4
      app/locales/fr/translation.json
  3. 4
      app/screens/CartScreen.tsx
  4. 2
      app/screens/HomeScreen.tsx
  5. 225
      app/screens/ProductDetailScreen.tsx

3
app/locales/en/translation.json

@ -362,6 +362,9 @@
"submit": "Submit" "submit": "Submit"
} }
}, },
"homePage":{
"searchPlaceholder": "Search products"
},
"searchCountry": "Search country", "searchCountry": "Search country",
"noCountriesFound": "No countries found" "noCountriesFound": "No countries found"
} }

4
app/locales/fr/translation.json

@ -356,6 +356,10 @@
"error": "Une erreur s'est produite. Veuillez réessayer.", "error": "Une erreur s'est produite. Veuillez réessayer.",
"submit": "Soumettre" "submit": "Soumettre"
} }
},
"homePage":{
"searchPlaceholder": "Rechercher des produits"
}, },
"searchCountry": "Rechercher un pays", "searchCountry": "Rechercher un pays",
"noCountriesFound": "Aucun pays trouvé" "noCountriesFound": "Aucun pays trouvé"

4
app/screens/CartScreen.tsx

@ -501,9 +501,9 @@ export const CartScreen = () => {
<View style={styles.productCardContainer7}> <View style={styles.productCardContainer7}>
<View style={styles.svgContainer}> <View style={styles.svgContainer}>
{/* Replace SVG with actual icon component or image */} {/* Replace SVG with actual icon component or image */}
<BackIcon size={fontSize(18)} /> {/* <BackIcon size={fontSize(18)} /> */}
</View> </View>
<Text style={styles.shoppingCartTitle}>Panier (5)</Text> {/* <Text style={styles.shoppingCartTitle}>Panier (5)</Text> */}
</View> </View>
{cartList.map((item, index1) => ( {cartList.map((item, index1) => (
<View style={styles.productCardListing} key={item.cart_id}> <View style={styles.productCardListing} key={item.cart_id}>

2
app/screens/HomeScreen.tsx

@ -756,7 +756,7 @@ export const HomeScreen = () => {
onPress={navigateToSearch} onPress={navigateToSearch}
> >
<IconComponent name="search-outline" size={20} color="#999" /> <IconComponent name="search-outline" size={20} color="#999" />
<Text style={styles.searchPlaceholder}></Text> <Text style={styles.searchPlaceholder}>{t("homePage.searchPlaceholder")}</Text>
<TouchableOpacity <TouchableOpacity
style={styles.cameraButton} style={styles.cameraButton}
onPress={() => setShowImagePickerModal(true)} onPress={() => setShowImagePickerModal(true)}

225
app/screens/ProductDetailScreen.tsx

@ -1,4 +1,4 @@
import React, { useEffect, useCallback } from "react"; import React, { useEffect, useCallback, useState } from "react";
import { import {
View, View,
Text, Text,
@ -15,7 +15,8 @@ import {
InteractionManager, InteractionManager,
Platform, Platform,
StatusBar, StatusBar,
SafeAreaView SafeAreaView,
Modal
} from "react-native"; } from "react-native";
import fontSize from "../utils/fontsizeUtils"; import fontSize from "../utils/fontsizeUtils";
import widthUtils from "../utils/widthUtils"; import widthUtils from "../utils/widthUtils";
@ -26,13 +27,14 @@ import ShoppingCartIcon from "../components/ShoppingCartIcon";
import HeartIcon from "../components/HeartIcon"; import HeartIcon from "../components/HeartIcon";
import HeartRedIcon from "../components/HeartIconRed"; import HeartRedIcon from "../components/HeartIconRed";
import ShareIcon from "../components/ShareIcon"; import ShareIcon from "../components/ShareIcon";
import { useState } from "react";
import { Image as ExpoImage, ImageBackground } from "expo-image"; import { Image as ExpoImage, ImageBackground } from "expo-image";
import useUserStore from "../store/user"; import useUserStore from "../store/user";
import { getSubjectTransLanguage } from "../utils/languageUtils"; import { getSubjectTransLanguage } from "../utils/languageUtils";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { getBurialPointData } from "../store/burialPoint"; import { getBurialPointData } from "../store/burialPoint";
import useBurialPointStore from "../store/burialPoint"; import useBurialPointStore from "../store/burialPoint";
import * as ImagePicker from "expo-image-picker";
import * as FileSystem from "expo-file-system";
import { import {
productApi, productApi,
@ -79,6 +81,8 @@ export const ProductDetailScreen = () => {
); );
const [priceSelectedSku, setPriceSelectedSku] = useState<any>(); const [priceSelectedSku, setPriceSelectedSku] = useState<any>();
const [showBottomSheet, setShowBottomSheet] = useState(false); const [showBottomSheet, setShowBottomSheet] = useState(false);
const [showImagePickerModal, setShowImagePickerModal] = useState(false);
const [galleryUsed, setGalleryUsed] = useState(false);
const groupData = ( const groupData = (
res: ProductDetailParams, res: ProductDetailParams,
priceSelectedSku: SkuAttribute[] priceSelectedSku: SkuAttribute[]
@ -386,6 +390,9 @@ export const ProductDetailScreen = () => {
navigation.navigate("Search"); navigation.navigate("Search");
}); });
}, [navigation]); }, [navigation]);
const handleCameraPress = useCallback(() => {
setShowImagePickerModal(true);
}, []);
const handleProductPress = useCallback( const handleProductPress = useCallback(
(item: similar) => { (item: similar) => {
InteractionManager.runAfterInteractions(() => { InteractionManager.runAfterInteractions(() => {
@ -412,6 +419,123 @@ export const ProductDetailScreen = () => {
)); ));
}; };
// 清理expo-image-picker临时文件
const cleanupImagePickerCache = async () => {
try {
// Skip cache cleanup on web platform
if (Platform.OS === 'web') {
console.log('Cache cleanup skipped on web platform');
setGalleryUsed(false);
return;
}
// 相册选择后清理临时缓存
const cacheDir = `${FileSystem.cacheDirectory}ImagePicker`;
await FileSystem.deleteAsync(cacheDir, { idempotent: true });
console.log("已清理ImagePicker缓存");
// 立即重置状态,无需用户干预
setGalleryUsed(false);
} catch (error) {
console.log("清理缓存错误", error);
// Even if cleanup fails, reset the state
setGalleryUsed(false);
}
};
// 处理从相册选择
const handleChooseFromGallery = useCallback(async () => {
console.log("handleChooseFromGallery");
setShowImagePickerModal(false);
// 等待模态窗关闭后再执行
setTimeout(async () => {
try {
// 请求相册权限
const permissionResult =
await ImagePicker.requestMediaLibraryPermissionsAsync();
if (permissionResult.status !== "granted") {
console.log("相册权限被拒绝");
return;
}
// 打开相册
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled && result.assets && result.assets.length > 0) {
console.log("相册选择成功:", result.assets[0].uri);
await cleanupImagePickerCache();
navigation.navigate("ImageSearchResultScreen", {
image: result.assets[0].uri,
type: 1,
});
}
} catch (error: any) {
console.error("相册错误:", error);
// 出错时也清理缓存
await cleanupImagePickerCache();
}
}, 500);
}, [navigation, userStore.user]);
// 处理相机拍照
const handleTakePhoto = useCallback(async () => {
console.log("handleTakePhoto");
setShowImagePickerModal(false);
// 等待模态窗关闭后再执行
setTimeout(async () => {
try {
const permissionResult =
await ImagePicker.requestCameraPermissionsAsync();
if (permissionResult.status !== "granted") {
console.log("相机权限被拒绝");
return;
}
const result = await ImagePicker.launchCameraAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [4, 3],
quality: 1,
});
if (!result.canceled && result.assets && result.assets.length > 0) {
console.log("拍照成功:", result.assets[0].uri);
// 使用后清理缓存
await cleanupImagePickerCache();
navigation.navigate("ImageSearchResultScreen", {
image: result.assets[0].uri,
type: 1,
});
}
} catch (error: any) {
console.error("相机错误:", error);
// 出错时也清理缓存
await cleanupImagePickerCache();
}
}, 500);
}, [navigation, userStore.user]);
// 重置应用状态函数
const resetAppState = useCallback(() => {
// 重置标记
setGalleryUsed(false);
// 清理缓存
cleanupImagePickerCache();
// 提示用户
Alert.alert("已重置", "现在您可以使用相机功能了");
}, []);
return ( return (
<SafeAreaView style={styles.safeArea}> <SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" /> <StatusBar barStyle="dark-content" backgroundColor="#fff" />
@ -431,10 +555,14 @@ export const ProductDetailScreen = () => {
> >
<BackIcon size={fontSize(20)} /> <BackIcon size={fontSize(20)} />
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.search} onPress={handleSearchPress}> <View style={styles.search}>
<TouchableOpacity onPress={handleSearchPress}>
<Text style={styles.searchText}></Text> <Text style={styles.searchText}></Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleCameraPress}>
<CameraIcon size={fontSize(20)} /> <CameraIcon size={fontSize(20)} />
</TouchableOpacity> </TouchableOpacity>
</View>
<TouchableOpacity <TouchableOpacity
style={styles.searchIcon} style={styles.searchIcon}
onPress={() => { onPress={() => {
@ -830,6 +958,57 @@ export const ProductDetailScreen = () => {
)} )}
</View> </View>
</View> </View>
{/* Image Picker Modal */}
<Modal
visible={showImagePickerModal}
animationType="slide"
transparent={true}
onRequestClose={() => setShowImagePickerModal(false)}
>
<TouchableOpacity
style={styles.imagePickerOverlay}
activeOpacity={1}
onPress={() => setShowImagePickerModal(false)}
>
<View style={styles.imagePickerContent}>
{!galleryUsed ? (
// 正常状态,显示相机选项
<TouchableOpacity
style={styles.imagePickerOption}
onPress={handleTakePhoto}
>
<CameraIcon size={24} color="#333" />
<Text style={styles.imagePickerText}></Text>
</TouchableOpacity>
) : (
// 已使用相册状态,显示重置选项
<TouchableOpacity
style={styles.imagePickerOption}
onPress={resetAppState}
>
<Text style={styles.imagePickerText}></Text>
</TouchableOpacity>
)}
<View style={styles.imagePickerDivider} />
<TouchableOpacity
style={styles.imagePickerOption}
onPress={handleChooseFromGallery}
>
<Text style={styles.imagePickerText}></Text>
</TouchableOpacity>
<TouchableOpacity
style={styles.imagePickerCancelButton}
onPress={() => setShowImagePickerModal(false)}
>
<Text style={styles.imagePickerCancelText}></Text>
</TouchableOpacity>
</View>
</TouchableOpacity>
</Modal>
</SafeAreaView> </SafeAreaView>
); );
}; };
@ -1560,4 +1739,42 @@ const styles = StyleSheet.create({
backgroundColor: '#e0e0e0', backgroundColor: '#e0e0e0',
borderRadius: 3, borderRadius: 3,
}, },
imagePickerOverlay: {
flex: 1,
backgroundColor: "rgba(0, 0, 0, 0.5)",
justifyContent: "flex-end",
},
imagePickerContent: {
backgroundColor: "#fff",
borderTopLeftRadius: 10,
borderTopRightRadius: 10,
paddingTop: 20,
},
imagePickerOption: {
flexDirection: "row",
alignItems: "center",
justifyContent: "center",
paddingVertical: 15,
},
imagePickerText: {
fontSize: fontSize(16),
color: "#333",
marginLeft: 10,
},
imagePickerDivider: {
height: 1,
backgroundColor: "#eee",
marginHorizontal: 20,
},
imagePickerCancelButton: {
alignItems: "center",
paddingVertical: 15,
borderTopWidth: 1,
borderTopColor: "#eee",
marginTop: 10,
},
imagePickerCancelText: {
fontSize: fontSize(16),
color: "#333",
},
}); });

Loading…
Cancel
Save