feat: 支持营养圆环
This commit is contained in:
@@ -16,7 +16,7 @@ export default function TabLayout() {
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
initialRouteName="coach"
|
||||
initialRouteName="statistics"
|
||||
screenOptions={({ route }) => {
|
||||
const routeName = route.name;
|
||||
const isSelected = (routeName === 'explore' && pathname === ROUTES.TAB_EXPLORE) ||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { AnimatedNumber } from '@/components/AnimatedNumber';
|
||||
import { BasalMetabolismCard } from '@/components/BasalMetabolismCard';
|
||||
import { DateSelector } from '@/components/DateSelector';
|
||||
import { FitnessRingsCard } from '@/components/FitnessRingsCard';
|
||||
@@ -332,7 +331,7 @@ export default function ExploreScreen() {
|
||||
{/* 营养摄入雷达图卡片 */}
|
||||
<NutritionRadarCard
|
||||
nutritionSummary={nutritionSummary}
|
||||
burnedCalories={basalMetabolism || 0}
|
||||
burnedCalories={(basalMetabolism || 0) + (activeCalories || 0)}
|
||||
calorieDeficit={0}
|
||||
resetToken={animToken}
|
||||
onMealPress={(mealType: 'breakfast' | 'lunch' | 'dinner' | 'snack') => {
|
||||
@@ -355,28 +354,6 @@ export default function ExploreScreen() {
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
|
||||
<FloatingCard style={styles.masonryCard} delay={500}>
|
||||
<Text style={styles.cardTitle}>消耗卡路里</Text>
|
||||
<View style={{
|
||||
flexDirection: 'row',
|
||||
alignItems: 'flex-end',
|
||||
marginTop: 20
|
||||
}}>
|
||||
{activeCalories != null ? (
|
||||
<AnimatedNumber
|
||||
value={activeCalories}
|
||||
resetToken={animToken}
|
||||
style={styles.caloriesValue}
|
||||
format={(v) => `${Math.round(v)}`}
|
||||
/>
|
||||
) : (
|
||||
<Text style={styles.caloriesValue}>——</Text>
|
||||
)}
|
||||
<Text style={styles.caloriesUnit}>千卡</Text>
|
||||
</View>
|
||||
</FloatingCard>
|
||||
|
||||
<FloatingCard style={styles.masonryCard}>
|
||||
<StepsCard
|
||||
stepCount={stepCount}
|
||||
@@ -392,6 +369,15 @@ export default function ExploreScreen() {
|
||||
hrvValue={hrvValue}
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
{/* 心率卡片 */}
|
||||
<FloatingCard style={styles.masonryCard} delay={2000}>
|
||||
<HeartRateCard
|
||||
resetToken={animToken}
|
||||
style={styles.basalMetabolismCardOverride}
|
||||
heartRate={heartRate}
|
||||
/>
|
||||
</FloatingCard>
|
||||
</View>
|
||||
|
||||
{/* 右列 */}
|
||||
@@ -439,14 +425,6 @@ export default function ExploreScreen() {
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
{/* 心率卡片 */}
|
||||
<FloatingCard style={styles.masonryCard} delay={2000}>
|
||||
<HeartRateCard
|
||||
resetToken={animToken}
|
||||
style={styles.basalMetabolismCardOverride}
|
||||
heartRate={heartRate}
|
||||
/>
|
||||
</FloatingCard>
|
||||
|
||||
</View>
|
||||
</View>
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function SplashScreen() {
|
||||
// router.replace('/onboarding');
|
||||
// }
|
||||
// setIsLoading(false);
|
||||
router.replace(ROUTES.TAB_COACH);
|
||||
router.replace(ROUTES.TAB_STATISTICS);
|
||||
} catch (error) {
|
||||
console.error('检查引导状态失败:', error);
|
||||
// 如果出现错误,默认显示引导页面
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
import { CalorieRingChart } from '@/components/CalorieRingChart';
|
||||
import { DateSelector } from '@/components/DateSelector';
|
||||
import { NutritionRecordCard } from '@/components/NutritionRecordCard';
|
||||
import { HeaderBar } from '@/components/ui/HeaderBar';
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { DietRecord, deleteDietRecord, getDietRecords } from '@/services/dietRecords';
|
||||
import { selectHealthDataByDate } from '@/store/healthSlice';
|
||||
import { fetchDailyNutritionData, selectNutritionSummaryByDate } from '@/store/nutritionSlice';
|
||||
import { getMonthDaysZh, getMonthTitleZh, getTodayIndexInMonth } from '@/utils/date';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import dayjs from 'dayjs';
|
||||
import { router } from 'expo-router';
|
||||
import React, { useEffect, useRef, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
ActivityIndicator,
|
||||
FlatList,
|
||||
RefreshControl,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
@@ -24,12 +28,26 @@ type ViewMode = 'daily' | 'all';
|
||||
export default function NutritionRecordsScreen() {
|
||||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||||
const colorTokens = Colors[theme];
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
// 日期相关状态 - 使用与统计页面相同的日期逻辑
|
||||
const days = getMonthDaysZh();
|
||||
const [selectedIndex, setSelectedIndex] = useState(getTodayIndexInMonth());
|
||||
const monthTitle = getMonthTitleZh();
|
||||
|
||||
// 获取当前选中日期
|
||||
const getCurrentSelectedDate = () => {
|
||||
return days[selectedIndex]?.date?.toDate() ?? new Date();
|
||||
};
|
||||
|
||||
const currentSelectedDate = getCurrentSelectedDate();
|
||||
const currentSelectedDateString = dayjs(currentSelectedDate).format('YYYY-MM-DD');
|
||||
|
||||
// 从 Redux 获取数据
|
||||
const healthData = useAppSelector(selectHealthDataByDate(currentSelectedDateString));
|
||||
const nutritionSummary = useAppSelector(selectNutritionSummaryByDate(currentSelectedDateString));
|
||||
const userProfile = useAppSelector((state) => state.user.profile);
|
||||
|
||||
// 视图模式:按天查看 vs 全部查看
|
||||
const [viewMode, setViewMode] = useState<ViewMode>('daily');
|
||||
|
||||
@@ -40,41 +58,6 @@ export default function NutritionRecordsScreen() {
|
||||
const [hasMoreData, setHasMoreData] = useState(true);
|
||||
const [page, setPage] = useState(1);
|
||||
|
||||
// 日期滚动相关
|
||||
const daysScrollRef = useRef<ScrollView | null>(null);
|
||||
const [scrollWidth, setScrollWidth] = useState(0);
|
||||
const DAY_PILL_WIDTH = 60; // 48px width + 12px marginRight = 60px total per item
|
||||
const DAY_PILL_SPACING = 0; // spacing is included in the width above
|
||||
|
||||
// 日期滚动控制
|
||||
const scrollToIndex = (index: number, animated = true) => {
|
||||
if (scrollWidth <= 0) return;
|
||||
|
||||
const itemOffset = index * DAY_PILL_WIDTH;
|
||||
const scrollViewCenterX = scrollWidth / 2;
|
||||
const itemCenterX = DAY_PILL_WIDTH / 2;
|
||||
const centerOffset = Math.max(0, itemOffset - scrollViewCenterX + itemCenterX);
|
||||
|
||||
daysScrollRef.current?.scrollTo({ x: centerOffset, animated });
|
||||
};
|
||||
|
||||
// 初始化时滚动到选中位置
|
||||
useEffect(() => {
|
||||
if (scrollWidth > 0) {
|
||||
// 延迟滚动以确保ScrollView已经完全渲染
|
||||
setTimeout(() => {
|
||||
scrollToIndex(selectedIndex, false);
|
||||
}, 100);
|
||||
}
|
||||
}, [scrollWidth]);
|
||||
|
||||
// 选中日期变化时滚动
|
||||
useEffect(() => {
|
||||
if (scrollWidth > 0) {
|
||||
scrollToIndex(selectedIndex, true);
|
||||
}
|
||||
}, [selectedIndex]);
|
||||
|
||||
// 加载记录数据
|
||||
const loadRecords = async (isRefresh = false, loadMore = false) => {
|
||||
try {
|
||||
@@ -126,10 +109,50 @@ export default function NutritionRecordsScreen() {
|
||||
loadRecords();
|
||||
}, [selectedIndex, viewMode]);
|
||||
|
||||
// 当选中日期变化时获取营养数据
|
||||
useEffect(() => {
|
||||
if (viewMode === 'daily') {
|
||||
dispatch(fetchDailyNutritionData(currentSelectedDate));
|
||||
}
|
||||
}, [selectedIndex, viewMode, currentSelectedDate, dispatch]);
|
||||
|
||||
const onRefresh = () => {
|
||||
loadRecords(true);
|
||||
};
|
||||
|
||||
// 计算营养目标
|
||||
const calculateNutritionGoals = () => {
|
||||
const weight = parseFloat(userProfile?.weight || '70'); // 默认70kg
|
||||
const height = parseFloat(userProfile?.height || '170'); // 默认170cm
|
||||
const age = userProfile?.birthDate ?
|
||||
dayjs().diff(dayjs(userProfile.birthDate), 'year') : 25; // 默认25岁
|
||||
const isWoman = userProfile?.gender === 'female';
|
||||
|
||||
// 基础代谢率计算(Mifflin-St Jeor Equation)
|
||||
let bmr;
|
||||
if (isWoman) {
|
||||
bmr = 10 * weight + 6.25 * height - 5 * age - 161;
|
||||
} else {
|
||||
bmr = 10 * weight + 6.25 * height - 5 * age + 5;
|
||||
}
|
||||
|
||||
// 总热量需求(假设轻度活动)
|
||||
const totalCalories = bmr * 1.375;
|
||||
|
||||
// 计算营养素目标
|
||||
const proteinGoal = weight * 1.6; // 1.6g/kg
|
||||
const fatGoal = totalCalories * 0.25 / 9; // 25%来自脂肪,9卡/克
|
||||
const carbsGoal = (totalCalories - proteinGoal * 4 - fatGoal * 9) / 4; // 剩余来自碳水
|
||||
|
||||
return {
|
||||
proteinGoal: Math.round(proteinGoal * 10) / 10,
|
||||
fatGoal: Math.round(fatGoal * 10) / 10,
|
||||
carbsGoal: Math.round(carbsGoal * 10) / 10,
|
||||
};
|
||||
};
|
||||
|
||||
const nutritionGoals = calculateNutritionGoals();
|
||||
|
||||
const loadMoreRecords = () => {
|
||||
if (hasMoreData && !loading && !refreshing) {
|
||||
loadRecords(false, true);
|
||||
@@ -254,6 +277,20 @@ export default function NutritionRecordsScreen() {
|
||||
{renderViewModeToggle()}
|
||||
{renderDateSelector()}
|
||||
|
||||
{/* Calorie Ring Chart */}
|
||||
<CalorieRingChart
|
||||
metabolism={healthData?.basalEnergyBurned || 1482}
|
||||
exercise={healthData?.activeEnergyBurned || 0}
|
||||
consumed={nutritionSummary?.totalCalories || 0}
|
||||
goal={userProfile?.dailyCaloriesGoal || 200}
|
||||
protein={nutritionSummary?.totalProtein || 0}
|
||||
fat={nutritionSummary?.totalFat || 0}
|
||||
carbs={nutritionSummary?.totalCarbohydrate || 0}
|
||||
proteinGoal={nutritionGoals.proteinGoal}
|
||||
fatGoal={nutritionGoals.fatGoal}
|
||||
carbsGoal={nutritionGoals.carbsGoal}
|
||||
/>
|
||||
|
||||
{loading ? (
|
||||
<View style={styles.loadingContainer}>
|
||||
<ActivityIndicator size="large" color={colorTokens.primary} />
|
||||
|
||||
300
components/CalorieRingChart.tsx
Normal file
300
components/CalorieRingChart.tsx
Normal file
@@ -0,0 +1,300 @@
|
||||
import { ThemedText } from '@/components/ThemedText';
|
||||
import { useThemeColor } from '@/hooks/useThemeColor';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { Animated, StyleSheet, View } from 'react-native';
|
||||
import Svg, { Circle } from 'react-native-svg';
|
||||
|
||||
const AnimatedCircle = Animated.createAnimatedComponent(Circle);
|
||||
|
||||
export type CalorieRingChartProps = {
|
||||
metabolism: number;
|
||||
exercise: number;
|
||||
consumed: number;
|
||||
goal: number;
|
||||
protein: number;
|
||||
fat: number;
|
||||
carbs: number;
|
||||
proteinGoal: number;
|
||||
fatGoal: number;
|
||||
carbsGoal: number;
|
||||
};
|
||||
|
||||
export function CalorieRingChart({
|
||||
metabolism,
|
||||
exercise,
|
||||
consumed,
|
||||
goal,
|
||||
protein,
|
||||
fat,
|
||||
carbs,
|
||||
proteinGoal,
|
||||
fatGoal,
|
||||
carbsGoal,
|
||||
}: CalorieRingChartProps) {
|
||||
const surfaceColor = useThemeColor({}, 'surface');
|
||||
const textColor = useThemeColor({}, 'text');
|
||||
const textSecondaryColor = useThemeColor({}, 'textSecondary');
|
||||
|
||||
// 动画值
|
||||
const animatedProgress = useRef(new Animated.Value(0)).current;
|
||||
|
||||
// 计算还能吃多少卡路里
|
||||
const remainingCalories = metabolism + exercise - consumed - goal;
|
||||
const canEat = Math.max(0, remainingCalories);
|
||||
|
||||
// 计算进度百分比 (用于圆环显示)
|
||||
const totalAvailable = metabolism + exercise - goal;
|
||||
const progressPercentage = totalAvailable > 0 ? Math.min((consumed / totalAvailable) * 100, 100) : 0;
|
||||
|
||||
// 圆环参数 - 更小的圆环以适应布局
|
||||
const radius = 62;
|
||||
const strokeWidth = 6;
|
||||
const center = radius + strokeWidth;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
const strokeDasharray = circumference;
|
||||
|
||||
// 动画效果
|
||||
useEffect(() => {
|
||||
Animated.timing(animatedProgress, {
|
||||
toValue: progressPercentage,
|
||||
duration: 600,
|
||||
useNativeDriver: false,
|
||||
}).start();
|
||||
}, [progressPercentage]);
|
||||
|
||||
// 使用动画值计算strokeDashoffset
|
||||
const strokeDashoffset = animatedProgress.interpolate({
|
||||
inputRange: [0, 100],
|
||||
outputRange: [circumference, 0],
|
||||
extrapolate: 'clamp',
|
||||
});
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { backgroundColor: surfaceColor }]}>
|
||||
{/* 左上角公式展示 */}
|
||||
<View style={styles.formulaContainer}>
|
||||
<ThemedText style={[styles.formulaText, { color: textSecondaryColor }]}>
|
||||
还能吃 = 代谢 + 运动 - 饮食 - 目标
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
{/* 主要内容区域 */}
|
||||
<View style={styles.mainContent}>
|
||||
{/* 左侧圆环图 */}
|
||||
<View style={styles.chartContainer}>
|
||||
<Svg width={center * 2} height={center * 2}>
|
||||
{/* 背景圆环 */}
|
||||
<Circle
|
||||
cx={center}
|
||||
cy={center}
|
||||
r={radius}
|
||||
stroke="#F0F0F0"
|
||||
strokeWidth={strokeWidth}
|
||||
fill="none"
|
||||
/>
|
||||
{/* 进度圆环 - 保持固定颜色 */}
|
||||
<AnimatedCircle
|
||||
cx={center}
|
||||
cy={center}
|
||||
r={radius}
|
||||
stroke={progressPercentage > 80 ? "#FF6B6B" : "#E0E0E0"}
|
||||
strokeWidth={strokeWidth}
|
||||
fill="none"
|
||||
strokeDasharray={`${strokeDasharray}`}
|
||||
strokeDashoffset={strokeDashoffset}
|
||||
strokeLinecap="round"
|
||||
transform={`rotate(-90 ${center} ${center})`}
|
||||
/>
|
||||
</Svg>
|
||||
|
||||
{/* 中心内容 */}
|
||||
<View style={styles.centerContent}>
|
||||
<ThemedText style={[styles.centerLabel, { color: textSecondaryColor }]}>
|
||||
还能吃
|
||||
</ThemedText>
|
||||
<ThemedText style={[styles.centerValue, { color: textColor }]}>
|
||||
{canEat.toLocaleString()}千卡
|
||||
</ThemedText>
|
||||
<ThemedText style={[styles.centerPercentage, { color: textSecondaryColor }]}>
|
||||
{Math.round(progressPercentage)}%
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 右侧数据展示 */}
|
||||
<View style={styles.dataContainer}>
|
||||
{/* 各项数值 */}
|
||||
<View style={styles.dataItem}>
|
||||
<ThemedText style={[styles.dataLabel, { color: textSecondaryColor }]}>代谢</ThemedText>
|
||||
<ThemedText style={[styles.dataValue, { color: textColor }]}>
|
||||
{metabolism.toLocaleString()}千卡
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.dataItem}>
|
||||
<ThemedText style={[styles.dataLabel, { color: textSecondaryColor }]}>运动</ThemedText>
|
||||
<ThemedText style={[styles.dataValue, { color: textColor }]}>
|
||||
{exercise}千卡
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.dataItem}>
|
||||
<ThemedText style={[styles.dataLabel, { color: textSecondaryColor }]}>饮食</ThemedText>
|
||||
<ThemedText style={[styles.dataValue, { color: textColor }]}>
|
||||
{consumed}千卡
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.dataItem}>
|
||||
<ThemedText style={[styles.dataLabel, { color: textSecondaryColor }]}>目标</ThemedText>
|
||||
<ThemedText style={[styles.dataValue, { color: textColor }]}>
|
||||
{goal}千卡
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{/* 底部营养素展示 */}
|
||||
<View style={styles.nutritionContainer}>
|
||||
<View style={styles.nutritionItem}>
|
||||
<ThemedText style={[styles.nutritionLabel, { color: textSecondaryColor }]}>
|
||||
蛋白质
|
||||
</ThemedText>
|
||||
<ThemedText style={[styles.nutritionValue, { color: textColor }]}>
|
||||
{protein.toFixed(2)}/{proteinGoal.toFixed(2)}g
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.nutritionItem}>
|
||||
<ThemedText style={[styles.nutritionLabel, { color: textSecondaryColor }]}>
|
||||
脂肪
|
||||
</ThemedText>
|
||||
<ThemedText style={[styles.nutritionValue, { color: textColor }]}>
|
||||
{fat.toFixed(2)}/{fatGoal.toFixed(2)}g
|
||||
</ThemedText>
|
||||
</View>
|
||||
|
||||
<View style={styles.nutritionItem}>
|
||||
<ThemedText style={[styles.nutritionLabel, { color: textSecondaryColor }]}>
|
||||
碳水化合物
|
||||
</ThemedText>
|
||||
<ThemedText style={[styles.nutritionValue, { color: textColor }]}>
|
||||
{carbs.toFixed(2)}/{carbsGoal.toFixed(2)}g
|
||||
</ThemedText>
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
backgroundColor: '#FFFFFF',
|
||||
borderRadius: 16,
|
||||
padding: 16,
|
||||
marginHorizontal: 16,
|
||||
marginBottom: 16,
|
||||
shadowColor: '#000000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.04,
|
||||
shadowRadius: 8,
|
||||
elevation: 2,
|
||||
},
|
||||
formulaContainer: {
|
||||
alignItems: 'flex-start',
|
||||
marginBottom: 12,
|
||||
},
|
||||
formulaText: {
|
||||
fontSize: 12,
|
||||
fontWeight: '500',
|
||||
color: '#999999',
|
||||
lineHeight: 16,
|
||||
},
|
||||
mainContent: {
|
||||
width: '100%',
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 16,
|
||||
paddingHorizontal: 8,
|
||||
},
|
||||
chartContainer: {
|
||||
position: 'relative',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: 140,
|
||||
flexShrink: 0,
|
||||
},
|
||||
centerContent: {
|
||||
position: 'absolute',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
centerLabel: {
|
||||
fontSize: 11,
|
||||
fontWeight: '500',
|
||||
color: '#999999',
|
||||
marginBottom: 2,
|
||||
},
|
||||
centerValue: {
|
||||
fontSize: 16,
|
||||
fontWeight: '700',
|
||||
color: '#333333',
|
||||
marginBottom: 1,
|
||||
},
|
||||
centerPercentage: {
|
||||
fontSize: 11,
|
||||
fontWeight: '500',
|
||||
color: '#999999',
|
||||
},
|
||||
dataContainer: {
|
||||
flex: 1,
|
||||
marginLeft: 32,
|
||||
gap: 4,
|
||||
paddingLeft: 8,
|
||||
},
|
||||
dataItem: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
gap: 4,
|
||||
paddingVertical: 2,
|
||||
},
|
||||
dataIcon: {
|
||||
width: 6,
|
||||
height: 6,
|
||||
borderRadius: 3,
|
||||
},
|
||||
dataLabel: {
|
||||
fontSize: 11,
|
||||
fontWeight: '500',
|
||||
color: '#999999',
|
||||
minWidth: 28,
|
||||
},
|
||||
dataValue: {
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
color: '#333333',
|
||||
},
|
||||
nutritionContainer: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
paddingTop: 12,
|
||||
borderTopWidth: 1,
|
||||
borderTopColor: 'rgba(0,0,0,0.06)',
|
||||
},
|
||||
nutritionItem: {
|
||||
alignItems: 'center',
|
||||
flex: 1,
|
||||
},
|
||||
nutritionLabel: {
|
||||
fontSize: 10,
|
||||
fontWeight: '500',
|
||||
color: '#999999',
|
||||
marginBottom: 3,
|
||||
},
|
||||
nutritionValue: {
|
||||
fontSize: 11,
|
||||
fontWeight: '600',
|
||||
color: '#333333',
|
||||
},
|
||||
});
|
||||
@@ -463,7 +463,10 @@
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = YES;
|
||||
ONLY_ACTIVE_ARCH = YES;
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = "$(inherited) DEBUG";
|
||||
@@ -518,7 +521,10 @@
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift\"$(inherited)\"";
|
||||
MTL_ENABLE_DEBUG_INFO = NO;
|
||||
OTHER_LDFLAGS = "$(inherited) ";
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
" ",
|
||||
);
|
||||
REACT_NATIVE_PATH = "${PODS_ROOT}/../../node_modules/react-native";
|
||||
SDKROOT = iphoneos;
|
||||
USE_HERMES = false;
|
||||
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
@@ -5895,6 +5895,7 @@
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://mirrors.tencent.com/npm/css-select/-/css-select-5.2.2.tgz",
|
||||
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"boolbase": "^1.0.0",
|
||||
"css-what": "^6.1.0",
|
||||
@@ -5921,6 +5922,7 @@
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://mirrors.tencent.com/npm/css-tree/-/css-tree-1.1.3.tgz",
|
||||
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.14",
|
||||
"source-map": "^0.6.1"
|
||||
@@ -5933,6 +5935,7 @@
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://mirrors.tencent.com/npm/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
@@ -6179,6 +6182,7 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://mirrors.tencent.com/npm/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0",
|
||||
"domhandler": "^5.0.2",
|
||||
@@ -6204,6 +6208,7 @@
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://mirrors.tencent.com/npm/domhandler/-/domhandler-5.0.3.tgz",
|
||||
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"domelementtype": "^2.3.0"
|
||||
},
|
||||
@@ -6218,6 +6223,7 @@
|
||||
"version": "3.2.2",
|
||||
"resolved": "https://mirrors.tencent.com/npm/domutils/-/domutils-3.2.2.tgz",
|
||||
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"dom-serializer": "^2.0.0",
|
||||
"domelementtype": "^2.3.0",
|
||||
|
||||
85
types/react-native-svg.d.ts
vendored
85
types/react-native-svg.d.ts
vendored
@@ -1,85 +0,0 @@
|
||||
declare module 'react-native-svg' {
|
||||
import * as React from 'react';
|
||||
import { ViewProps } from 'react-native';
|
||||
|
||||
export interface SvgProps extends ViewProps {
|
||||
width?: number | string;
|
||||
height?: number | string;
|
||||
viewBox?: string;
|
||||
}
|
||||
export default function Svg(props: React.PropsWithChildren<SvgProps>): React.ReactElement | null;
|
||||
|
||||
export interface CommonProps {
|
||||
fill?: string;
|
||||
stroke?: string;
|
||||
strokeWidth?: number;
|
||||
strokeLinecap?: 'butt' | 'round' | 'square';
|
||||
strokeLinejoin?: 'miter' | 'round' | 'bevel';
|
||||
strokeDasharray?: string | number[];
|
||||
strokeDashoffset?: number;
|
||||
}
|
||||
|
||||
export interface CircleProps extends CommonProps {
|
||||
cx?: number;
|
||||
cy?: number;
|
||||
r?: number;
|
||||
originX?: number;
|
||||
originY?: number;
|
||||
}
|
||||
export const Circle: React.ComponentType<CircleProps>;
|
||||
|
||||
export interface GProps extends CommonProps {
|
||||
rotation?: number;
|
||||
originX?: number;
|
||||
originY?: number;
|
||||
}
|
||||
export const G: React.ComponentType<React.PropsWithChildren<GProps>>;
|
||||
|
||||
export interface DefsProps { }
|
||||
export const Defs: React.ComponentType<React.PropsWithChildren<DefsProps>>;
|
||||
|
||||
export interface LineProps extends CommonProps {
|
||||
x1?: number | string;
|
||||
y1?: number | string;
|
||||
x2?: number | string;
|
||||
y2?: number | string;
|
||||
}
|
||||
export const Line: React.ComponentType<LineProps>;
|
||||
|
||||
export interface LinearGradientProps {
|
||||
id?: string;
|
||||
x1?: number | string;
|
||||
y1?: number | string;
|
||||
x2?: number | string;
|
||||
y2?: number | string;
|
||||
}
|
||||
export const LinearGradient: React.ComponentType<React.PropsWithChildren<LinearGradientProps>>;
|
||||
|
||||
export interface StopProps {
|
||||
offset?: number | string;
|
||||
stopColor?: string;
|
||||
stopOpacity?: number;
|
||||
}
|
||||
export const Stop: React.ComponentType<StopProps>;
|
||||
|
||||
export interface PolygonProps extends CommonProps {
|
||||
points?: string;
|
||||
}
|
||||
export const Polygon: React.ComponentType<PolygonProps>;
|
||||
|
||||
export interface PathProps extends CommonProps {
|
||||
d?: string;
|
||||
}
|
||||
export const Path: React.ComponentType<PathProps>;
|
||||
|
||||
export interface TextProps extends CommonProps {
|
||||
x?: number | string;
|
||||
y?: number | string;
|
||||
fontSize?: number | string;
|
||||
fill?: string;
|
||||
textAnchor?: 'start' | 'middle' | 'end';
|
||||
}
|
||||
export const Text: React.ComponentType<React.PropsWithChildren<TextProps>>;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user