feat(divination): use DateTimePickerBottomSheet in manual_divination_screen
This commit is contained in:
@@ -2,20 +2,30 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:intl/intl.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 '../../../../l10n/app_localizations.dart';
|
||||||
import '../../../../shared/theme/design_tokens.dart';
|
import '../../../../shared/theme/design_tokens.dart';
|
||||||
import '../../../../shared/widgets/divination/divination_shared_widgets.dart';
|
import '../../../../shared/widgets/divination/divination_shared_widgets.dart';
|
||||||
import '../../../../shared/widgets/divination/divination_terms.dart';
|
import '../../../../shared/widgets/divination/divination_terms.dart';
|
||||||
import '../../../../shared/widgets/divination/yao_legend.dart';
|
import '../../../../shared/widgets/divination/yao_legend.dart';
|
||||||
import '../../../../shared/widgets/divination/yao_line_row.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/models/divination_params.dart';
|
||||||
import '../../data/services/divination_result_builder.dart';
|
import '../../data/services/divination_run_service.dart';
|
||||||
import 'divination_result_screen.dart';
|
import 'divination_result_screen.dart';
|
||||||
|
|
||||||
class ManualDivinationScreen extends StatefulWidget {
|
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 DivinationParams params;
|
||||||
|
final DivinationRunService runService;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ManualDivinationScreen> createState() => _ManualDivinationScreenState();
|
State<ManualDivinationScreen> createState() => _ManualDivinationScreenState();
|
||||||
@@ -23,10 +33,10 @@ class ManualDivinationScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _ManualDivinationScreenState extends State<ManualDivinationScreen>
|
class _ManualDivinationScreenState extends State<ManualDivinationScreen>
|
||||||
with TickerProviderStateMixin {
|
with TickerProviderStateMixin {
|
||||||
final DivinationResultBuilder _resultBuilder = DivinationResultBuilder();
|
|
||||||
late DateTime _selectedTime;
|
late DateTime _selectedTime;
|
||||||
final List<YaoType?> _selectedYaos = List<YaoType?>.filled(6, null);
|
final List<YaoType?> _selectedYaos = List<YaoType?>.filled(6, null);
|
||||||
late final AnimationController _blinkController;
|
late final AnimationController _blinkController;
|
||||||
|
bool _submitting = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -81,7 +91,7 @@ class _ManualDivinationScreenState extends State<ManualDivinationScreen>
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 50,
|
height: 50,
|
||||||
child: FilledButton(
|
child: FilledButton(
|
||||||
onPressed: _allSelected ? _showMockPayload : null,
|
onPressed: _allSelected && !_submitting ? _submitRun : null,
|
||||||
style: FilledButton.styleFrom(
|
style: FilledButton.styleFrom(
|
||||||
backgroundColor: _allSelected
|
backgroundColor: _allSelected
|
||||||
? base.withValues(
|
? base.withValues(
|
||||||
@@ -89,7 +99,13 @@ class _ManualDivinationScreenState extends State<ManualDivinationScreen>
|
|||||||
)
|
)
|
||||||
: base,
|
: 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<ManualDivinationScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _pickTime() async {
|
Future<void> _pickTime() async {
|
||||||
final date = await showDatePicker(
|
final result = await showDateTimePickerBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
initialDate: _selectedTime,
|
initialDateTime: _selectedTime,
|
||||||
firstDate: DateTime(2000),
|
minDateTime: DateTime(2000),
|
||||||
lastDate: DateTime(2100),
|
maxDateTime: DateTime(2100),
|
||||||
);
|
);
|
||||||
if (date == null || !mounted) {
|
if (result == null || !mounted) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
final time = await showTimePicker(
|
|
||||||
context: context,
|
|
||||||
initialTime: TimeOfDay.fromDateTime(_selectedTime),
|
|
||||||
);
|
|
||||||
if (time == null || !mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_selectedTime = DateTime(
|
_selectedTime = result;
|
||||||
date.year,
|
|
||||||
date.month,
|
|
||||||
date.day,
|
|
||||||
time.hour,
|
|
||||||
time.minute,
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,16 +179,44 @@ class _ManualDivinationScreenState extends State<ManualDivinationScreen>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _showMockPayload() async {
|
Future<void> _submitRun() async {
|
||||||
final result = _resultBuilder.build(
|
final l10n = AppLocalizations.of(context)!;
|
||||||
params: widget.params.copyWith(divinationTime: _selectedTime),
|
setState(() {
|
||||||
yaoStates: _selectedYaos.cast<YaoType>(),
|
_submitting = true;
|
||||||
);
|
});
|
||||||
Navigator.of(context).push(
|
try {
|
||||||
MaterialPageRoute<void>(
|
final aggregate = await widget.runService.run(
|
||||||
builder: (_) => DivinationResultScreen(data: result),
|
params: widget.params.copyWith(divinationTime: _selectedTime),
|
||||||
),
|
yaoStates: _selectedYaos.cast<YaoType>(),
|
||||||
);
|
);
|
||||||
|
if (!mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Navigator.of(context).push(
|
||||||
|
MaterialPageRoute<void>(
|
||||||
|
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: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
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,
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user