Files
digital-pilates/components/GoalCarousel.tsx
richarjiang 20a244e375 feat: 实现目标通知功能及相关组件
- 新增目标通知功能,支持根据用户创建目标时选择的频率和开始时间自动创建本地定时推送通知
- 实现每日、每周和每月的重复类型,用户可自定义选择提醒时间和重复规则
- 集成目标通知测试组件,方便开发者测试不同类型的通知
- 更新相关文档,详细描述目标通知功能的实现和使用方法
- 优化目标页面,确保用户体验和界面一致性
2025-08-23 17:13:04 +08:00

103 lines
2.5 KiB
TypeScript

import { Colors } from '@/constants/Colors';
import { useColorScheme } from '@/hooks/useColorScheme';
import React, { useRef } from 'react';
import { Dimensions, ScrollView, StyleSheet, Text, View } from 'react-native';
import { GoalCard, GoalItem } from './GoalCard';
interface GoalCarouselProps {
goals: GoalItem[];
onGoalPress?: (item: GoalItem) => void;
}
const { width: screenWidth } = Dimensions.get('window');
export function GoalCarousel({ goals, onGoalPress }: GoalCarouselProps) {
const theme = useColorScheme() ?? 'light';
const colorTokens = Colors[theme];
const scrollViewRef = useRef<ScrollView>(null);
if (!goals || goals.length === 0) {
return (
<View style={styles.emptyContainer}>
<Text style={[styles.emptyText, { color: colorTokens.textMuted }]}>
</Text>
</View>
);
}
return (
<View style={styles.container}>
<ScrollView
ref={scrollViewRef}
horizontal
showsHorizontalScrollIndicator={false}
snapToInterval={(screenWidth - 60) * 0.65 + 16} // 卡片宽度 + 间距
snapToAlignment="start"
decelerationRate="fast"
contentContainerStyle={styles.scrollContent}
style={styles.scrollView}
>
{goals.map((item, index) => (
<GoalCard
key={item.id}
item={item}
onPress={onGoalPress}
/>
))}
{/* 占位符,确保最后一张卡片有足够的滑动空间 */}
<View style={{ width: 20 }} />
</ScrollView>
{/* 底部指示器 */}
{/* <View style={styles.indicatorContainer}>
{goals.map((_, index) => (
<View
key={index}
style={[
styles.indicator,
{ backgroundColor: index === 0 ? colorTokens.primary : colorTokens.border }
]}
/>
))}
</View> */}
</View>
);
}
const styles = StyleSheet.create({
container: {
},
scrollView: {
},
scrollContent: {
paddingHorizontal: 20,
alignItems: 'center',
},
emptyContainer: {
height: 140,
justifyContent: 'center',
alignItems: 'center',
marginHorizontal: 20,
borderRadius: 20,
borderWidth: 1,
borderColor: '#E5E7EB',
borderStyle: 'dashed',
},
emptyText: {
fontSize: 14,
fontWeight: '500',
},
indicatorContainer: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
gap: 6,
},
indicator: {
width: 6,
height: 6,
borderRadius: 3,
},
});