feat: 更新多个组件以优化用户体验和功能
- 在 CoachScreen 中移除不必要的 router 引入,简化代码结构 - 在 PersonalScreen 中移除未使用的 colorScheme 引入,优化组件性能 - 更新 NutritionRadarCard 组件,新增卡路里计算功能,提升营养数据展示 - 修改 Statistics 组件,调整样式以增强视觉效果 - 移除 iOS 项目中的多余健康数据权限设置,简化配置
This commit is contained in:
@@ -2,7 +2,7 @@ import { Ionicons } from '@expo/vector-icons';
|
|||||||
import { BlurView } from 'expo-blur';
|
import { BlurView } from 'expo-blur';
|
||||||
import * as Haptics from 'expo-haptics';
|
import * as Haptics from 'expo-haptics';
|
||||||
import * as ImagePicker from 'expo-image-picker';
|
import * as ImagePicker from 'expo-image-picker';
|
||||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
import { useLocalSearchParams } from 'expo-router';
|
||||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import {
|
import {
|
||||||
ActivityIndicator,
|
ActivityIndicator,
|
||||||
@@ -115,10 +115,8 @@ const CardType = {
|
|||||||
|
|
||||||
type CardType = typeof CardType[keyof typeof CardType];
|
type CardType = typeof CardType[keyof typeof CardType];
|
||||||
|
|
||||||
// const COACH_AVATAR = require('@/assets/images/logo.png');
|
|
||||||
|
|
||||||
export default function CoachScreen() {
|
export default function CoachScreen() {
|
||||||
const router = useRouter();
|
|
||||||
const params = useLocalSearchParams<{ name?: string }>();
|
const params = useLocalSearchParams<{ name?: string }>();
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
|
|
||||||
@@ -290,10 +288,10 @@ export default function CoachScreen() {
|
|||||||
if (Platform.OS === 'ios') {
|
if (Platform.OS === 'ios') {
|
||||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
|
||||||
}
|
}
|
||||||
router.push('/mood/calendar');
|
pushIfAuthedElseLogin('/mood/calendar');
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
], [router, planDraft, checkin]);
|
], [planDraft, checkin]);
|
||||||
|
|
||||||
const scrollToEnd = useCallback(() => {
|
const scrollToEnd = useCallback(() => {
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import ActivityHeatMap from '@/components/ActivityHeatMap';
|
import ActivityHeatMap from '@/components/ActivityHeatMap';
|
||||||
import { PRIVACY_POLICY_URL, USER_AGREEMENT_URL } from '@/constants/Agree';
|
import { PRIVACY_POLICY_URL, USER_AGREEMENT_URL } from '@/constants/Agree';
|
||||||
import { Colors } from '@/constants/Colors';
|
|
||||||
import { getTabBarBottomPadding } from '@/constants/TabBar';
|
import { getTabBarBottomPadding } from '@/constants/TabBar';
|
||||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||||
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
||||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
||||||
import { useNotifications } from '@/hooks/useNotifications';
|
import { useNotifications } from '@/hooks/useNotifications';
|
||||||
import { DEFAULT_MEMBER_NAME, fetchActivityHistory, fetchMyProfile } from '@/store/userSlice';
|
import { DEFAULT_MEMBER_NAME, fetchActivityHistory, fetchMyProfile } from '@/store/userSlice';
|
||||||
import { Ionicons } from '@expo/vector-icons';
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
@@ -21,16 +19,14 @@ export default function PersonalScreen() {
|
|||||||
const { confirmLogout, confirmDeleteAccount, isLoggedIn, pushIfAuthedElseLogin } = useAuthGuard();
|
const { confirmLogout, confirmDeleteAccount, isLoggedIn, pushIfAuthedElseLogin } = useAuthGuard();
|
||||||
const insets = useSafeAreaInsets();
|
const insets = useSafeAreaInsets();
|
||||||
const tabBarHeight = useBottomTabBarHeight();
|
const tabBarHeight = useBottomTabBarHeight();
|
||||||
const colorScheme = useColorScheme();
|
|
||||||
|
|
||||||
// 推送通知相关
|
// 推送通知相关
|
||||||
const {
|
const {
|
||||||
isInitialized,
|
|
||||||
permissionStatus,
|
permissionStatus,
|
||||||
requestPermission,
|
requestPermission,
|
||||||
sendNotification,
|
sendNotification,
|
||||||
} = useNotifications();
|
} = useNotifications();
|
||||||
|
|
||||||
const [notificationEnabled, setNotificationEnabled] = useState(false);
|
const [notificationEnabled, setNotificationEnabled] = useState(false);
|
||||||
|
|
||||||
// 计算底部间距
|
// 计算底部间距
|
||||||
@@ -38,9 +34,6 @@ export default function PersonalScreen() {
|
|||||||
return getTabBarBottomPadding(tabBarHeight) + (insets?.bottom ?? 0);
|
return getTabBarBottomPadding(tabBarHeight) + (insets?.bottom ?? 0);
|
||||||
}, [tabBarHeight, insets?.bottom]);
|
}, [tabBarHeight, insets?.bottom]);
|
||||||
|
|
||||||
// 颜色主题
|
|
||||||
const colors = Colors[colorScheme ?? 'light'];
|
|
||||||
|
|
||||||
// 直接使用 Redux 中的用户信息,避免重复状态管理
|
// 直接使用 Redux 中的用户信息,避免重复状态管理
|
||||||
const userProfile = useAppSelector((state) => state.user.profile);
|
const userProfile = useAppSelector((state) => state.user.profile);
|
||||||
|
|
||||||
@@ -116,9 +109,9 @@ export default function PersonalScreen() {
|
|||||||
<View style={styles.cardContainer}>
|
<View style={styles.cardContainer}>
|
||||||
<View style={styles.userInfoContainer}>
|
<View style={styles.userInfoContainer}>
|
||||||
<View style={styles.avatarContainer}>
|
<View style={styles.avatarContainer}>
|
||||||
<Image
|
<Image
|
||||||
source={{ uri: userProfile.avatar || DEFAULT_AVATAR_URL }}
|
source={{ uri: userProfile.avatar || DEFAULT_AVATAR_URL }}
|
||||||
style={styles.avatar}
|
style={styles.avatar}
|
||||||
/>
|
/>
|
||||||
</View>
|
</View>
|
||||||
<View style={styles.userDetails}>
|
<View style={styles.userDetails}>
|
||||||
@@ -183,7 +176,7 @@ export default function PersonalScreen() {
|
|||||||
{item.type === 'switch' ? (
|
{item.type === 'switch' ? (
|
||||||
<Switch
|
<Switch
|
||||||
value={item.switchValue || false}
|
value={item.switchValue || false}
|
||||||
onValueChange={item.onSwitchChange || (() => {})}
|
onValueChange={item.onSwitchChange || (() => { })}
|
||||||
trackColor={{ false: '#E5E5E5', true: '#9370DB' }}
|
trackColor={{ false: '#E5E5E5', true: '#9370DB' }}
|
||||||
thumbColor="#FFFFFF"
|
thumbColor="#FFFFFF"
|
||||||
style={styles.switch}
|
style={styles.switch}
|
||||||
|
|||||||
@@ -352,6 +352,14 @@ export default function ExploreScreen() {
|
|||||||
{/* 营养摄入雷达图卡片 */}
|
{/* 营养摄入雷达图卡片 */}
|
||||||
<NutritionRadarCard
|
<NutritionRadarCard
|
||||||
nutritionSummary={nutritionSummary}
|
nutritionSummary={nutritionSummary}
|
||||||
|
burnedCalories={basalMetabolism || 0}
|
||||||
|
calorieDeficit={0}
|
||||||
|
resetToken={animToken}
|
||||||
|
onMealPress={(mealType: 'breakfast' | 'lunch' | 'dinner' | 'snack') => {
|
||||||
|
console.log('选择餐次:', mealType);
|
||||||
|
// 这里可以导航到营养记录页面
|
||||||
|
pushIfAuthedElseLogin('/nutrition/records');
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* 真正瀑布流布局 */}
|
{/* 真正瀑布流布局 */}
|
||||||
@@ -720,13 +728,11 @@ const styles = StyleSheet.create({
|
|||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
},
|
},
|
||||||
healthMetricsContainer: {
|
|
||||||
marginBottom: 16,
|
|
||||||
},
|
|
||||||
masonryContainer: {
|
masonryContainer: {
|
||||||
marginBottom: 16,
|
marginBottom: 16,
|
||||||
flexDirection: 'row',
|
flexDirection: 'row',
|
||||||
gap: 12,
|
gap: 12,
|
||||||
|
marginTop: 16,
|
||||||
},
|
},
|
||||||
masonryColumn: {
|
masonryColumn: {
|
||||||
flex: 1,
|
flex: 1,
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
||||||
import { ROUTES } from '@/constants/Routes';
|
import { ROUTES } from '@/constants/Routes';
|
||||||
import { NutritionSummary } from '@/services/dietRecords';
|
import { NutritionSummary } from '@/services/dietRecords';
|
||||||
|
import { Ionicons } from '@expo/vector-icons';
|
||||||
import Feather from '@expo/vector-icons/Feather';
|
import Feather from '@expo/vector-icons/Feather';
|
||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import { router } from 'expo-router';
|
import { router } from 'expo-router';
|
||||||
@@ -9,6 +11,14 @@ import { RadarCategory, RadarChart } from './RadarChart';
|
|||||||
|
|
||||||
export type NutritionRadarCardProps = {
|
export type NutritionRadarCardProps = {
|
||||||
nutritionSummary: NutritionSummary | null;
|
nutritionSummary: NutritionSummary | null;
|
||||||
|
/** 基础代谢消耗的卡路里 */
|
||||||
|
burnedCalories?: number;
|
||||||
|
/** 卡路里缺口 */
|
||||||
|
calorieDeficit?: number;
|
||||||
|
/** 动画重置令牌 */
|
||||||
|
resetToken?: number;
|
||||||
|
/** 餐次点击回调 */
|
||||||
|
onMealPress?: (mealType: 'breakfast' | 'lunch' | 'dinner' | 'snack') => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// 营养维度定义
|
// 营养维度定义
|
||||||
@@ -21,7 +31,13 @@ const NUTRITION_DIMENSIONS: RadarCategory[] = [
|
|||||||
{ key: 'sodium', label: '钠' },
|
{ key: 'sodium', label: '钠' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export function NutritionRadarCard({ nutritionSummary }: NutritionRadarCardProps) {
|
export function NutritionRadarCard({
|
||||||
|
nutritionSummary,
|
||||||
|
burnedCalories = 1618,
|
||||||
|
calorieDeficit = 0,
|
||||||
|
resetToken,
|
||||||
|
onMealPress
|
||||||
|
}: NutritionRadarCardProps) {
|
||||||
const radarValues = useMemo(() => {
|
const radarValues = useMemo(() => {
|
||||||
// 基于推荐日摄入量计算分数
|
// 基于推荐日摄入量计算分数
|
||||||
const recommendations = {
|
const recommendations = {
|
||||||
@@ -35,13 +51,21 @@ export function NutritionRadarCard({ nutritionSummary }: NutritionRadarCardProps
|
|||||||
|
|
||||||
if (!nutritionSummary) return [0, 0, 0, 0, 0, 0];
|
if (!nutritionSummary) return [0, 0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
// 检查每个营养素是否有实际值,没有则返回0
|
||||||
|
const calories = nutritionSummary.totalCalories || 0;
|
||||||
|
const protein = nutritionSummary.totalProtein || 0;
|
||||||
|
const carbohydrate = nutritionSummary.totalCarbohydrate || 0;
|
||||||
|
const fat = nutritionSummary.totalFat || 0;
|
||||||
|
const fiber = nutritionSummary.totalFiber || 0;
|
||||||
|
const sodium = nutritionSummary.totalSodium || 0;
|
||||||
|
|
||||||
return [
|
return [
|
||||||
Math.min(5, (nutritionSummary.totalCalories / recommendations.calories) * 5),
|
calories > 0 ? Math.min(5, (calories / recommendations.calories) * 5) : 0,
|
||||||
Math.min(5, (nutritionSummary.totalProtein / recommendations.protein) * 5),
|
protein > 0 ? Math.min(5, (protein / recommendations.protein) * 5) : 0,
|
||||||
Math.min(5, (nutritionSummary.totalCarbohydrate / recommendations.carbohydrate) * 5),
|
carbohydrate > 0 ? Math.min(5, (carbohydrate / recommendations.carbohydrate) * 5) : 0,
|
||||||
Math.min(5, (nutritionSummary.totalFat / recommendations.fat) * 5),
|
fat > 0 ? Math.min(5, (fat / recommendations.fat) * 5) : 0,
|
||||||
Math.min(5, (nutritionSummary.totalFiber / recommendations.fiber) * 5),
|
fiber > 0 ? Math.min(5, (fiber / recommendations.fiber) * 5) : 0,
|
||||||
Math.min(5, Math.max(0, 5 - (nutritionSummary.totalSodium / recommendations.sodium) * 5)), // 钠含量越低越好
|
sodium > 0 ? Math.min(5, Math.max(0, 5 - (sodium / recommendations.sodium) * 5)) : 0, // 钠含量越低越好
|
||||||
];
|
];
|
||||||
}, [nutritionSummary]);
|
}, [nutritionSummary]);
|
||||||
|
|
||||||
@@ -56,6 +80,34 @@ export function NutritionRadarCard({ nutritionSummary }: NutritionRadarCardProps
|
|||||||
];
|
];
|
||||||
}, [nutritionSummary]);
|
}, [nutritionSummary]);
|
||||||
|
|
||||||
|
// 计算还能吃的卡路里
|
||||||
|
const consumedCalories = nutritionSummary?.totalCalories || 0;
|
||||||
|
const remainingCalories = burnedCalories - consumedCalories - calorieDeficit;
|
||||||
|
|
||||||
|
// 餐次数据
|
||||||
|
const meals = [
|
||||||
|
{
|
||||||
|
type: 'breakfast' as const,
|
||||||
|
name: '早餐',
|
||||||
|
emoji: '🥚',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'lunch' as const,
|
||||||
|
name: '午餐',
|
||||||
|
emoji: '🍔',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'dinner' as const,
|
||||||
|
name: '晚餐',
|
||||||
|
emoji: '🥣',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'snack' as const,
|
||||||
|
name: '加餐',
|
||||||
|
emoji: '🍎',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
const handleNavigateToRecords = () => {
|
const handleNavigateToRecords = () => {
|
||||||
router.push(ROUTES.NUTRITION_RECORDS);
|
router.push(ROUTES.NUTRITION_RECORDS);
|
||||||
};
|
};
|
||||||
@@ -90,6 +142,74 @@ export function NutritionRadarCard({ nutritionSummary }: NutritionRadarCardProps
|
|||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
{/* 卡路里计算区域 */}
|
||||||
|
<View style={styles.calorieSection}>
|
||||||
|
<View style={styles.calorieContent}>
|
||||||
|
<Text style={styles.calorieSubtitle}>还能吃(千卡)</Text>
|
||||||
|
<View style={styles.calculationRow}>
|
||||||
|
<AnimatedNumber
|
||||||
|
value={remainingCalories}
|
||||||
|
resetToken={resetToken}
|
||||||
|
style={styles.mainValue}
|
||||||
|
format={(v) => Math.round(v).toString()}
|
||||||
|
/>
|
||||||
|
<Text style={styles.calculationText}> = </Text>
|
||||||
|
<View style={styles.calculationItem}>
|
||||||
|
<Ionicons name="flame" size={16} color="#FF6B6B" />
|
||||||
|
<Text style={styles.calculationLabel}>消耗</Text>
|
||||||
|
</View>
|
||||||
|
<AnimatedNumber
|
||||||
|
value={burnedCalories}
|
||||||
|
resetToken={resetToken}
|
||||||
|
style={styles.calculationValue}
|
||||||
|
format={(v) => Math.round(v).toString()}
|
||||||
|
/>
|
||||||
|
<Text style={styles.calculationText}> - </Text>
|
||||||
|
<View style={styles.calculationItem}>
|
||||||
|
<Ionicons name="restaurant" size={16} color="#4ECDC4" />
|
||||||
|
<Text style={styles.calculationLabel}>饮食</Text>
|
||||||
|
</View>
|
||||||
|
<AnimatedNumber
|
||||||
|
value={consumedCalories}
|
||||||
|
resetToken={resetToken}
|
||||||
|
style={styles.calculationValue}
|
||||||
|
format={(v) => Math.round(v).toString()}
|
||||||
|
/>
|
||||||
|
<Text style={styles.calculationText}> - </Text>
|
||||||
|
<View style={styles.calculationItem}>
|
||||||
|
<Ionicons name="trending-down" size={16} color="#95A5A6" />
|
||||||
|
<Text style={styles.calculationLabel}>缺口</Text>
|
||||||
|
</View>
|
||||||
|
<AnimatedNumber
|
||||||
|
value={calorieDeficit}
|
||||||
|
resetToken={resetToken}
|
||||||
|
style={styles.calculationValue}
|
||||||
|
format={(v) => Math.round(v).toString()}
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
|
||||||
|
{/* 餐次选择区域 */}
|
||||||
|
{/* <View style={styles.mealsContainer}>
|
||||||
|
{meals.map((meal) => (
|
||||||
|
<TouchableOpacity
|
||||||
|
key={meal.type}
|
||||||
|
style={styles.mealItem}
|
||||||
|
onPress={() => onMealPress?.(meal.type)}
|
||||||
|
activeOpacity={0.7}
|
||||||
|
>
|
||||||
|
<View style={styles.mealIconContainer}>
|
||||||
|
<Text style={styles.mealEmoji}>{meal.emoji}</Text>
|
||||||
|
<View style={styles.addButton}>
|
||||||
|
<Ionicons name="add" size={12} color="#FFFFFF" />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<Text style={styles.mealName}>{meal.name}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
))}
|
||||||
|
</View> */}
|
||||||
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -99,7 +219,6 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: '#FFFFFF',
|
backgroundColor: '#FFFFFF',
|
||||||
borderRadius: 22,
|
borderRadius: 22,
|
||||||
padding: 18,
|
padding: 18,
|
||||||
marginBottom: 16,
|
|
||||||
shadowColor: '#000',
|
shadowColor: '#000',
|
||||||
shadowOffset: {
|
shadowOffset: {
|
||||||
width: 0,
|
width: 0,
|
||||||
@@ -168,4 +287,103 @@ const styles = StyleSheet.create({
|
|||||||
color: '#192126',
|
color: '#192126',
|
||||||
fontWeight: '700',
|
fontWeight: '700',
|
||||||
},
|
},
|
||||||
|
// 卡路里相关样式
|
||||||
|
calorieSection: {
|
||||||
|
marginTop: 12,
|
||||||
|
},
|
||||||
|
|
||||||
|
calorieTitleContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
},
|
||||||
|
calorieIcon: {
|
||||||
|
fontSize: 16,
|
||||||
|
marginRight: 8,
|
||||||
|
},
|
||||||
|
calorieTitle: {
|
||||||
|
fontSize: 16,
|
||||||
|
fontWeight: '800',
|
||||||
|
color: '#192126',
|
||||||
|
},
|
||||||
|
calorieContent: {
|
||||||
|
},
|
||||||
|
calorieSubtitle: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: '#64748B',
|
||||||
|
marginBottom: 8,
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
|
calculationRow: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
flexWrap: 'wrap',
|
||||||
|
gap: 4,
|
||||||
|
},
|
||||||
|
mainValue: {
|
||||||
|
fontSize: 24,
|
||||||
|
fontWeight: '800',
|
||||||
|
color: '#192126',
|
||||||
|
},
|
||||||
|
calculationText: {
|
||||||
|
fontSize: 14,
|
||||||
|
fontWeight: '600',
|
||||||
|
color: '#64748B',
|
||||||
|
},
|
||||||
|
calculationItem: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 2,
|
||||||
|
},
|
||||||
|
calculationLabel: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: '#64748B',
|
||||||
|
fontWeight: '500',
|
||||||
|
},
|
||||||
|
calculationValue: {
|
||||||
|
fontSize: 12,
|
||||||
|
fontWeight: '700',
|
||||||
|
color: '#192126',
|
||||||
|
},
|
||||||
|
mealsContainer: {
|
||||||
|
flexDirection: 'row',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
paddingTop: 12,
|
||||||
|
borderTopWidth: 1,
|
||||||
|
borderTopColor: '#F1F5F9',
|
||||||
|
},
|
||||||
|
mealItem: {
|
||||||
|
alignItems: 'center',
|
||||||
|
flex: 1,
|
||||||
|
},
|
||||||
|
mealIconContainer: {
|
||||||
|
position: 'relative',
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
mealEmoji: {
|
||||||
|
fontSize: 24,
|
||||||
|
},
|
||||||
|
addButton: {
|
||||||
|
position: 'absolute',
|
||||||
|
top: -2,
|
||||||
|
right: -2,
|
||||||
|
width: 16,
|
||||||
|
height: 16,
|
||||||
|
borderRadius: 8,
|
||||||
|
backgroundColor: '#10B981',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
shadowColor: '#000',
|
||||||
|
shadowOffset: {
|
||||||
|
width: 0,
|
||||||
|
height: 2,
|
||||||
|
},
|
||||||
|
shadowOpacity: 0.1,
|
||||||
|
shadowRadius: 4,
|
||||||
|
elevation: 2,
|
||||||
|
},
|
||||||
|
mealName: {
|
||||||
|
fontSize: 10,
|
||||||
|
color: '#64748B',
|
||||||
|
fontWeight: '600',
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -10,10 +10,6 @@
|
|||||||
</array>
|
</array>
|
||||||
<key>com.apple.developer.healthkit</key>
|
<key>com.apple.developer.healthkit</key>
|
||||||
<true/>
|
<true/>
|
||||||
<key>com.apple.developer.healthkit.access</key>
|
|
||||||
<array>
|
|
||||||
<string>health-records</string>
|
|
||||||
</array>
|
|
||||||
<key>com.apple.developer.healthkit.background-delivery</key>
|
<key>com.apple.developer.healthkit.background-delivery</key>
|
||||||
<true/>
|
<true/>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
Reference in New Issue
Block a user