8.5 KiB
日期时间选择器优化实现计划
For Claude: REQUIRED SUB-SKILL: Use superpowers:executing-plans to implement this plan task-by-task.
Goal: 将摇卦页面的日期时间选择器改为 iOS 滚轮样式,并实现 locale-aware 格式化
Architecture: 创建共享的 DateTimePickerBottomSheet 组件,封装 CupertinoDatePicker 和底部弹层交互,替换现有的 showDatePicker + showTimePicker 调用
Tech Stack: Flutter, Cupertino widgets, intl package
Task 1: 创建 DateTimePickerBottomSheet 组件
Files:
- Create:
apps/lib/shared/widgets/date_time_picker/date_time_picker_bottom_sheet.dart
Step 1: 创建文件结构和基础代码
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:intl/intl.dart';
class DateTimePickerBottomSheet extends StatefulWidget {
const DateTimePickerBottomSheet({
super.key,
required this.initialDateTime,
this.minDateTime,
this.maxDateTime,
});
final DateTime initialDateTime;
final DateTime? minDateTime;
final DateTime? maxDateTime;
@override
State<DateTimePickerBottomSheet> createState() => _DateTimePickerBottomSheetState();
}
class _DateTimePickerBottomSheetState extends State<DateTimePickerBottomSheet> {
late DateTime _selectedDateTime;
int _selectedTab = 0; // 0=日期, 1=时间
@override
void initState() {
super.initState();
_selectedDateTime = widget.initialDateTime;
}
@override
Widget build(BuildContext context) {
final l10n = AppLocalizations.of(context)!;
final locale = Localizations.localeOf(context);
return Container(
height: 400,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(16)),
),
child: Column(
children: [
// 顶部栏
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton(
onPressed: () => Navigator.pop(context),
child: Text(l10n.cancel),
),
Text(
l10n.autoSelectTime,
style: Theme.of(context).textTheme.titleMedium,
),
TextButton(
onPressed: () => Navigator.pop(context, _selectedDateTime),
child: Text(l10n.confirm),
),
],
),
),
// SegmentedControl 切换日期/时间
Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: CupertinoSlidingSegmentedControl<int>(
groupValue: _selectedTab,
children: {
0: Text(l10n.dateTab),
1: Text(l10n.timeTab),
},
onValueChanged: (value) => setState(() => _selectedTab = value ?? 0),
),
),
const SizedBox(height: 16),
// CupertinoDatePicker
Expanded(
child: CupertinoDatePicker(
mode: _selectedTab == 0
? CupertinoDatePickerMode.date
: CupertinoDatePickerMode.time,
initialDateTime: _selectedDateTime,
minimumDate: widget.minDateTime,
maximumDate: widget.maxDateTime,
onDateTimeChanged: (DateTime newDateTime) {
setState(() => _selectedDateTime = newDateTime);
},
),
),
],
),
);
}
}
Future<DateTime?> showDateTimePickerBottomSheet({
required BuildContext context,
required DateTime initialDateTime,
DateTime? minDateTime,
DateTime? maxDateTime,
}) {
return showModalBottomSheet<DateTime>(
context: context,
isScrollControlled: true,
backgroundColor: Colors.transparent,
builder: (context) => DateTimePickerBottomSheet(
initialDateTime: initialDateTime,
minDateTime: minDateTime,
maxDateTime: maxDateTime,
),
);
}
Step 2: 添加 l10n 键值
在 apps/lib/l10n/app_zh.arb 添加:
"dateTab": "日期",
"timeTab": "时间",
"confirm": "确认",
"cancel": "取消"
在 apps/lib/l10n/app_en.arb 添加:
"dateTab": "Date",
"timeTab": "Time",
"confirm": "Confirm",
"cancel": "Cancel"
运行 flutter gen-l10n 生成代码
Step 3: Commit
git add apps/lib/shared/widgets/date_time_picker/ apps/lib/l10n/
git commit -m "feat(divination): add DateTimePickerBottomSheet with iOS wheel style"
Task 2: 修改 auto_divination_screen.dart 使用新选择器
Files:
- Modify:
apps/lib/features/divination/presentation/screens/auto_divination_screen.dart:208-230 - Modify:
apps/lib/features/divination/presentation/screens/auto_divination_screen.dart:353
Step 1: 添加 import
在文件顶部添加:
import 'package:shared/widgets/date_time_picker/date_time_picker_bottom_sheet.dart';
Step 2: 修改 _pickTime 方法
将:
Future<void> _pickTime() async {
final date = await showDatePicker(
context: context,
initialDate: _selectedTime,
firstDate: DateTime(2000),
lastDate: DateTime(2100),
);
if (date == null || !mounted) return;
final time = await showTimePicker(
context: context,
initialTime: TimeOfDay.fromDateTime(_selectedTime),
);
if (time == null || !mounted) return;
setState(() {
_selectedTime = DateTime(
date.year,
date.month,
date.day,
time.hour,
time.minute,
);
});
}
替换为:
Future<void> _pickTime() async {
final result = await showDateTimePickerBottomSheet(
context: context,
initialDateTime: _selectedTime,
minDateTime: DateTime(2000),
maxDateTime: DateTime(2100),
);
if (result == null || !mounted) return;
setState(() {
_selectedTime = result;
});
}
Step 3: 修改日期显示格式
将:
DateFormat('yyyy年MM月dd日 HH:mm').format(selectedTime)
替换为:
DateFormat.yMd(Localizations.localeOf(context).toString()).add_Hm().format(selectedTime)
需要添加 import:
import 'package:intl/intl.dart';
Step 4: Commit
git add apps/lib/features/divination/presentation/screens/auto_divination_screen.dart
git commit -m "feat(divination): use DateTimePickerBottomSheet in auto_divination_screen"
Task 3: 修改 manual_divination_screen.dart 使用新选择器
Files:
- Modify:
apps/lib/features/divination/presentation/screens/manual_divination_screen.dart:142-168 - Modify:
apps/lib/features/divination/presentation/screens/manual_divination_screen.dart:271
Step 1: 添加 import
import 'package:shared/widgets/date_time_picker/date_time_picker_bottom_sheet.dart';
import 'package:intl/intl.dart';
Step 2: 修改 _pickTime 方法和日期显示格式
同 Task 2 的修改方式
Step 3: Commit
git add apps/lib/features/divination/presentation/screens/manual_divination_screen.dart
git commit -m "feat(divination): use DateTimePickerBottomSheet in manual_divination_screen"
Task 4: 修改 divination_result_screen.dart 的日期格式
Files:
- Modify:
apps/lib/features/divination/presentation/screens/divination_result_screen.dart:455-457
Step 1: 添加 import
import 'package:intl/intl.dart';
Step 2: 修改日期格式
将:
DateFormat(
'yyyy年MM月dd日 HH:mm',
).format(data.params.divinationTime),
替换为:
DateFormat.yMd(Localizations.localeOf(context).toString()).add_Hm().format(data.params.divinationTime),
Step 3: Commit
git add apps/lib/features/divination/presentation/screens/divination_result_screen.dart
git commit -m "refactor(divination): use locale-aware date format in divination_result_screen"
Task 5: 运行验证
Step 1: 生成 l10n
cd apps && flutter gen-l10n
Step 2: 运行静态分析
cd apps && flutter analyze
预期: 无错误
Step 3: 运行相关测试
cd apps && flutter test test/features/divination/
Plan complete. Two execution options:
1. Subagent-Driven (this session) - I dispatch fresh subagent per task, review between tasks, fast iteration
2. Parallel Session (separate) - Open new session with executing-plans, batch execution with checkpoints
Which approach?