Files
digital-pilates/components/fasting/FastingOverviewCard.tsx
richarjiang e03b2b3032 feat(fasting): 新增轻断食功能模块
新增完整的轻断食功能,包括:
- 断食计划列表和详情页面,支持12-12、14-10、16-8、18-6四种计划
- 断食状态实时追踪和倒计时显示
- 自定义开始时间选择器
- 断食通知提醒功能
- Redux状态管理和数据持久化
- 新增tab导航入口和路由配置
2025-10-13 19:21:29 +08:00

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',
},
});