feat: 更新应用名称为“Out Live”,删除推送通知使用指南和喝水记录API修复测试文档,优化饮水设置页面,添加登录状态检查
This commit is contained in:
@@ -15,7 +15,7 @@ import { useAuthGuard } from '@/hooks/useAuthGuard';
|
||||
import { selectHealthDataByDate, setHealthData } from '@/store/healthSlice';
|
||||
import { fetchDailyMoodCheckins, selectLatestMoodRecordByDate } from '@/store/moodSlice';
|
||||
import { fetchDailyNutritionData, selectNutritionSummaryByDate } from '@/store/nutritionSlice';
|
||||
import { fetchTodayWaterStats, selectTodayStats } from '@/store/waterSlice';
|
||||
import { fetchTodayWaterStats } from '@/store/waterSlice';
|
||||
import { getMonthDaysZh, getTodayIndexInMonth } from '@/utils/date';
|
||||
import { ensureHealthPermissions, fetchHealthDataForDate, testHRVDataFetch } from '@/utils/health';
|
||||
import { getTestHealthData } from '@/utils/mockHealthData';
|
||||
@@ -89,8 +89,6 @@ export default function ExploreScreen() {
|
||||
// 从 Redux 获取指定日期的健康数据
|
||||
const healthData = useAppSelector(selectHealthDataByDate(currentSelectedDateString));
|
||||
|
||||
// 获取今日喝水统计数据
|
||||
const todayWaterStats = useAppSelector(selectTodayStats);
|
||||
|
||||
// 解构健康数据(支持mock数据)
|
||||
const mockData = useMockData ? getTestHealthData('mock') : null;
|
||||
@@ -101,7 +99,7 @@ export default function ExploreScreen() {
|
||||
const sleepDuration = useMockData ? (mockData?.sleepDuration ?? null) : (healthData?.sleepDuration ?? null);
|
||||
const hrvValue = useMockData ? (mockData?.hrv ?? 0) : (healthData?.hrv ?? 0);
|
||||
const oxygenSaturation = useMockData ? (mockData?.oxygenSaturation ?? null) : (healthData?.oxygenSaturation ?? null);
|
||||
const heartRate = useMockData ? (mockData?.heartRate ?? null) : (healthData?.heartRate ?? null);
|
||||
|
||||
const fitnessRingsData = useMockData ? {
|
||||
activeCalories: mockData?.activeCalories ?? 0,
|
||||
activeCaloriesGoal: mockData?.activeCaloriesGoal ?? 350,
|
||||
@@ -455,7 +453,7 @@ export default function ExploreScreen() {
|
||||
|
||||
{/* 右边文字区域 */}
|
||||
<View style={styles.headerTextContainer}>
|
||||
<Text style={styles.headerTitle}>海豹健康</Text>
|
||||
<Text style={styles.headerTitle}>Out Live</Text>
|
||||
</View>
|
||||
|
||||
{/* 开发环境调试按钮 */}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
import { Colors } from '@/constants/Colors';
|
||||
import { useAuthGuard } from '@/hooks/useAuthGuard';
|
||||
import { useColorScheme } from '@/hooks/useColorScheme';
|
||||
import { useWaterDataByDate } from '@/hooks/useWaterData';
|
||||
import { getQuickWaterAmount, setQuickWaterAmount } from '@/utils/userPreferences';
|
||||
import { Ionicons } from '@expo/vector-icons';
|
||||
import { Picker } from '@react-native-picker/picker';
|
||||
import { Image } from 'expo-image';
|
||||
import { LinearGradient } from 'expo-linear-gradient';
|
||||
import { router, useLocalSearchParams } from 'expo-router';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import {
|
||||
@@ -32,6 +34,7 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
||||
const { selectedDate } = useLocalSearchParams<{ selectedDate?: string }>();
|
||||
const theme = (useColorScheme() ?? 'light') as 'light' | 'dark';
|
||||
const colorTokens = Colors[theme];
|
||||
const { ensureLoggedIn } = useAuthGuard();
|
||||
|
||||
const [dailyGoal, setDailyGoal] = useState<string>('2000');
|
||||
const [quickAddAmount, setQuickAddAmount] = useState<string>('250');
|
||||
@@ -47,6 +50,19 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
||||
// 使用新的 hook 来处理指定日期的饮水数据
|
||||
const { waterRecords, dailyWaterGoal, updateWaterGoal, removeWaterRecord } = useWaterDataByDate(selectedDate);
|
||||
|
||||
// 检查登录状态
|
||||
useEffect(() => {
|
||||
const checkLoginStatus = async () => {
|
||||
const isLoggedIn = await ensureLoggedIn();
|
||||
if (!isLoggedIn) {
|
||||
// 如果未登录,用户会被重定向到登录页面
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
checkLoginStatus();
|
||||
}, [ensureLoggedIn]);
|
||||
|
||||
const goalPresets = [1500, 2000, 2500, 3000, 3500, 4000];
|
||||
const quickAddPresets = [100, 150, 200, 250, 300, 350, 400, 500];
|
||||
|
||||
@@ -203,7 +219,19 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
||||
};
|
||||
|
||||
return (
|
||||
<View style={[styles.container, { backgroundColor: colorTokens.background }]}>
|
||||
<View style={styles.container}>
|
||||
{/* 背景渐变 */}
|
||||
<LinearGradient
|
||||
colors={['#f5e5fbff', '#e5fcfeff', '#eefdffff', '#e6f6fcff']}
|
||||
style={styles.gradientBackground}
|
||||
start={{ x: 0, y: 0 }}
|
||||
end={{ x: 0, y: 1 }}
|
||||
/>
|
||||
|
||||
{/* 装饰性圆圈 */}
|
||||
<View style={styles.decorativeCircle1} />
|
||||
<View style={styles.decorativeCircle2} />
|
||||
|
||||
<HeaderBar
|
||||
title="饮水设置"
|
||||
onBack={() => {
|
||||
@@ -249,7 +277,7 @@ const WaterSettings: React.FC<WaterSettingsProps> = () => {
|
||||
<View style={styles.settingLeft}>
|
||||
<Text style={[styles.settingTitle, { color: colorTokens.text }]}>快速添加默认值</Text>
|
||||
<Text style={[styles.settingSubtitle, { color: colorTokens.textSecondary }]}>
|
||||
设置点击右上角"+"按钮时添加的默认饮水量
|
||||
{`设置点击右上角"+"按钮时添加的默认饮水量`}
|
||||
</Text>
|
||||
<Text style={[styles.settingValue, { color: colorTokens.textSecondary }]}>{quickAddAmount}ml</Text>
|
||||
</View>
|
||||
@@ -382,6 +410,33 @@ const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
},
|
||||
gradientBackground: {
|
||||
position: 'absolute',
|
||||
left: 0,
|
||||
right: 0,
|
||||
top: 0,
|
||||
bottom: 0,
|
||||
},
|
||||
decorativeCircle1: {
|
||||
position: 'absolute',
|
||||
top: 40,
|
||||
right: 20,
|
||||
width: 60,
|
||||
height: 60,
|
||||
borderRadius: 30,
|
||||
backgroundColor: '#0EA5E9',
|
||||
opacity: 0.1,
|
||||
},
|
||||
decorativeCircle2: {
|
||||
position: 'absolute',
|
||||
bottom: -15,
|
||||
left: -15,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: '#0EA5E9',
|
||||
opacity: 0.05,
|
||||
},
|
||||
keyboardAvoidingView: {
|
||||
flex: 1,
|
||||
},
|
||||
@@ -395,19 +450,19 @@ const styles = StyleSheet.create({
|
||||
marginBottom: 32,
|
||||
},
|
||||
sectionTitle: {
|
||||
fontSize: 20,
|
||||
fontWeight: '600',
|
||||
fontSize: 16,
|
||||
fontWeight: '500',
|
||||
marginBottom: 20,
|
||||
letterSpacing: -0.5,
|
||||
},
|
||||
subsectionTitle: {
|
||||
fontSize: 16,
|
||||
fontSize: 14,
|
||||
fontWeight: '500',
|
||||
marginBottom: 12,
|
||||
letterSpacing: -0.3,
|
||||
},
|
||||
sectionSubtitle: {
|
||||
fontSize: 14,
|
||||
fontSize: 12,
|
||||
fontWeight: '400',
|
||||
lineHeight: 18,
|
||||
},
|
||||
@@ -582,15 +637,18 @@ const styles = StyleSheet.create({
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
paddingVertical: 40,
|
||||
gap: 12,
|
||||
gap: 16,
|
||||
},
|
||||
noRecordsText: {
|
||||
fontSize: 16,
|
||||
fontWeight: '600',
|
||||
fontSize: 15,
|
||||
fontWeight: '500',
|
||||
lineHeight: 20,
|
||||
},
|
||||
noRecordsSubText: {
|
||||
fontSize: 14,
|
||||
fontSize: 13,
|
||||
textAlign: 'center',
|
||||
lineHeight: 18,
|
||||
opacity: 0.7,
|
||||
},
|
||||
modalBackdrop: {
|
||||
...StyleSheet.absoluteFillObject,
|
||||
|
||||
Reference in New Issue
Block a user