import 'package:flutter/material.dart'; import 'dart:async'; class AnalyzingDialog extends StatefulWidget { /// Stage 通知用 ValueNotifier。 /// null のとき(プロキシモード・キャッシュヒット後など)は Stage1 メッセージのみを表示する。 /// value が 2 に変わると Stage2 メッセージセットに切り替わる。 final ValueNotifier? stageNotifier; const AnalyzingDialog({super.key, this.stageNotifier}); @override State createState() => _AnalyzingDialogState(); } class _AnalyzingDialogState extends State { int _messageIndex = 0; Timer? _timer; static const _stage1Messages = [ 'ラベルを読み取っています...', '文字を一字一句確認中...', ]; static const _stage2Messages = [ 'この日本酒の個性を分析中...', 'フレーバーチャートを描画しています...', '素敵なキャッチコピーを考えています...', ]; List get _currentMessages => (_stage == 2) ? _stage2Messages : _stage1Messages; int _stage = 1; @override void initState() { super.initState(); widget.stageNotifier?.addListener(_onStageChanged); _startMessageRotation(); } void _onStageChanged() { final newStage = widget.stageNotifier?.value ?? 1; if (newStage != _stage) { _timer?.cancel(); setState(() { _stage = newStage; _messageIndex = 0; }); _startMessageRotation(); } } void _startMessageRotation() { _timer = Timer.periodic(const Duration(milliseconds: 1800), (timer) { if (!mounted) { timer.cancel(); return; } final messages = _currentMessages; if (_messageIndex < messages.length - 1) { setState(() => _messageIndex++); } else { timer.cancel(); } }); } @override void dispose() { _timer?.cancel(); widget.stageNotifier?.removeListener(_onStageChanged); super.dispose(); } @override Widget build(BuildContext context) { final messages = _currentMessages; final safeIndex = _messageIndex.clamp(0, messages.length - 1); return Dialog( child: Padding( padding: const EdgeInsets.all(24.0), child: Column( mainAxisSize: MainAxisSize.min, children: [ const CircularProgressIndicator(), const SizedBox(height: 24), Text( messages[safeIndex], style: Theme.of(context).textTheme.titleMedium, textAlign: TextAlign.center, ), if (widget.stageNotifier != null) ...[ const SizedBox(height: 12), Text( 'ステップ $_stage / 2', style: Theme.of(context).textTheme.bodySmall?.copyWith( color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.4), ), ), ], ], ), ), ); } }