From a73ba67ef1abcb7e80ce86a6a33934fadfccfc3a Mon Sep 17 00:00:00 2001 From: qzl Date: Fri, 3 Apr 2026 18:18:55 +0800 Subject: [PATCH] feat(divination): use DateTimePickerBottomSheet in manual_divination_screen --- .../screens/manual_divination_screen.dart | 105 ++++++++++++------ 1 file changed, 68 insertions(+), 37 deletions(-) diff --git a/apps/lib/features/divination/presentation/screens/manual_divination_screen.dart b/apps/lib/features/divination/presentation/screens/manual_divination_screen.dart index a6161e1..3bd6be2 100644 --- a/apps/lib/features/divination/presentation/screens/manual_divination_screen.dart +++ b/apps/lib/features/divination/presentation/screens/manual_divination_screen.dart @@ -2,20 +2,30 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:intl/intl.dart'; +import '../../../../core/network/api_problem.dart'; +import '../../../../core/network/api_problem_mapper.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../../shared/theme/design_tokens.dart'; import '../../../../shared/widgets/divination/divination_shared_widgets.dart'; import '../../../../shared/widgets/divination/divination_terms.dart'; import '../../../../shared/widgets/divination/yao_legend.dart'; import '../../../../shared/widgets/divination/yao_line_row.dart'; +import '../../../../shared/widgets/toast/toast.dart'; +import '../../../../shared/widgets/toast/toast_type.dart'; +import '../../../../shared/widgets/date_time_picker/date_time_picker_bottom_sheet.dart'; import '../../data/models/divination_params.dart'; -import '../../data/services/divination_result_builder.dart'; +import '../../data/services/divination_run_service.dart'; import 'divination_result_screen.dart'; class ManualDivinationScreen extends StatefulWidget { - const ManualDivinationScreen({super.key, required this.params}); + const ManualDivinationScreen({ + super.key, + required this.params, + required this.runService, + }); final DivinationParams params; + final DivinationRunService runService; @override State createState() => _ManualDivinationScreenState(); @@ -23,10 +33,10 @@ class ManualDivinationScreen extends StatefulWidget { class _ManualDivinationScreenState extends State with TickerProviderStateMixin { - final DivinationResultBuilder _resultBuilder = DivinationResultBuilder(); late DateTime _selectedTime; final List _selectedYaos = List.filled(6, null); late final AnimationController _blinkController; + bool _submitting = false; @override void initState() { @@ -81,7 +91,7 @@ class _ManualDivinationScreenState extends State width: double.infinity, height: 50, child: FilledButton( - onPressed: _allSelected ? _showMockPayload : null, + onPressed: _allSelected && !_submitting ? _submitRun : null, style: FilledButton.styleFrom( backgroundColor: _allSelected ? base.withValues( @@ -89,7 +99,13 @@ class _ManualDivinationScreenState extends State ) : base, ), - child: Text(l10n.manualStartResolve), + child: _submitting + ? const SizedBox( + width: 18, + height: 18, + child: CircularProgressIndicator(strokeWidth: 2), + ) + : Text(l10n.manualStartResolve), ), ); }, @@ -125,30 +141,15 @@ class _ManualDivinationScreenState extends State } Future _pickTime() async { - final date = await showDatePicker( + final result = await showDateTimePickerBottomSheet( context: context, - initialDate: _selectedTime, - firstDate: DateTime(2000), - lastDate: DateTime(2100), + initialDateTime: _selectedTime, + minDateTime: DateTime(2000), + maxDateTime: DateTime(2100), ); - if (date == null || !mounted) { - return; - } - final time = await showTimePicker( - context: context, - initialTime: TimeOfDay.fromDateTime(_selectedTime), - ); - if (time == null || !mounted) { - return; - } + if (result == null || !mounted) return; setState(() { - _selectedTime = DateTime( - date.year, - date.month, - date.day, - time.hour, - time.minute, - ); + _selectedTime = result; }); } @@ -178,16 +179,44 @@ class _ManualDivinationScreenState extends State ); } - Future _showMockPayload() async { - final result = _resultBuilder.build( - params: widget.params.copyWith(divinationTime: _selectedTime), - yaoStates: _selectedYaos.cast(), - ); - Navigator.of(context).push( - MaterialPageRoute( - builder: (_) => DivinationResultScreen(data: result), - ), - ); + Future _submitRun() async { + final l10n = AppLocalizations.of(context)!; + setState(() { + _submitting = true; + }); + try { + final aggregate = await widget.runService.run( + params: widget.params.copyWith(divinationTime: _selectedTime), + yaoStates: _selectedYaos.cast(), + ); + if (!mounted) { + return; + } + Navigator.of(context).push( + MaterialPageRoute( + builder: (_) => DivinationResultScreen( + data: aggregate.toViewData( + widget.params.copyWith(divinationTime: _selectedTime), + ), + ), + ), + ); + } catch (error) { + if (!mounted) { + return; + } + final message = error is ApiProblem + ? mapApiProblemToMessage(error, l10n) + : l10n.errorRequestGeneric; + Toast.show(context, message, type: ToastType.error); + } finally { + if (!mounted) { + return; + } + setState(() { + _submitting = false; + }); + } } } @@ -225,7 +254,9 @@ class _TimeCard extends StatelessWidget { children: [ Expanded( child: Text( - DateFormat('yyyy年MM月dd日 HH:mm').format(selectedTime), + DateFormat.yMd( + Localizations.localeOf(context).toString(), + ).add_Hm().format(selectedTime), style: Theme.of(context).textTheme.titleMedium, ), ),