新增完整的轻断食功能,包括: - 断食计划列表和详情页面,支持12-12、14-10、16-8、18-6四种计划 - 断食状态实时追踪和倒计时显示 - 自定义开始时间选择器 - 断食通知提醒功能 - Redux状态管理和数据持久化 - 新增tab导航入口和路由配置
275 lines
6.8 KiB
TypeScript
275 lines
6.8 KiB
TypeScript
import { CircularRing } from '@/components/CircularRing';
|
|
import { Colors } from '@/constants/Colors';
|
|
import type { FastingPlan } from '@/constants/Fasting';
|
|
import { useColorScheme } from '@/hooks/useColorScheme';
|
|
import { LinearGradient } from 'expo-linear-gradient';
|
|
import React from 'react';
|
|
import {
|
|
StyleSheet,
|
|
Text,
|
|
TouchableOpacity,
|
|
View,
|
|
} from 'react-native';
|
|
|
|
type FastingOverviewCardProps = {
|
|
plan?: FastingPlan;
|
|
phaseLabel: string;
|
|
countdownLabel: string;
|
|
countdownValue: string;
|
|
startDayLabel: string;
|
|
startTimeLabel: string;
|
|
endDayLabel: string;
|
|
endTimeLabel: string;
|
|
onAdjustStartPress: () => void;
|
|
onViewMealsPress: () => void;
|
|
progress: number;
|
|
};
|
|
|
|
export function FastingOverviewCard({
|
|
plan,
|
|
phaseLabel,
|
|
countdownLabel,
|
|
countdownValue,
|
|
startDayLabel,
|
|
startTimeLabel,
|
|
endDayLabel,
|
|
endTimeLabel,
|
|
onAdjustStartPress,
|
|
onViewMealsPress,
|
|
progress,
|
|
}: FastingOverviewCardProps) {
|
|
const theme = useColorScheme() ?? 'light';
|
|
const colors = Colors[theme];
|
|
const themeColors = plan?.theme;
|
|
|
|
return (
|
|
<LinearGradient
|
|
colors={[
|
|
themeColors?.accentSecondary ?? colors.heroSurfaceTint,
|
|
themeColors?.backdrop ?? colors.pageBackgroundEmphasis,
|
|
]}
|
|
style={styles.container}
|
|
>
|
|
<View style={styles.headerRow}>
|
|
<View>
|
|
<Text style={styles.planLabel}>轻断食计划</Text>
|
|
{plan?.id && (
|
|
<View style={styles.planTag}>
|
|
<Text style={[styles.planTagText, { color: themeColors?.accent ?? colors.primary }]}>
|
|
{plan.id}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
{plan?.badge && (
|
|
<View style={[styles.badge, { backgroundColor: `${themeColors?.accent ?? colors.primary}20` }]}>
|
|
<Text style={[styles.badgeText, { color: themeColors?.accent ?? colors.primary }]}>
|
|
{plan.badge}
|
|
</Text>
|
|
</View>
|
|
)}
|
|
</View>
|
|
|
|
<View style={styles.scheduleRow}>
|
|
<View style={styles.scheduleCell}>
|
|
<Text style={styles.scheduleLabel}>断食开始时间</Text>
|
|
<Text style={styles.scheduleDay}>{startDayLabel}</Text>
|
|
<Text style={styles.scheduleTime}>{startTimeLabel}</Text>
|
|
</View>
|
|
<View style={styles.separator} />
|
|
<View style={styles.scheduleCell}>
|
|
<Text style={styles.scheduleLabel}>断食结束时间</Text>
|
|
<Text style={styles.scheduleDay}>{endDayLabel}</Text>
|
|
<Text style={styles.scheduleTime}>{endTimeLabel}</Text>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.statusRow}>
|
|
<View style={styles.ringContainer}>
|
|
<CircularRing
|
|
size={168}
|
|
strokeWidth={14}
|
|
progress={progress}
|
|
progressColor={themeColors?.ringProgress ?? colors.primary}
|
|
trackColor={themeColors?.ringTrack ?? 'rgba(0,0,0,0.05)'}
|
|
showCenterText={false}
|
|
startAngleDeg={-90}
|
|
resetToken={phaseLabel}
|
|
/>
|
|
<View style={styles.ringContent}>
|
|
<Text style={styles.phaseText}>{phaseLabel}</Text>
|
|
<Text style={styles.countdownLabel}>{countdownLabel}</Text>
|
|
<Text style={styles.countdownValue}>{countdownValue}</Text>
|
|
</View>
|
|
</View>
|
|
</View>
|
|
|
|
<View style={styles.actionsRow}>
|
|
<TouchableOpacity
|
|
style={[styles.secondaryButton, { borderColor: themeColors?.accent ?? colors.primary }]}
|
|
onPress={onAdjustStartPress}
|
|
activeOpacity={0.85}
|
|
>
|
|
<Text style={[styles.secondaryButtonText, { color: themeColors?.accent ?? colors.primary }]}>
|
|
提前开始断食
|
|
</Text>
|
|
</TouchableOpacity>
|
|
{/* <TouchableOpacity
|
|
style={[styles.primaryButton, { backgroundColor: themeColors?.accent ?? colors.primary }]}
|
|
onPress={onViewMealsPress}
|
|
activeOpacity={0.9}
|
|
>
|
|
<Text style={styles.primaryButtonText}>查看食谱</Text>
|
|
</TouchableOpacity> */}
|
|
</View>
|
|
</LinearGradient>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
borderRadius: 28,
|
|
paddingHorizontal: 20,
|
|
paddingVertical: 24,
|
|
shadowColor: '#000',
|
|
shadowOffset: { width: 0, height: 16 },
|
|
shadowOpacity: 0.08,
|
|
shadowRadius: 24,
|
|
elevation: 6,
|
|
},
|
|
headerRow: {
|
|
flexDirection: 'row',
|
|
justifyContent: 'space-between',
|
|
alignItems: 'center',
|
|
marginBottom: 24,
|
|
},
|
|
planLabel: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: '#2E3142',
|
|
marginBottom: 6,
|
|
},
|
|
planTag: {
|
|
alignSelf: 'flex-start',
|
|
backgroundColor: 'rgba(255,255,255,0.8)',
|
|
paddingHorizontal: 12,
|
|
paddingVertical: 6,
|
|
borderRadius: 12,
|
|
},
|
|
planTagText: {
|
|
fontSize: 13,
|
|
fontWeight: '600',
|
|
},
|
|
badge: {
|
|
paddingHorizontal: 14,
|
|
paddingVertical: 6,
|
|
borderRadius: 18,
|
|
},
|
|
badgeText: {
|
|
fontSize: 12,
|
|
fontWeight: '600',
|
|
},
|
|
scheduleRow: {
|
|
flexDirection: 'row',
|
|
borderRadius: 20,
|
|
backgroundColor: 'rgba(255,255,255,0.8)',
|
|
paddingVertical: 14,
|
|
paddingHorizontal: 16,
|
|
alignItems: 'center',
|
|
},
|
|
scheduleCell: {
|
|
flex: 1,
|
|
alignItems: 'center',
|
|
},
|
|
scheduleLabel: {
|
|
fontSize: 13,
|
|
color: '#70808E',
|
|
marginBottom: 6,
|
|
fontWeight: '500',
|
|
},
|
|
scheduleDay: {
|
|
fontSize: 16,
|
|
color: '#2E3142',
|
|
fontWeight: '600',
|
|
},
|
|
scheduleTime: {
|
|
fontSize: 24,
|
|
fontWeight: '700',
|
|
color: '#2E3142',
|
|
marginTop: 4,
|
|
},
|
|
separator: {
|
|
width: 1,
|
|
height: 52,
|
|
backgroundColor: 'rgba(112,128,142,0.22)',
|
|
},
|
|
statusRow: {
|
|
marginTop: 26,
|
|
alignItems: 'center',
|
|
},
|
|
ringContainer: {
|
|
width: 180,
|
|
height: 180,
|
|
borderRadius: 90,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
alignSelf: 'center',
|
|
position: 'relative',
|
|
},
|
|
ringContent: {
|
|
position: 'absolute',
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
},
|
|
phaseText: {
|
|
fontSize: 18,
|
|
fontWeight: '700',
|
|
color: '#2E3142',
|
|
marginBottom: 8,
|
|
},
|
|
countdownLabel: {
|
|
fontSize: 12,
|
|
color: '#6F7D87',
|
|
marginBottom: 4,
|
|
},
|
|
countdownValue: {
|
|
fontSize: 20,
|
|
fontWeight: '700',
|
|
color: '#2E3142',
|
|
letterSpacing: 1,
|
|
},
|
|
actionsRow: {
|
|
marginTop: 24,
|
|
flexDirection: 'row',
|
|
justifyContent: 'center',
|
|
alignItems: 'center',
|
|
},
|
|
secondaryButton: {
|
|
paddingHorizontal: 20,
|
|
borderWidth: 1.2,
|
|
borderRadius: 24,
|
|
paddingVertical: 14,
|
|
marginRight: 12,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
backgroundColor: 'rgba(255,255,255,0.92)',
|
|
},
|
|
secondaryButtonText: {
|
|
fontSize: 15,
|
|
fontWeight: '600',
|
|
},
|
|
primaryButton: {
|
|
flex: 1,
|
|
borderRadius: 24,
|
|
paddingVertical: 14,
|
|
alignItems: 'center',
|
|
justifyContent: 'center',
|
|
backgroundColor: '#2E3142',
|
|
},
|
|
primaryButtonText: {
|
|
fontSize: 15,
|
|
fontWeight: '700',
|
|
color: '#fff',
|
|
},
|
|
});
|