import 'dart:async'; import 'package:flutter/material.dart'; import '../models/writing_task.dart'; import 'writing_result_screen.dart'; /// 写作练习页面 class WritingExerciseScreen extends StatefulWidget { final WritingTask task; const WritingExerciseScreen({ super.key, required this.task, }); @override State createState() => _WritingExerciseScreenState(); } class _WritingExerciseScreenState extends State { final TextEditingController _textController = TextEditingController(); Timer? _timer; int _remainingSeconds = 0; int _wordCount = 0; bool _isSubmitted = false; @override void initState() { super.initState(); final minutes = widget.task.timeLimit > 0 ? widget.task.timeLimit : 30; _remainingSeconds = minutes * 60; _startTimer(); _textController.addListener(_updateWordCount); } @override void dispose() { _timer?.cancel(); _textController.dispose(); super.dispose(); } void _startTimer() { _timer = Timer.periodic(const Duration(seconds: 1), (timer) { if (_remainingSeconds > 0) { setState(() { _remainingSeconds--; }); } else { _submitWriting(); } }); } void _updateWordCount() { final text = _textController.text.trim(); final words = text.isEmpty ? 0 : text.split(RegExp(r'\s+')).length; setState(() { _wordCount = words; }); } String _formatTime(int seconds) { final minutes = seconds ~/ 60; final remainingSeconds = seconds % 60; return '${minutes.toString().padLeft(2, '0')}:${remainingSeconds.toString().padLeft(2, '0')}'; } void _submitWriting() { if (_isSubmitted) return; setState(() { _isSubmitted = true; }); _timer?.cancel(); Navigator.pushReplacement( context, MaterialPageRoute( builder: (context) => WritingResultScreen( task: widget.task, content: _textController.text, wordCount: _wordCount, timeUsed: widget.task.timeLimit * 60 - _remainingSeconds, ), ), ); } void _showSubmitDialog() { showDialog( context: context, builder: (context) => AlertDialog( title: const Text('提交写作'), content: Text('确定要提交吗?当前已写${_wordCount}词,剩余时间${_formatTime(_remainingSeconds)}。'), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('继续写作'), ), TextButton( onPressed: () { Navigator.pop(context); _submitWriting(); }, child: const Text('确定提交'), ), ], ), ); } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: const Color(0xFFF5F5F5), appBar: AppBar( title: Text(widget.task.title), backgroundColor: Colors.white, foregroundColor: Colors.black, elevation: 0, actions: [ IconButton( icon: const Icon(Icons.help_outline), onPressed: _showTaskInfo, ), ], ), body: Column( children: [ _buildStatusBar(), Expanded( child: _buildWritingArea(), ), _buildBottomBar(), ], ), ); } Widget _buildStatusBar() { final timeColor = _remainingSeconds < 300 ? Colors.red : const Color(0xFF2196F3); // 5分钟内显示红色 final limit = widget.task.wordLimit > 0 ? widget.task.wordLimit : 200; final wordColor = _wordCount > limit ? Colors.red : const Color(0xFF4CAF50); return Container( padding: const EdgeInsets.all(16), color: Colors.white, child: Row( children: [ Expanded( child: _buildStatusItem( Icons.timer, '剩余时间', _formatTime(_remainingSeconds), timeColor, ), ), Container( width: 1, height: 40, color: Colors.grey[300], ), Expanded( child: _buildStatusItem( Icons.text_fields, '字数统计', '$_wordCount/$limit', wordColor, ), ), ], ), ); } Widget _buildStatusItem(IconData icon, String label, String value, Color color) { return Column( children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( icon, size: 16, color: color, ), const SizedBox(width: 4), Text( label, style: const TextStyle( fontSize: 12, color: Colors.grey, ), ), ], ), const SizedBox(height: 4), Text( value, style: TextStyle( fontSize: 18, fontWeight: FontWeight.bold, color: color, ), ), ], ); } Widget _buildWritingArea() { return Container( margin: const EdgeInsets.all(16), 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( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '写作提示:${widget.task.prompt}', style: const TextStyle( fontSize: 14, color: Colors.grey, fontStyle: FontStyle.italic, ), ), const SizedBox(height: 16), Expanded( child: TextField( controller: _textController, maxLines: null, expands: true, decoration: const InputDecoration( hintText: '请在此处开始写作...', border: InputBorder.none, hintStyle: TextStyle( color: Colors.grey, fontSize: 16, ), ), style: const TextStyle( fontSize: 16, height: 1.6, ), ), ), ], ), ); } Widget _buildBottomBar() { return Container( padding: const EdgeInsets.all(16), color: Colors.white, child: Row( children: [ Expanded( child: OutlinedButton( onPressed: _showTaskInfo, style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF2196F3), side: const BorderSide(color: Color(0xFF2196F3)), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.symmetric(vertical: 16), ), child: const Text('查看要求'), ), ), const SizedBox(width: 16), Expanded( child: ElevatedButton( onPressed: _wordCount > 0 ? _showSubmitDialog : null, style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF2196F3), foregroundColor: Colors.white, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(12), ), padding: const EdgeInsets.symmetric(vertical: 16), elevation: 0, ), child: const Text( '提交写作', style: TextStyle( fontWeight: FontWeight.bold, ), ), ), ), ], ), ); } void _showTaskInfo() { showModalBottomSheet( context: context, isScrollControlled: true, backgroundColor: Colors.transparent, builder: (context) => Container( height: MediaQuery.of(context).size.height * 0.7, decoration: const BoxDecoration( color: Colors.white, borderRadius: BorderRadius.vertical(top: Radius.circular(20)), ), child: Column( children: [ Container( padding: const EdgeInsets.all(20), child: Row( children: [ const Expanded( child: Text( '写作要求', style: TextStyle( fontSize: 20, fontWeight: FontWeight.bold, ), ), ), IconButton( onPressed: () => Navigator.pop(context), icon: const Icon(Icons.close), ), ], ), ), Expanded( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 20), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildInfoSection('写作提示', widget.task.prompt ?? '暂无写作提示'), const SizedBox(height: 20), _buildInfoSection('写作要求', widget.task.requirements.join('\n• ')), if (widget.task.keywords.isNotEmpty) ...[ const SizedBox(height: 20), _buildInfoSection('关键词', widget.task.keywords.join(', ')), ], ], ), ), ), ], ), ), ); } Widget _buildInfoSection(String title, String content) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( title, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: Colors.grey[50], borderRadius: BorderRadius.circular(12), ), child: Text( content, style: const TextStyle( fontSize: 14, height: 1.5, ), ), ), ], ); } }