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. 231
      app/screens/ProductDetailScreen.tsx

3
app/locales/en/translation.json

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

4
app/locales/fr/translation.json

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

4
app/screens/CartScreen.tsx

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

2
app/screens/HomeScreen.tsx

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

231
app/screens/ProductDetailScreen.tsx

@ -1,4 +1,4 @@
import React, { useEffect, useCallback } from "react";
import React, { useEffect, useCallback, useState } from "react";
import {
View,
Text,
@ -15,7 +15,8 @@ import {
InteractionManager,
Platform,
StatusBar,
SafeAreaView
SafeAreaView,
Modal
} from "react-native";
import fontSize from "../utils/fontsizeUtils";
import widthUtils from "../utils/widthUtils";
@ -26,13 +27,14 @@ import ShoppingCartIcon from "../components/ShoppingCartIcon";
import HeartIcon from "../components/HeartIcon";
import HeartRedIcon from "../components/HeartIconRed";
import ShareIcon from "../components/ShareIcon";
import { useState } from "react";
import { Image as ExpoImage, ImageBackground } from "expo-image";
import useUserStore from "../store/user";
import { getSubjectTransLanguage } from "../utils/languageUtils";
import { useTranslation } from "react-i18next";
import { getBurialPointData } from "../store/burialPoint";
import useBurialPointStore from "../store/burialPoint";
import * as ImagePicker from "expo-image-picker";
import * as FileSystem from "expo-file-system";
import {
productApi,
@ -79,6 +81,8 @@ export const ProductDetailScreen = () => {
);
const [priceSelectedSku, setPriceSelectedSku] = useState<any>();
const [showBottomSheet, setShowBottomSheet] = useState(false);
const [showImagePickerModal, setShowImagePickerModal] = useState(false);
const [galleryUsed, setGalleryUsed] = useState(false);
const groupData = (
res: ProductDetailParams,
priceSelectedSku: SkuAttribute[]
@ -386,6 +390,9 @@ export const ProductDetailScreen = () => {
navigation.navigate("Search");
});
}, [navigation]);
const handleCameraPress = useCallback(() => {
setShowImagePickerModal(true);
}, []);
const handleProductPress = useCallback(
(item: similar) => {
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 (
<SafeAreaView style={styles.safeArea}>
<StatusBar barStyle="dark-content" backgroundColor="#fff" />
@ -431,10 +555,14 @@ export const ProductDetailScreen = () => {
>
<BackIcon size={fontSize(20)} />
</TouchableOpacity>
<TouchableOpacity style={styles.search} onPress={handleSearchPress}>
<Text style={styles.searchText}></Text>
<CameraIcon size={fontSize(20)} />
</TouchableOpacity>
<View style={styles.search}>
<TouchableOpacity onPress={handleSearchPress}>
<Text style={styles.searchText}></Text>
</TouchableOpacity>
<TouchableOpacity onPress={handleCameraPress}>
<CameraIcon size={fontSize(20)} />
</TouchableOpacity>
</View>
<TouchableOpacity
style={styles.searchIcon}
onPress={() => {
@ -830,6 +958,57 @@ export const ProductDetailScreen = () => {
)}
</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>
);
};
@ -1560,4 +1739,42 @@ const styles = StyleSheet.create({
backgroundColor: '#e0e0e0',
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