feat: 新增动画资源与庆祝效果,优化布局与标签页配置
This commit is contained in:
62
components/CelebrationAnimation.tsx
Normal file
62
components/CelebrationAnimation.tsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import LottieView from 'lottie-react-native';
|
||||
import React, { forwardRef, useImperativeHandle, useRef } from 'react';
|
||||
import {
|
||||
Dimensions,
|
||||
StyleSheet,
|
||||
View,
|
||||
} from 'react-native';
|
||||
|
||||
export interface CelebrationAnimationRef {
|
||||
play: () => void;
|
||||
}
|
||||
|
||||
interface CelebrationAnimationProps {
|
||||
visible?: boolean;
|
||||
}
|
||||
|
||||
const CelebrationAnimation = forwardRef<CelebrationAnimationRef, CelebrationAnimationProps>(
|
||||
({ visible = true }, ref) => {
|
||||
const animationRef = useRef<LottieView>(null);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
play: () => {
|
||||
animationRef.current?.play();
|
||||
},
|
||||
}));
|
||||
|
||||
if (!visible) return null;
|
||||
|
||||
return (
|
||||
<View style={styles.container} pointerEvents="none">
|
||||
<LottieView
|
||||
ref={animationRef}
|
||||
autoPlay={false}
|
||||
loop={false}
|
||||
source={require('@/assets/lottie/Confetti.json')}
|
||||
style={styles.animation}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
position: 'absolute',
|
||||
top: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
zIndex: 9999,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
animation: {
|
||||
width: Dimensions.get('window').width,
|
||||
height: Dimensions.get('window').height,
|
||||
},
|
||||
});
|
||||
|
||||
CelebrationAnimation.displayName = 'CelebrationAnimation';
|
||||
|
||||
export default CelebrationAnimation;
|
||||
@@ -1,6 +1,7 @@
|
||||
import { MoodCheckin, getMoodConfig } from '@/services/moodCheckins';
|
||||
import dayjs from 'dayjs';
|
||||
import React from 'react';
|
||||
import LottieView from 'lottie-react-native';
|
||||
import React, { useEffect, useRef } from 'react';
|
||||
import { StyleSheet, Text, TouchableOpacity, View } from 'react-native';
|
||||
|
||||
interface MoodCardProps {
|
||||
@@ -11,10 +12,26 @@ interface MoodCardProps {
|
||||
|
||||
export function MoodCard({ moodCheckin, onPress, isLoading = false }: MoodCardProps) {
|
||||
const moodConfig = moodCheckin ? getMoodConfig(moodCheckin.moodType) : null;
|
||||
const animationRef = useRef<LottieView>(null);
|
||||
|
||||
useEffect(() => {
|
||||
if (animationRef.current) {
|
||||
animationRef.current.play();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<TouchableOpacity onPress={onPress} style={styles.moodCardContent} disabled={isLoading}>
|
||||
<Text style={styles.cardTitle}>心情</Text>
|
||||
<View style={styles.moodCardHeader}>
|
||||
<Text style={styles.cardTitle}>心情</Text>
|
||||
<LottieView
|
||||
ref={animationRef}
|
||||
source={require('@/assets/lottie/mood/mood_demo.json')}
|
||||
autoPlay
|
||||
loop
|
||||
style={styles.lottieAnimation}
|
||||
/>
|
||||
</View>
|
||||
{isLoading ? (
|
||||
<View style={styles.moodPreview}>
|
||||
<Text style={styles.moodLoadingText}>加载中...</Text>
|
||||
@@ -40,11 +57,22 @@ const styles = StyleSheet.create({
|
||||
width: '100%',
|
||||
},
|
||||
|
||||
moodCardHeader: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
|
||||
cardTitle: {
|
||||
fontSize: 14,
|
||||
color: '#192126',
|
||||
},
|
||||
|
||||
lottieAnimation: {
|
||||
width: 40,
|
||||
height: 40,
|
||||
},
|
||||
|
||||
moodPreview: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
|
||||
@@ -10,10 +10,12 @@ import { Alert, Animated, Image, StyleSheet, Text, TouchableOpacity, View } from
|
||||
|
||||
interface TaskCardProps {
|
||||
task: TaskListItem;
|
||||
onTaskCompleted?: (task: TaskListItem) => void; // 任务完成回调
|
||||
}
|
||||
|
||||
export const TaskCard: React.FC<TaskCardProps> = ({
|
||||
task,
|
||||
onTaskCompleted,
|
||||
}) => {
|
||||
const theme = useColorScheme() ?? 'light';
|
||||
const colorTokens = Colors[theme];
|
||||
@@ -98,6 +100,9 @@ export const TaskCard: React.FC<TaskCardProps> = ({
|
||||
notes: '通过任务卡片完成'
|
||||
}
|
||||
})).unwrap();
|
||||
|
||||
// 触发任务完成回调
|
||||
onTaskCompleted?.(task);
|
||||
|
||||
} catch (error) {
|
||||
Alert.alert('错误', '完成任务失败,请重试');
|
||||
|
||||
@@ -2,7 +2,8 @@ import { useWaterDataByDate } from '@/hooks/useWaterData';
|
||||
import { getQuickWaterAmount } from '@/utils/userPreferences';
|
||||
import dayjs from 'dayjs';
|
||||
import * as Haptics from 'expo-haptics';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import LottieView from 'lottie-react-native';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
import {
|
||||
Animated,
|
||||
StyleSheet,
|
||||
@@ -31,6 +32,8 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
|
||||
const currentIntake = waterStats?.totalAmount || 0;
|
||||
const targetIntake = dailyWaterGoal || 2000;
|
||||
|
||||
const animationRef = useRef<LottieView>(null);
|
||||
|
||||
// 为每个时间点创建独立的动画值
|
||||
const animatedValues = useMemo(() =>
|
||||
Array.from({ length: 24 }, () => new Animated.Value(0))
|
||||
@@ -119,6 +122,8 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
|
||||
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Medium);
|
||||
}
|
||||
|
||||
animationRef.current?.play();
|
||||
|
||||
// 使用用户配置的快速添加饮水量
|
||||
const waterAmount = quickWaterAmount;
|
||||
// 如果有选中日期,则为该日期添加记录;否则为今天添加记录
|
||||
@@ -156,6 +161,20 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
|
||||
onPress={handleCardPress}
|
||||
activeOpacity={0.8}
|
||||
>
|
||||
<LottieView
|
||||
ref={animationRef}
|
||||
autoPlay={false}
|
||||
loop={false}
|
||||
source={require('@/assets/lottie/Confetti.json')}
|
||||
style={{
|
||||
width: 150,
|
||||
height: 150,
|
||||
position: 'absolute',
|
||||
left: '15%',
|
||||
}}
|
||||
/>
|
||||
|
||||
|
||||
{/* 标题和加号按钮 */}
|
||||
<View style={styles.header}>
|
||||
<Text style={styles.title}>喝水</Text>
|
||||
@@ -166,6 +185,7 @@ const WaterIntakeCard: React.FC<WaterIntakeCardProps> = ({
|
||||
)}
|
||||
</View>
|
||||
|
||||
|
||||
{/* 柱状图 */}
|
||||
<View style={styles.chartContainer}>
|
||||
<View style={styles.chartWrapper}>
|
||||
|
||||
Reference in New Issue
Block a user