feat: 更新应用版本和主题设置
- 将应用版本更新至 1.0.3,修改相关配置文件 - 强制全局使用浅色主题,确保一致的用户体验 - 在训练计划功能中新增激活计划的 API 接口,支持用户激活训练计划 - 优化打卡功能,支持自动同步打卡记录至服务器 - 更新样式以适应新功能的展示和交互
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import DateTimePicker from '@react-native-community/datetimepicker';
|
||||
import { useRouter } from 'expo-router';
|
||||
import { useLocalSearchParams, useRouter } from 'expo-router';
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import { Modal, Platform, Pressable, SafeAreaView, ScrollView, StyleSheet, TextInput, View } from 'react-native';
|
||||
|
||||
@@ -38,7 +38,8 @@ const GOALS: { key: PlanGoal; title: string; desc: string }[] = [
|
||||
export default function TrainingPlanCreateScreen() {
|
||||
const router = useRouter();
|
||||
const dispatch = useAppDispatch();
|
||||
const { draft, loading, error } = useAppSelector((s) => s.trainingPlan);
|
||||
const { draft, loading, error, editingId } = useAppSelector((s) => s.trainingPlan);
|
||||
const { id } = useLocalSearchParams<{ id?: string }>();
|
||||
const [weightInput, setWeightInput] = useState<string>('');
|
||||
const [datePickerVisible, setDatePickerVisible] = useState(false);
|
||||
const [pickerDate, setPickerDate] = useState<Date>(new Date());
|
||||
@@ -47,6 +48,17 @@ export default function TrainingPlanCreateScreen() {
|
||||
dispatch(loadPlans());
|
||||
}, [dispatch]);
|
||||
|
||||
// 如果带有 id,加载详情并进入编辑模式
|
||||
useEffect(() => {
|
||||
if (id) {
|
||||
dispatch({ type: 'trainingPlan/clearError' } as any);
|
||||
dispatch((require('@/store/trainingPlanSlice') as any).loadPlanForEdit(id as string));
|
||||
} else {
|
||||
// 离开编辑模式
|
||||
dispatch((require('@/store/trainingPlanSlice') as any).setEditingId(null));
|
||||
}
|
||||
}, [id, dispatch]);
|
||||
|
||||
useEffect(() => {
|
||||
if (draft.startWeightKg && !weightInput) setWeightInput(String(draft.startWeightKg));
|
||||
}, [draft.startWeightKg]);
|
||||
@@ -76,7 +88,11 @@ export default function TrainingPlanCreateScreen() {
|
||||
|
||||
const handleSave = async () => {
|
||||
try {
|
||||
await dispatch(saveDraftAsPlan()).unwrap();
|
||||
if (editingId) {
|
||||
await dispatch((require('@/store/trainingPlanSlice') as any).updatePlanFromDraft()).unwrap();
|
||||
} else {
|
||||
await dispatch(saveDraftAsPlan()).unwrap();
|
||||
}
|
||||
router.back();
|
||||
} catch (error) {
|
||||
// 错误已经在Redux中处理,这里可以显示额外的用户反馈
|
||||
@@ -114,7 +130,7 @@ export default function TrainingPlanCreateScreen() {
|
||||
return (
|
||||
<SafeAreaView style={styles.safeArea}>
|
||||
<ThemedView style={styles.container}>
|
||||
<HeaderBar title="新建训练计划" onBack={() => router.back()} withSafeTop={false} transparent />
|
||||
<HeaderBar title={editingId ? '编辑训练计划' : '新建训练计划'} onBack={() => router.back()} withSafeTop={false} transparent />
|
||||
<ScrollView showsVerticalScrollIndicator={false} contentContainerStyle={styles.content}>
|
||||
<ThemedText style={styles.title}>制定你的训练计划</ThemedText>
|
||||
<ThemedText style={styles.subtitle}>选择你的训练节奏与目标,我们将为你生成合适的普拉提安排。</ThemedText>
|
||||
@@ -242,7 +258,7 @@ export default function TrainingPlanCreateScreen() {
|
||||
|
||||
<Pressable disabled={!canSave || loading} onPress={handleSave} style={[styles.primaryBtn, (!canSave || loading) && styles.primaryBtnDisabled]}>
|
||||
<ThemedText style={styles.primaryBtnText}>
|
||||
{loading ? '创建中...' : canSave ? '生成计划' : '请先选择目标/频率'}
|
||||
{loading ? (editingId ? '更新中...' : '创建中...') : canSave ? (editingId ? '更新计划' : '生成计划') : '请先选择目标/频率'}
|
||||
</ThemedText>
|
||||
</Pressable>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user