feat: Implement Food Camera Screen and Floating Food Overlay
- Added FoodCameraScreen for capturing food images with camera functionality. - Integrated image picker for selecting images from the gallery. - Created FloatingFoodOverlay for quick access to food library and scanning options. - Updated NutritionRadarCard to utilize FloatingFoodOverlay for adding food. - Enhanced ExploreScreen layout and styles for better user experience. - Removed unused SafeAreaView from ExploreScreen. - Updated profile edit screen to remove unnecessary state variables. - Updated avatar image source in profile edit screen. - Added ExpoCamera dependency for camera functionalities.
This commit is contained in:
@@ -10,11 +10,12 @@ import { Ionicons } from '@expo/vector-icons';
|
||||
import { useBottomTabBarHeight } from '@react-navigation/bottom-tabs';
|
||||
import { useFocusEffect } from '@react-navigation/native';
|
||||
import { Image } from 'expo-image';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Alert, Linking, ScrollView, StatusBar, StyleSheet, Switch, Text, TouchableOpacity, View } from 'react-native';
|
||||
import { SafeAreaView, useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
const DEFAULT_AVATAR_URL = 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/avatar/avatarGirl01.jpeg';
|
||||
const DEFAULT_AVATAR_URL = 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/seal-avatar/2.jpeg';
|
||||
|
||||
export default function PersonalScreen() {
|
||||
const dispatch = useAppDispatch();
|
||||
@@ -24,7 +25,6 @@ export default function PersonalScreen() {
|
||||
|
||||
// 推送通知相关
|
||||
const {
|
||||
permissionStatus,
|
||||
requestPermission,
|
||||
sendNotification,
|
||||
} = useNotifications();
|
||||
@@ -133,35 +133,37 @@ export default function PersonalScreen() {
|
||||
|
||||
// 用户信息头部
|
||||
const UserHeader = () => (
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.sectionTitle}>个人信息</Text>
|
||||
<View style={styles.cardContainer}>
|
||||
<View style={styles.userInfoContainer}>
|
||||
<View style={styles.avatarContainer}>
|
||||
<Image
|
||||
source={userProfile.avatar || DEFAULT_AVATAR_URL}
|
||||
style={styles.avatar}
|
||||
contentFit="cover"
|
||||
transition={200}
|
||||
cachePolicy="memory-disk"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.userDetails}>
|
||||
<Text style={styles.userName}>{displayName}</Text>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.editButton} onPress={() => pushIfAuthedElseLogin('/profile/edit')}>
|
||||
<Text style={styles.editButtonText}>编辑</Text>
|
||||
</TouchableOpacity>
|
||||
<View style={[styles.sectionContainer, {
|
||||
marginBottom: 0
|
||||
}]}>
|
||||
|
||||
<View style={[styles.userInfoContainer,]}>
|
||||
<View style={styles.avatarContainer}>
|
||||
<Image
|
||||
source={userProfile.avatar || DEFAULT_AVATAR_URL}
|
||||
style={styles.avatar}
|
||||
contentFit="cover"
|
||||
transition={200}
|
||||
cachePolicy="memory-disk"
|
||||
/>
|
||||
</View>
|
||||
<View style={styles.userDetails}>
|
||||
<Text style={styles.userName}>{displayName}</Text>
|
||||
</View>
|
||||
<TouchableOpacity style={styles.editButton} onPress={() => pushIfAuthedElseLogin('/profile/edit')}>
|
||||
<Text style={styles.editButtonText}>编辑</Text>
|
||||
</TouchableOpacity>
|
||||
</View>
|
||||
|
||||
</View>
|
||||
);
|
||||
|
||||
// 数据统计部分
|
||||
const StatsSection = () => (
|
||||
<View style={styles.sectionContainer}>
|
||||
<Text style={styles.sectionTitle}>身体数据</Text>
|
||||
<View style={styles.cardContainer}>
|
||||
<View style={[styles.cardContainer, {
|
||||
backgroundColor: 'unset'
|
||||
}]}>
|
||||
<View style={styles.statsContainer}>
|
||||
<View style={styles.statItem}>
|
||||
<Text style={styles.statValue}>{formatHeight()}</Text>
|
||||
@@ -224,16 +226,6 @@ export default function PersonalScreen() {
|
||||
|
||||
// 菜单项配置
|
||||
const menuSections = [
|
||||
{
|
||||
title: '账户',
|
||||
items: [
|
||||
{
|
||||
icon: 'flag-outline' as const,
|
||||
title: '目标管理',
|
||||
onPress: () => pushIfAuthedElseLogin('/profile/goals'),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
title: '通知',
|
||||
items: [
|
||||
@@ -284,30 +276,45 @@ export default function PersonalScreen() {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<StatusBar barStyle={'dark-content'} backgroundColor="transparent" translucent />
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<ScrollView
|
||||
style={styles.scrollView}
|
||||
contentContainerStyle={{ paddingBottom: bottomPadding }}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<UserHeader />
|
||||
<StatsSection />
|
||||
<View style={styles.fishRecordContainer}>
|
||||
{/* <Image
|
||||
|
||||
{/* 背景渐变 */}
|
||||
<LinearGradient
|
||||
colors={['#f5e5fbff', '#e5fcfeff', '#eefdffff', '#e6f6fcff']}
|
||||
style={styles.gradientBackground}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 0, y: 1 }}
|
||||
/>
|
||||
|
||||
{/* 装饰性圆圈 */}
|
||||
<View style={styles.decorativeCircle1} />
|
||||
<View style={styles.decorativeCircle2} />
|
||||
|
||||
<ScrollView
|
||||
style={styles.scrollView}
|
||||
contentContainerStyle={{
|
||||
paddingTop: insets.top,
|
||||
paddingBottom: bottomPadding,
|
||||
paddingHorizontal: 16,
|
||||
}}
|
||||
showsVerticalScrollIndicator={false}
|
||||
>
|
||||
<UserHeader />
|
||||
<StatsSection />
|
||||
<View style={styles.fishRecordContainer}>
|
||||
{/* <Image
|
||||
source={{ uri: 'https://plates-1251306435.cos.ap-guangzhou.myqcloud.com/images/icons/icon-profile-fish.png' }}
|
||||
contentFit="cover"
|
||||
style={{ width: 16, height: 16, marginLeft: 6 }}
|
||||
transition={200}
|
||||
cachePolicy="memory-disk"
|
||||
/> */}
|
||||
<Text style={styles.fishRecordText}>鱼干记录</Text>
|
||||
</View>
|
||||
<ActivityHeatMap />
|
||||
{menuSections.map((section, index) => (
|
||||
<MenuSection key={index} title={section.title} items={section.items} />
|
||||
))}
|
||||
</ScrollView>
|
||||
</SafeAreaView>
|
||||
<Text style={styles.fishRecordText}>鱼干记录</Text>
|
||||
</View>
|
||||
<ActivityHeatMap />
|
||||
{menuSections.map((section, index) => (
|
||||
<MenuSection key={index} title={section.title} items={section.items} />
|
||||
))}
|
||||
</ScrollView>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
@@ -315,15 +322,36 @@ export default function PersonalScreen() {
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
backgroundColor: '#F0F9FF',
|
||||
},
|
||||
safeArea: {
|
||||
flex: 1,
|
||||
gradientBackground: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
decorativeCircle1: {
|
||||
position: 'absolute',
|
||||
top: 40,
|
||||
right: 20,
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
backgroundColor: '#0EA5E9',
|
||||
opacity: 0.1,
|
||||
},
|
||||
decorativeCircle2: {
|
||||
position: 'absolute',
|
||||
bottom: -15,
|
||||
left: -15,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: '#0EA5E9',
|
||||
opacity: 0.05,
|
||||
},
|
||||
scrollView: {
|
||||
flex: 1,
|
||||
paddingHorizontal: 16,
|
||||
paddingTop: 16,
|
||||
},
|
||||
// 部分容器
|
||||
sectionContainer: {
|
||||
@@ -453,3 +481,4 @@ const styles = StyleSheet.create({
|
||||
marginLeft: 4,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user