import 'package:flutter/material.dart'; import '../../../../l10n/app_localizations.dart'; import '../../../../shared/theme/app_color_palette.dart'; import '../../../../shared/theme/design_tokens.dart'; import '../../../../shared/widgets/divination/divination_shared_widgets.dart'; import '../../../../shared/widgets/toast/toast.dart'; import '../../../../shared/widgets/toast/toast_type.dart'; import '../../data/models/divination_params.dart'; import 'auto_divination_screen.dart'; import 'manual_divination_screen.dart'; class DivinationScreen extends StatefulWidget { const DivinationScreen({super.key}); @override State createState() => _DivinationScreenState(); } class _DivinationScreenState extends State { late DivinationParams _params; final TextEditingController _questionController = TextEditingController(); @override void initState() { super.initState(); _params = DivinationMockData.initial(); _questionController.addListener(_syncQuestion); } @override void dispose() { _questionController ..removeListener(_syncQuestion) ..dispose(); super.dispose(); } void _syncQuestion() { _params = _params.copyWith(question: _questionController.text.trim()); } @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; final l10n = AppLocalizations.of(context)!; return Scaffold( backgroundColor: colors.surface, appBar: AppBar( backgroundColor: colors.surface, surfaceTintColor: colors.surface, title: Text(l10n.divinationScreenTitle), centerTitle: true, ), body: _buildBody(context, l10n), ); } Widget _buildBody(BuildContext context, AppLocalizations l10n) { final palette = Theme.of(context).extension()!; return GestureDetector( onTap: () => FocusScope.of(context).unfocus(), child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB( AppSpacing.xl, AppSpacing.lg, AppSpacing.xl, AppSpacing.xl, ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _GuideEntryCard(onTap: () => _showGuide(context, l10n)), const SizedBox(height: AppSpacing.lg), _MethodSection( selected: _params.method, onChanged: (method) { setState(() { _params = _params.copyWith(method: method); }); }, l10n: l10n, ), const SizedBox(height: AppSpacing.xl), Text( l10n.divinationQuestionTypePrompt, style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: AppSpacing.sm), _QuestionTypeSelector( selected: _params.questionType, onChanged: (type) { setState(() { _params = _params.copyWith(questionType: type); }); }, l10n: l10n, ), const SizedBox(height: AppSpacing.lg), Text( l10n.divinationQuestionInputPrompt, style: Theme.of(context).textTheme.titleMedium, ), const SizedBox(height: AppSpacing.sm), _QuestionTextField(controller: _questionController, l10n: l10n), const SizedBox(height: AppSpacing.xl), _StartButton(onPressed: _onStart, l10n: l10n), const SizedBox(height: AppSpacing.sm), Center( child: Text( l10n.divinationCoinBalance(_params.coinBalance), style: Theme.of( context, ).textTheme.bodySmall?.copyWith(color: palette.warning), ), ), ], ), ), ); } void _onStart() { final l10n = AppLocalizations.of(context)!; if (_params.question.isEmpty) { Toast.show( context, l10n.toastPleaseInputQuestion, type: ToastType.warning, ); return; } if (_params.coinBalance <= 0) { Toast.show(context, l10n.toastCoinInsufficient, type: ToastType.warning); return; } if (_params.method == DivinationMethod.manual) { final nextParams = _params.copyWith(divinationTime: DateTime.now()); Navigator.of(context).push( MaterialPageRoute( builder: (_) => ManualDivinationScreen(params: nextParams), ), ); return; } final nextParams = _params.copyWith(divinationTime: DateTime.now()); Navigator.of(context).push( MaterialPageRoute( builder: (_) => AutoDivinationScreen(params: nextParams), ), ); } } class _GuideEntryCard extends StatelessWidget { const _GuideEntryCard({required this.onTap}); final VoidCallback onTap; @override Widget build(BuildContext context) { final l10n = AppLocalizations.of(context)!; return DivinationInstructionCard( text: l10n.divinationRecommendManual, onTap: onTap, ); } } class _MethodSection extends StatelessWidget { const _MethodSection({ required this.selected, required this.onChanged, required this.l10n, }); final DivinationMethod selected; final ValueChanged onChanged; final AppLocalizations l10n; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Text( l10n.divinationSelectMethod, style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(width: AppSpacing.sm), IconButton( onPressed: () => _showMethodTip(context, l10n), icon: Icon( Icons.help_outline, color: Theme.of(context).colorScheme.primary, ), ), ], ), const SizedBox(height: AppSpacing.sm), _MethodSegment(selected: selected, onChanged: onChanged, l10n: l10n), ], ); } } class _MethodSegment extends StatelessWidget { const _MethodSegment({ required this.selected, required this.onChanged, required this.l10n, }); final DivinationMethod selected; final ValueChanged onChanged; final AppLocalizations l10n; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; return SizedBox( height: 40, child: Row( children: [ _SegmentButton( text: l10n.divinationManualMethod, selected: selected == DivinationMethod.manual, onTap: () => onChanged(DivinationMethod.manual), color: colors.primary, isLeft: true, ), _SegmentButton( text: l10n.divinationAutoMethod, selected: selected == DivinationMethod.auto, onTap: () => onChanged(DivinationMethod.auto), color: colors.primary, isRight: true, ), ], ), ); } } class _SegmentButton extends StatelessWidget { const _SegmentButton({ required this.text, required this.selected, required this.onTap, required this.color, this.isLeft = false, this.isRight = false, }); final String text; final bool selected; final VoidCallback onTap; final Color color; final bool isLeft; final bool isRight; @override Widget build(BuildContext context) { return Expanded( child: InkWell( onTap: onTap, borderRadius: BorderRadius.horizontal( left: isLeft ? Radius.circular(AppRadius.sm) : Radius.zero, right: isRight ? Radius.circular(AppRadius.sm) : Radius.zero, ), child: Container( decoration: BoxDecoration( color: selected ? color : color.withValues(alpha: 0), borderRadius: BorderRadius.horizontal( left: isLeft ? Radius.circular(AppRadius.sm) : Radius.zero, right: isRight ? Radius.circular(AppRadius.sm) : Radius.zero, ), border: Border.all(color: color), ), alignment: Alignment.center, child: Text( text, style: Theme.of(context).textTheme.titleMedium?.copyWith( color: selected ? Theme.of(context).colorScheme.onPrimary : color, fontWeight: FontWeight.w500, ), ), ), ), ); } } class _QuestionTextField extends StatelessWidget { const _QuestionTextField({required this.controller, required this.l10n}); final TextEditingController controller; final AppLocalizations l10n; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; return TextField( controller: controller, maxLines: 4, decoration: InputDecoration( hintText: l10n.divinationQuestionInputHint, filled: true, fillColor: colors.surface, enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppRadius.sm), borderSide: BorderSide(color: colors.outline), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(AppRadius.sm), borderSide: BorderSide(color: colors.primary), ), ), ); } } class _StartButton extends StatelessWidget { const _StartButton({required this.onPressed, required this.l10n}); final VoidCallback onPressed; final AppLocalizations l10n; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; return SizedBox( width: double.infinity, height: 50, child: FilledButton( style: FilledButton.styleFrom( backgroundColor: colors.primary, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(AppRadius.sm), ), ), onPressed: onPressed, child: Text(l10n.divinationStartButton), ), ); } } Future _showMethodTip(BuildContext context, AppLocalizations l10n) { return showDialog( context: context, builder: (context) { return AlertDialog( title: Text(l10n.divinationMethodTipTitle), content: Text( '${l10n.divinationMethodTipAuto}\n\n${l10n.divinationMethodTipManual}\n\n${l10n.divinationMethodTipRecommend}', ), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: Text(l10n.divinationIAcknowledge), ), ], ); }, ); } Future _showGuide(BuildContext context, AppLocalizations l10n) { return showDialog( context: context, builder: (context) { return DivinationGuideDialog( title: l10n.divinationManualGuideTitle, guideImages: const [ 'assets/images/qigua/lc1.jpg', 'assets/images/qigua/lc2.jpg', 'assets/images/qigua/lc3.jpg', 'assets/images/qigua/lc4.jpg', 'assets/images/qigua/lc5.jpg', ], instructionText: l10n.divinationManualGuideInstruction, ); }, ); } class _QuestionTypeSelector extends StatelessWidget { const _QuestionTypeSelector({ required this.selected, required this.onChanged, required this.l10n, }); final QuestionType selected; final ValueChanged onChanged; final AppLocalizations l10n; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; final types = <(QuestionType, String, IconData)>[ (QuestionType.career, l10n.questionTypeCareer, Icons.work), (QuestionType.love, l10n.questionTypeLove, Icons.favorite), (QuestionType.wealth, l10n.questionTypeWealth, Icons.attach_money), (QuestionType.fortune, l10n.questionTypeFortune, Icons.trending_up), (QuestionType.dream, l10n.questionTypeDream, Icons.bedtime), (QuestionType.health, l10n.questionTypeHealth, Icons.health_and_safety), (QuestionType.study, l10n.questionTypeStudy, Icons.school), (QuestionType.search, l10n.questionTypeSearch, Icons.search), (QuestionType.other, l10n.questionTypeOther, Icons.help), ]; return SingleChildScrollView( scrollDirection: Axis.horizontal, child: Row( children: types.map((item) { final isSelected = selected == item.$1; return Padding( padding: const EdgeInsets.only(right: AppSpacing.sm), child: _TypeChip( label: item.$2, icon: item.$3, isSelected: isSelected, onTap: () => onChanged(item.$1), selectedColor: colors.primary, ), ); }).toList(), ), ); } } class _TypeChip extends StatelessWidget { const _TypeChip({ required this.label, required this.icon, required this.isSelected, required this.onTap, required this.selectedColor, }); final String label; final IconData icon; final bool isSelected; final VoidCallback onTap; final Color selectedColor; @override Widget build(BuildContext context) { final colors = Theme.of(context).colorScheme; return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(AppRadius.sm), child: Container( width: 92, height: 45, decoration: BoxDecoration( color: isSelected ? selectedColor.withValues(alpha: 0.1) : colors.surface, borderRadius: BorderRadius.circular(AppRadius.sm), border: Border.all( color: isSelected ? selectedColor : colors.outline, width: isSelected ? 2 : 1, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 20, color: isSelected ? selectedColor : colors.onSurface, ), const SizedBox(width: AppSpacing.xs), Text( label, style: Theme.of(context).textTheme.bodyMedium?.copyWith( fontWeight: FontWeight.w700, color: isSelected ? selectedColor : colors.onSurface, ), ), ], ), ), ); } }