import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../models/vocabulary_book_model.dart'; import '../models/review_models.dart'; import '../models/word_model.dart'; import '../providers/vocabulary_provider.dart'; import 'dart:math'; class SmartReviewScreen extends ConsumerStatefulWidget { final VocabularyBook? vocabularyBook; final ReviewMode reviewMode; final int dailyTarget; const SmartReviewScreen({ super.key, this.vocabularyBook, this.reviewMode = ReviewMode.adaptive, this.dailyTarget = 20, }); @override ConsumerState createState() => _SmartReviewScreenState(); } class _SmartReviewScreenState extends ConsumerState { List _reviewWords = []; int _currentIndex = 0; bool _isLoading = true; bool _showAnswer = false; Map _reviewResults = {}; // 0: 不记得, 1: 模糊, 2: 记得 @override void initState() { super.initState(); _loadWords(); } Future _loadWords() async { setState(() => _isLoading = true); try { final notifier = ref.read(vocabularyProvider.notifier); await notifier.loadReviewWords(); final state = ref.read(vocabularyProvider); final words = state.reviewWords; if (words.isEmpty) { // 如果没有复习词汇,生成示例数据 _reviewWords = _generateSampleWords(); } else { _reviewWords = words.take(widget.dailyTarget).toList(); } } catch (e) { _reviewWords = _generateSampleWords(); } setState(() => _isLoading = false); } List _generateSampleWords() { final sampleData = [ {'word': 'abandon', 'phonetic': '/əˈbændən/', 'translation': '放弃;遗弃'}, {'word': 'ability', 'phonetic': '/əˈbɪləti/', 'translation': '能力;才能'}, {'word': 'abroad', 'phonetic': '/əˈbrɔːd/', 'translation': '在国外;到国外'}, {'word': 'absence', 'phonetic': '/ˈæbsəns/', 'translation': '缺席;缺乏'}, {'word': 'absolute', 'phonetic': '/ˈæbsəluːt/', 'translation': '绝对的;完全的'}, {'word': 'absorb', 'phonetic': '/əbˈsɔːrb/', 'translation': '吸收;吸引'}, {'word': 'abstract', 'phonetic': '/ˈæbstrækt/', 'translation': '抽象的;抽象概念'}, {'word': 'abundant', 'phonetic': '/əˈbʌndənt/', 'translation': '丰富的;充裕的'}, {'word': 'academic', 'phonetic': '/ˌækəˈdemɪk/', 'translation': '学术的;学院的'}, {'word': 'accept', 'phonetic': '/əkˈsept/', 'translation': '接受;承认'}, ]; return List.generate( widget.dailyTarget.clamp(1, sampleData.length), (index) { final data = sampleData[index % sampleData.length]; return Word( id: '${index + 1}', word: data['word']!, phonetic: data['phonetic'], difficulty: WordDifficulty.intermediate, frequency: 1000, definitions: [ WordDefinition( type: WordType.noun, definition: 'Example definition', translation: data['translation']!, ), ], createdAt: DateTime.now(), updatedAt: DateTime.now(), ); }, ); } @override Widget build(BuildContext context) { if (_isLoading) { return Scaffold( appBar: AppBar( title: const Text('智能复习'), ), body: const Center( child: CircularProgressIndicator(), ), ); } if (_currentIndex >= _reviewWords.length) { return _buildCompleteScreen(); } return Scaffold( appBar: AppBar( title: Text('智能复习 (${_currentIndex + 1}/${_reviewWords.length})'), actions: [ TextButton( onPressed: _showExitConfirmDialog, child: const Text( '退出', style: TextStyle(color: Colors.white), ), ), ], ), body: _buildReviewCard(), ); } Widget _buildReviewCard() { final word = _reviewWords[_currentIndex]; final translation = word.definitions.isNotEmpty ? word.definitions.first.translation : '示例释义'; return Column( children: [ // 进度条 LinearProgressIndicator( value: (_currentIndex + 1) / _reviewWords.length, backgroundColor: Colors.grey[200], valueColor: const AlwaysStoppedAnimation(Color(0xFF9C27B0)), ), Expanded( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.all(24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 卡片 Container( width: double.infinity, padding: const EdgeInsets.all(32), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(20), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.1), blurRadius: 20, offset: const Offset(0, 4), ), ], ), child: Column( children: [ // 单词 Text( word.word, style: const TextStyle( fontSize: 42, fontWeight: FontWeight.bold, color: Color(0xFF9C27B0), ), ), if (word.phonetic != null) ...[ const SizedBox(height: 12), Text( word.phonetic!, style: const TextStyle( fontSize: 20, color: Colors.grey, fontStyle: FontStyle.italic, ), ), ], const SizedBox(height: 32), // 音频按钮 IconButton( onPressed: () => _playAudio(word.word), icon: const Icon( Icons.volume_up, size: 48, color: Color(0xFF9C27B0), ), ), const SizedBox(height: 32), // 答案区域 AnimatedContainer( duration: const Duration(milliseconds: 300), curve: Curves.easeInOut, height: _showAnswer ? null : 0, child: _showAnswer ? Column( children: [ const Divider(), const SizedBox(height: 16), const Text( '释义', style: TextStyle( fontSize: 14, color: Colors.grey, ), ), const SizedBox(height: 8), Text( translation, style: const TextStyle( fontSize: 24, fontWeight: FontWeight.w600, ), textAlign: TextAlign.center, ), ], ) : const SizedBox.shrink(), ), ], ), ), const SizedBox(height: 32), // 提示文本 if (!_showAnswer) const Text( '回忆这个单词的意思,然后点击“显示答案”', style: TextStyle( fontSize: 14, color: Colors.grey, ), textAlign: TextAlign.center, ), ], ), ), ), ), // 底部按钮 Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.white, boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, -2), ), ], ), child: SafeArea( child: _showAnswer ? Row( children: [ Expanded( child: _buildResultButton( label: '不记得', color: Colors.red, result: 0, ), ), const SizedBox(width: 12), Expanded( child: _buildResultButton( label: '模糊', color: Colors.orange, result: 1, ), ), const SizedBox(width: 12), Expanded( child: _buildResultButton( label: '记得', color: Colors.green, result: 2, ), ), ], ) : ElevatedButton( onPressed: () { setState(() { _showAnswer = true; }); }, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF9C27B0), padding: const EdgeInsets.symmetric(vertical: 16), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text( '显示答案', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), ), ), ], ); } Widget _buildResultButton({ required String label, required Color color, required int result, }) { return ElevatedButton( onPressed: () => _recordResult(result), style: ElevatedButton.styleFrom( backgroundColor: color, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: Text( label, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.bold, ), ), ); } void _recordResult(int result) { setState(() { _reviewResults[_currentIndex] = result; _showAnswer = false; _currentIndex++; }); } Widget _buildCompleteScreen() { final remembered = _reviewResults.values.where((r) => r == 2).length; final fuzzy = _reviewResults.values.where((r) => r == 1).length; final forgotten = _reviewResults.values.where((r) => r == 0).length; return Scaffold( appBar: AppBar( title: const Text('复习完成'), automaticallyImplyLeading: false, ), body: Center( child: Padding( padding: const EdgeInsets.all(24), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 120, height: 120, decoration: BoxDecoration( color: const Color(0xFF9C27B0).withOpacity(0.1), shape: BoxShape.circle, ), child: const Center( child: Icon( Icons.check_circle, size: 64, color: Color(0xFF9C27B0), ), ), ), const SizedBox(height: 24), const Text( '复习完成!', style: TextStyle( fontSize: 28, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 16), Text( '共复习 ${_reviewWords.length} 个单词', style: const TextStyle( fontSize: 18, color: Colors.grey, ), ), const SizedBox(height: 32), // 统计信息 Container( padding: const EdgeInsets.all(20), decoration: BoxDecoration( color: Colors.white, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.05), blurRadius: 10, offset: const Offset(0, 2), ), ], ), child: Column( children: [ _buildStatRow( '完全记得', remembered, Colors.green, ), const SizedBox(height: 12), _buildStatRow( '模糊记得', fuzzy, Colors.orange, ), const SizedBox(height: 12), _buildStatRow( '不记得', forgotten, Colors.red, ), ], ), ), const SizedBox(height: 48), ElevatedButton( onPressed: () => Navigator.of(context).pop(), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF9C27B0), padding: const EdgeInsets.symmetric( horizontal: 48, vertical: 16, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), ), child: const Text( '完成', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), ), const SizedBox(height: 16), TextButton( onPressed: () { setState(() { _currentIndex = 0; _reviewResults.clear(); _showAnswer = false; }); _loadWords(); }, child: const Text('重新复习'), ), ], ), ), ), ); } Widget _buildStatRow(String label, int count, Color color) { return Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( width: 12, height: 12, decoration: BoxDecoration( color: color, shape: BoxShape.circle, ), ), const SizedBox(width: 12), Text( label, style: const TextStyle( fontSize: 16, ), ), ], ), Text( '$count', style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: color, ), ), ], ); } void _playAudio(String word) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text('正在播放 "$word" 的发音'), duration: const Duration(seconds: 1), ), ); } void _showExitConfirmDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('退出复习'), content: const Text('确定要退出吗?当前进度将不会保存。'), actions: [ TextButton( onPressed: () => Navigator.of(context).pop(), child: const Text('取消'), ), TextButton( onPressed: () { Navigator.of(context).pop(); Navigator.of(context).pop(); }, child: const Text('确定'), ), ], ), ); } }