Refactor: Remove background task management and related hooks
- Deleted `useBackgroundTasks.ts` hook and its associated logic for managing background tasks. - Removed `backgroundTaskManager.ts` service and all related task definitions and registrations. - Cleaned up `Podfile.lock` and `package.json` to remove unused dependencies related to background tasks. - Updated iOS project files to eliminate references to removed background task components. - Added new background fetch identifier in `Info.plist` for future use.
This commit is contained in:
@@ -13,9 +13,7 @@ import { Colors } from '@/constants/Colors';
|
||||
import { getTabBarBottomPadding } from '@/constants/TabBar';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
||||
import { useBackgroundTasks } from '@/hooks/useBackgroundTasks';
|
||||
import { notificationService } from '@/services/notifications';
|
||||
import { backgroundTaskManager } from '@/services/backgroundTaskManager';
|
||||
import { selectHealthDataByDate, setHealthData } from '@/store/healthSlice';
|
||||
import { fetchDailyMoodCheckins, selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
import { fetchDailyNutritionData, selectNutritionSummaryByDate } from '@/store/nutritionSlice';
|
||||
@@ -38,8 +36,8 @@ import {
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
View,
|
||||
TouchableOpacity
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from 'react-native';
|
||||
import { useSafeAreaInsets } from 'react-native-safe-area-context';
|
||||
|
||||
@@ -150,7 +148,6 @@ export default function ExploreScreen() {
|
||||
});
|
||||
}, [userProfile]);
|
||||
|
||||
const { registerTask, isInitialized } = useBackgroundTasks();
|
||||
// 心情相关状态
|
||||
const dispatch = useAppDispatch();
|
||||
const [isMoodLoading, setIsMoodLoading] = useState(false);
|
||||
@@ -416,49 +413,6 @@ export default function ExploreScreen() {
|
||||
};
|
||||
}, [loadAllData, currentSelectedDate]);
|
||||
|
||||
useEffect(() => {
|
||||
// 只有在后台任务管理器初始化完成后才注册任务
|
||||
if (isInitialized) {
|
||||
console.log('后台任务管理器已初始化,开始注册健康数据任务...');
|
||||
registerTask({
|
||||
id: 'health-data-task',
|
||||
name: 'health-data-task',
|
||||
handler: async () => {
|
||||
try {
|
||||
console.log('后台任务:更新健康数据和检查压力水平...');
|
||||
|
||||
// 发送测试通知,验证后台任务是否执行
|
||||
await notificationService.sendImmediateNotification({
|
||||
title: '后台任务测试 🔔',
|
||||
body: `任务执行时间: ${new Date().toLocaleTimeString('zh-CN')}`,
|
||||
data: {
|
||||
type: 'background_task_test',
|
||||
timestamp: new Date().toISOString(),
|
||||
},
|
||||
sound: true,
|
||||
priority: 'high'
|
||||
});
|
||||
|
||||
// 后台任务只更新健康数据,强制刷新以获取最新数据
|
||||
await loadHealthData(undefined, true);
|
||||
|
||||
// 执行压力检查
|
||||
await checkStressLevelAndNotify();
|
||||
|
||||
// 执行喝水目标检查
|
||||
await checkWaterGoalAndNotify();
|
||||
} catch (error) {
|
||||
console.error('健康数据任务执行失败:', error);
|
||||
}
|
||||
},
|
||||
}).then(() => {
|
||||
console.log('健康数据任务注册成功');
|
||||
}).catch((error) => {
|
||||
console.error('健康数据任务注册失败:', error);
|
||||
});
|
||||
}
|
||||
}, [isInitialized]);
|
||||
|
||||
// 检查压力水平并发送通知
|
||||
const checkStressLevelAndNotify = React.useCallback(async () => {
|
||||
try {
|
||||
@@ -627,7 +581,7 @@ export default function ExploreScreen() {
|
||||
style={styles.debugButton}
|
||||
onPress={async () => {
|
||||
console.log('🔧 手动触发后台任务测试...');
|
||||
await backgroundTaskManager.debugExecuteBackgroundTask();
|
||||
// await backgroundTaskManager.triggerTaskForTesting();
|
||||
}}
|
||||
>
|
||||
<Text style={styles.debugButtonText}>🔧</Text>
|
||||
|
||||
@@ -8,7 +8,6 @@ import 'react-native-reanimated';
|
||||
import PrivacyConsentModal from '@/components/PrivacyConsentModal';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { clearAiCoachSessionCache } from '@/services/aiCoachSession';
|
||||
import { backgroundTaskManager } from '@/services/backgroundTaskManager';
|
||||
import { notificationService } from '@/services/notifications';
|
||||
import { store } from '@/store';
|
||||
import { rehydrateUser, setPrivacyAgreed } from '@/store/userSlice';
|
||||
@@ -31,16 +30,6 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
await dispatch(rehydrateUser());
|
||||
setUserDataLoaded(true);
|
||||
};
|
||||
|
||||
const initializeBackgroundTasks = async () => {
|
||||
try {
|
||||
await backgroundTaskManager.initialize();
|
||||
console.log('后台任务管理器初始化成功');
|
||||
} catch (error) {
|
||||
console.error('后台任务管理器初始化失败:', error);
|
||||
}
|
||||
};
|
||||
|
||||
const initializeNotifications = async () => {
|
||||
try {
|
||||
// 初始化通知服务
|
||||
@@ -52,7 +41,6 @@ function Bootstrapper({ children }: { children: React.ReactNode }) {
|
||||
};
|
||||
|
||||
loadUserData();
|
||||
initializeBackgroundTasks();
|
||||
initializeNotifications();
|
||||
// 冷启动时清空 AI 教练会话缓存
|
||||
clearAiCoachSessionCache();
|
||||
|
||||
@@ -7,13 +7,14 @@ import { addDietRecord, type CreateDietRecordDto, type MealType } from '@/servic
|
||||
import { selectFoodRecognitionResult } from '@/store/foodRecognitionSlice';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import dayjs from 'dayjs';
|
||||
import { Image } from 'expo-image';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
|
||||
import {
|
||||
ActivityIndicator,
|
||||
BackHandler,
|
||||
Image,
|
||||
Modal,
|
||||
Pressable,
|
||||
ScrollView,
|
||||
@@ -297,7 +298,7 @@ export default function FoodAnalysisResultScreen() {
|
||||
<Image
|
||||
source={{ uri: imageUri }}
|
||||
style={styles.foodImage}
|
||||
resizeMode="cover"
|
||||
cachePolicy={'memory-disk'}
|
||||
/>
|
||||
{/* 预览提示图标 */}
|
||||
<View style={styles.previewHint}>
|
||||
|
||||
@@ -3,21 +3,19 @@ import { Colors } from '@/constants/Colors';
|
||||
import { useAppDispatch, useAppSelector } from '@/hooks/redux';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { useMoodData } from '@/hooks/useMoodData';
|
||||
import { getMoodOptions, MoodOption } from '@/services/moodCheckins';
|
||||
import { getMoodOptions } from '@/services/moodCheckins';
|
||||
import { selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
import { Image } from 'react-native';
|
||||
import dayjs from 'dayjs';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { router, useFocusEffect, useLocalSearchParams } from 'expo-router';
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import {
|
||||
Dimensions,
|
||||
SafeAreaView,
|
||||
Dimensions, Image, SafeAreaView,
|
||||
ScrollView,
|
||||
StyleSheet,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
View
|
||||
} from 'react-native';
|
||||
|
||||
const { width } = Dimensions.get('window');
|
||||
@@ -60,7 +58,7 @@ export default function MoodCalendarScreen() {
|
||||
// 使用 useRef 来存储函数引用,避免依赖循环
|
||||
const fetchMoodRecordsRef = useRef(fetchMoodRecords);
|
||||
const fetchMoodHistoryRecordsRef = useRef(fetchMoodHistoryRecords);
|
||||
|
||||
|
||||
// 更新 ref 值
|
||||
fetchMoodRecordsRef.current = fetchMoodRecords;
|
||||
fetchMoodHistoryRecordsRef.current = fetchMoodHistoryRecords;
|
||||
@@ -73,7 +71,7 @@ export default function MoodCalendarScreen() {
|
||||
|
||||
// 使用 Redux store 中的数据
|
||||
const moodRecords = useAppSelector(state => state.mood.moodRecords);
|
||||
|
||||
|
||||
// 获取选中日期的数据
|
||||
const selectedDateMood = useAppSelector(state => {
|
||||
if (!selectedDay) return null;
|
||||
@@ -191,46 +189,30 @@ export default function MoodCalendarScreen() {
|
||||
const moodRecord = dayRecords.length > 0 ? dayRecords[0] : null;
|
||||
|
||||
const isToday = day === new Date().getDate() &&
|
||||
month === new Date().getMonth() + 1 &&
|
||||
year === new Date().getFullYear();
|
||||
month === new Date().getMonth() + 1 &&
|
||||
year === new Date().getFullYear();
|
||||
|
||||
if (moodRecord) {
|
||||
const mood = moodOptions.find(m => m.type === moodRecord.moodType);
|
||||
const intensity = moodRecord.intensity;
|
||||
const color = mood?.color || '#7a5af8';
|
||||
|
||||
// 计算圆环的填充比例 (0-1)
|
||||
const fillRatio = intensity / 10;
|
||||
|
||||
|
||||
return (
|
||||
<View style={isToday ? styles.todayMoodRingContainer : styles.moodRingContainer}>
|
||||
<View style={[isToday ? styles.todayMoodRing : styles.moodRing, { borderColor: color }]}>
|
||||
<View style={[
|
||||
styles.moodRingFill,
|
||||
{
|
||||
backgroundColor: color,
|
||||
height: `${fillRatio * 100}%`,
|
||||
opacity: 0.7,
|
||||
}
|
||||
]} />
|
||||
<Text style={[styles.moodIntensityText, { color: '#fff', fontSize: isToday ? 7 : 8 }]}>
|
||||
{intensity}
|
||||
</Text>
|
||||
<View style={isToday ? styles.todayMoodIconContainer : styles.moodIconContainer}>
|
||||
<View style={styles.moodIcon}>
|
||||
<Image
|
||||
source={mood?.image}
|
||||
style={styles.moodIconImage}
|
||||
/>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<View style={isToday ? styles.todayDefaultMoodRing : styles.defaultMoodRing}>
|
||||
<View style={isToday ? styles.todayDefaultMoodRingBorder : styles.defaultMoodRingBorder} />
|
||||
<View style={isToday ? styles.todayDefaultMoodIcon : styles.defaultMoodIcon}>
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
// 使用统一的渐变背景色
|
||||
const backgroundGradientColors = [colorTokens.backgroundGradientStart, colorTokens.backgroundGradientEnd] as const;
|
||||
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<LinearGradient
|
||||
@@ -242,7 +224,7 @@ export default function MoodCalendarScreen() {
|
||||
{/* 装饰性圆圈 */}
|
||||
<View style={styles.decorativeCircle1} />
|
||||
<View style={styles.decorativeCircle2} />
|
||||
|
||||
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<HeaderBar
|
||||
title="心情日历"
|
||||
@@ -538,6 +520,20 @@ const styles = StyleSheet.create({
|
||||
shadowRadius: 2,
|
||||
elevation: 1,
|
||||
},
|
||||
todayMoodIconContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 1,
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
shadowColor: '#7a5af8',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 2,
|
||||
elevation: 2,
|
||||
},
|
||||
moodIcon: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
@@ -547,8 +543,8 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
},
|
||||
moodIconImage: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
width: 28,
|
||||
height: 28,
|
||||
borderRadius: 9,
|
||||
},
|
||||
defaultMoodIcon: {
|
||||
@@ -564,10 +560,18 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(122,90,248,0.05)',
|
||||
},
|
||||
defaultMoodEmoji: {
|
||||
fontSize: 10,
|
||||
opacity: 0.4,
|
||||
color: '#7a5af8',
|
||||
todayDefaultMoodIcon: {
|
||||
position: 'absolute',
|
||||
bottom: 1,
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
borderWidth: 1.5,
|
||||
borderColor: 'rgba(122,90,248,0.4)',
|
||||
borderStyle: 'dashed',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: 'rgba(122,90,248,0.08)',
|
||||
},
|
||||
moodRingContainer: {
|
||||
position: 'absolute',
|
||||
@@ -577,29 +581,7 @@ const styles = StyleSheet.create({
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
moodRing: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
borderWidth: 1.5,
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'rgba(255,255,255,0.95)',
|
||||
shadowColor: '#000',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.1,
|
||||
shadowRadius: 2,
|
||||
elevation: 1,
|
||||
},
|
||||
moodRingFill: {
|
||||
position: 'absolute',
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
borderBottomLeftRadius: 8,
|
||||
borderBottomRightRadius: 8,
|
||||
},
|
||||
|
||||
moodIntensityText: {
|
||||
fontSize: 8,
|
||||
fontWeight: '800',
|
||||
@@ -610,63 +592,8 @@ const styles = StyleSheet.create({
|
||||
textShadowOffset: { width: 0, height: 0.5 },
|
||||
textShadowRadius: 1,
|
||||
},
|
||||
defaultMoodRing: {
|
||||
position: 'absolute',
|
||||
bottom: 2,
|
||||
width: 22,
|
||||
height: 22,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
defaultMoodRingBorder: {
|
||||
width: 20,
|
||||
height: 20,
|
||||
borderRadius: 10,
|
||||
borderWidth: 1.5,
|
||||
borderColor: 'rgba(122,90,248,0.3)',
|
||||
borderStyle: 'dashed',
|
||||
backgroundColor: 'rgba(122,90,248,0.05)',
|
||||
},
|
||||
todayMoodRingContainer: {
|
||||
position: 'absolute',
|
||||
bottom: 1,
|
||||
width: 20,
|
||||
height: 20,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
todayMoodRing: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: 9,
|
||||
borderWidth: 1.5,
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'center',
|
||||
overflow: 'hidden',
|
||||
backgroundColor: 'rgba(255,255,255,0.95)',
|
||||
shadowColor: '#7a5af8',
|
||||
shadowOffset: { width: 0, height: 1 },
|
||||
shadowOpacity: 0.2,
|
||||
shadowRadius: 2,
|
||||
elevation: 2,
|
||||
},
|
||||
todayDefaultMoodRing: {
|
||||
position: 'absolute',
|
||||
bottom: 1,
|
||||
width: 20,
|
||||
height: 20,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
},
|
||||
todayDefaultMoodRingBorder: {
|
||||
width: 18,
|
||||
height: 18,
|
||||
borderRadius: 9,
|
||||
borderWidth: 1.5,
|
||||
borderColor: 'rgba(122,90,248,0.4)',
|
||||
borderStyle: 'dashed',
|
||||
backgroundColor: 'rgba(122,90,248,0.08)',
|
||||
},
|
||||
|
||||
|
||||
selectedDateSection: {
|
||||
backgroundColor: 'rgba(255,255,255,0.95)',
|
||||
margin: 16,
|
||||
@@ -720,7 +647,7 @@ const styles = StyleSheet.create({
|
||||
width: 52,
|
||||
height: 52,
|
||||
borderRadius: 26,
|
||||
backgroundColor: '#7a5af8',
|
||||
backgroundColor: '#e9e7f1ff',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
marginRight: 16,
|
||||
|
||||
Reference in New Issue
Block a user