import 'package:flutter/material.dart'; import 'package:ai_english_learning/features/vocabulary/models/word_model.dart'; import 'package:ai_english_learning/features/vocabulary/models/learning_session_model.dart'; class StudyCardWidget extends StatefulWidget { final Word word; final Function(StudyDifficulty) onAnswer; final VoidCallback? onNext; const StudyCardWidget({ Key? key, required this.word, required this.onAnswer, this.onNext, }) : super(key: key); @override State createState() => _StudyCardWidgetState(); } class _StudyCardWidgetState extends State with SingleTickerProviderStateMixin { bool _showAnswer = false; late AnimationController _flipController; late Animation _flipAnimation; @override void initState() { super.initState(); _flipController = AnimationController( duration: const Duration(milliseconds: 300), vsync: this, ); _flipAnimation = Tween(begin: 0, end: 1).animate( CurvedAnimation(parent: _flipController, curve: Curves.easeInOut), ); } @override void dispose() { _flipController.dispose(); super.dispose(); } void _toggleAnswer() { setState(() { _showAnswer = !_showAnswer; if (_showAnswer) { _flipController.forward(); } else { _flipController.reverse(); } }); } @override Widget build(BuildContext context) { return Column( children: [ // 卡片主体 Expanded( child: GestureDetector( onTap: _toggleAnswer, child: AnimatedBuilder( animation: _flipAnimation, builder: (context, child) { final angle = _flipAnimation.value * 3.14159; final transform = Matrix4.identity() ..setEntry(3, 2, 0.001) ..rotateY(angle); return Transform( transform: transform, alignment: Alignment.center, child: angle < 1.57 ? _buildFrontCard() : Transform( transform: Matrix4.identity()..rotateY(3.14159), alignment: Alignment.center, child: _buildBackCard(), ), ); }, ), ), ), const SizedBox(height: 16), // 答案按钮 if (_showAnswer) _buildAnswerButtons(), // 提示文本 if (!_showAnswer) Padding( padding: const EdgeInsets.all(16), child: Text( '点击卡片查看答案', style: TextStyle( fontSize: 14, color: Colors.grey[600], ), ), ), ], ); } Widget _buildFrontCard() { return Card( elevation: 8, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Container( width: double.infinity, padding: const EdgeInsets.all(32), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ // 单词 Text( widget.word.word, style: const TextStyle( fontSize: 48, fontWeight: FontWeight.bold, ), textAlign: TextAlign.center, ), const SizedBox(height: 16), // 音标 if (widget.word.phonetic != null) Text( widget.word.phonetic!, style: TextStyle( fontSize: 18, color: Colors.grey[600], ), ), const SizedBox(height: 32), // 提示:点击查看释义 Icon( Icons.flip, size: 32, color: Colors.grey[400], ), ], ), ), ); } Widget _buildBackCard() { return Card( elevation: 8, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), child: Container( width: double.infinity, padding: const EdgeInsets.all(24), child: SingleChildScrollView( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 单词和音标 Center( child: Column( children: [ Text( widget.word.word, style: const TextStyle( fontSize: 32, fontWeight: FontWeight.bold, ), ), if (widget.word.phonetic != null) Text( widget.word.phonetic!, style: TextStyle( fontSize: 16, color: Colors.grey[600], ), ), ], ), ), const SizedBox(height: 24), const Divider(), const SizedBox(height: 16), // 释义 if (widget.word.definitions.isNotEmpty) ...[ const Text( '释义', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), ...widget.word.definitions.map((def) => Padding( padding: const EdgeInsets.only(bottom: 8), child: Text( '• ${def.translation}', style: const TextStyle(fontSize: 14), ), )), const SizedBox(height: 16), ], // 例句 if (widget.word.examples.isNotEmpty) ...[ const Text( '例句', style: TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), ...widget.word.examples.take(2).map((example) => Padding( padding: const EdgeInsets.only(bottom: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( example.sentence, style: const TextStyle( fontSize: 14, fontStyle: FontStyle.italic, ), ), const SizedBox(height: 4), Text( example.translation, style: TextStyle( fontSize: 13, color: Colors.grey[700], ), ), ], ), )), ], ], ), ), ), ); } Widget _buildAnswerButtons() { return Padding( padding: const EdgeInsets.symmetric(horizontal: 16), child: Column( children: [ Row( children: [ // 完全忘记 Expanded( child: _DifficultyButton( label: '完全忘记', icon: Icons.close, color: Colors.red, onPressed: () => widget.onAnswer(StudyDifficulty.forgot), ), ), const SizedBox(width: 8), // 困难 Expanded( child: _DifficultyButton( label: '困难', icon: Icons.sentiment_dissatisfied, color: Colors.orange, onPressed: () => widget.onAnswer(StudyDifficulty.hard), ), ), ], ), const SizedBox(height: 8), Row( children: [ // 一般 Expanded( child: _DifficultyButton( label: '一般', icon: Icons.sentiment_neutral, color: Colors.blue, onPressed: () => widget.onAnswer(StudyDifficulty.good), ), ), const SizedBox(width: 8), // 容易 Expanded( child: _DifficultyButton( label: '容易', icon: Icons.sentiment_satisfied, color: Colors.green, onPressed: () => widget.onAnswer(StudyDifficulty.easy), ), ), const SizedBox(width: 8), // 完美 Expanded( child: _DifficultyButton( label: '完美', icon: Icons.sentiment_very_satisfied, color: Colors.purple, onPressed: () => widget.onAnswer(StudyDifficulty.perfect), ), ), ], ), ], ), ); } } class _DifficultyButton extends StatelessWidget { final String label; final IconData icon; final Color color; final VoidCallback onPressed; const _DifficultyButton({ required this.label, required this.icon, required this.color, required this.onPressed, }); @override Widget build(BuildContext context) { return ElevatedButton( onPressed: onPressed, style: ElevatedButton.styleFrom( backgroundColor: color, foregroundColor: Colors.white, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Column( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, size: 20), const SizedBox(height: 4), Text( label, style: const TextStyle(fontSize: 12), ), ], ), ); } }