import 'package:flutter/material.dart'; import '../../core/app_state.dart'; import '../../core/app_theme.dart'; import '../../core/seed_courses.dart'; import '../../widgets/app_widgets.dart'; class HomePage extends StatelessWidget { const HomePage({ super.key, required this.state, required this.onStartPrimaryTask, required this.onOpenDialogue, required this.onResumeLessonDialogue, required this.onStartReinforcement, required this.onOpenAssessment, }); final AppState state; final VoidCallback onStartPrimaryTask; final VoidCallback onOpenDialogue; final VoidCallback onResumeLessonDialogue; final VoidCallback onStartReinforcement; final ValueChanged onOpenAssessment; @override Widget build(BuildContext context) { final isReview = state.reviewIsPrimary; final count = state.dueReviewCount; final activeLesson = lessonById(state.activeLessonId); final activeSegment = state.activeSegmentIndexFor(activeLesson.id) + 1; final resumeDialogue = state.hasResumableLessonDialogue; final stageStep = !resumeDialogue && !isReview && state.allLessonsComplete ? _stageStep() : null; final primaryTitle = resumeDialogue ? '继续第 ${activeLesson.number} 课的课程对话' : isReview ? '先复习 $count 项' : stageStep?.title ?? '第 ${activeLesson.number} 课 · ${activeLesson.title}${activeLesson.segments.length > 1 ? ' · 第 $activeSegment/${activeLesson.segments.length} 段' : ''}'; final primaryNote = resumeDialogue ? '已保留你的对话进度和提示状态。' : isReview ? (state.reviewBacklog ? '有积压项目;先花几分钟清掉到期复习。' : '昨天练过的关键句,今天换个情境再用一次。') : stageStep?.note ?? '预热词汇 → 听说读写 → 对话 → 独立尝试'; final scene = state.recommendedScene; return AppPage( child: SpacedColumn( spacing: 16, children: [ const Eyebrow('今天的学习'), Text( '今天,说几句能用的英语。', style: Theme.of(context).textTheme.headlineMedium, ), Text( isReview ? '到期复习优先;完成后再进入新内容。' : '没有到期复习,继续完成一个小任务。', style: Theme.of(context).textTheme.bodyMedium, ), SectionCard( child: Row( children: [ Icon(Icons.psychology_outlined, color: AppColors.green), const SizedBox(width: 10), Expanded( child: Text( '已接触 ${state.knownItemCount} 项 · 可独立使用 ${state.usableMasteryCount} 项', ), ), ], ), ), SectionCard( tint: AppColors.softGreen, child: SpacedColumn( children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( primaryTitle, style: const TextStyle( fontSize: 16, fontWeight: FontWeight.w600, ), ), ), Text( isReview ? '${(count * 2).clamp(2, 10)} 分钟' : stageStep?.minutes ?? '12 分钟', style: TextStyle(color: AppColors.green), ), ], ), Text( primaryNote, style: Theme.of(context).textTheme.bodyMedium, ), PrimaryButton( label: resumeDialogue ? '继续对话' : isReview ? '开始复习' : stageStep?.action ?? '开始今天的学习', onPressed: resumeDialogue ? onResumeLessonDialogue : stageStep?.onPressed ?? onStartPrimaryTask, ), ], ), ), SectionCard( child: SpacedColumn( children: [ const Text( 'AI 情境对话', style: TextStyle(fontSize: 16, fontWeight: FontWeight.w600), ), Text( '${scene.title} · ${scene.script.prompts.length} 个任务 · 文字或语音输入', style: Theme.of(context).textTheme.bodyMedium, ), SecondaryButton(label: '开始情境对话', onPressed: onOpenDialogue), ], ), ), const _FrameworkNote(), ], ), ); } /// What comes after the last A0 lesson: consolidation until the core items /// are ready, then the stage assessment, then waiting for A1 content. _StageStep _stageStep() { final usable = '可使用 ${state.coreUsableCount}/48 · 已掌握 ${state.coreMasteredCount}/30'; if (state.a0Passed) { return _StageStep( title: 'A0 已通过', note: 'A1 课程准备中。先用巩固练习和情境对话保持手感。', action: '安排一题巩固练习', minutes: '3 分钟', onPressed: onStartReinforcement, ); } final packId = state.nextAssessmentPackId; if (state.a0AssessmentReady && packId != null) { return _StageStep( title: 'A0 阶段评估 · $packId', note: '$usable。可以开始阶段评估,两套评估间隔至少 24 小时。', action: '开始阶段评估', minutes: '15 分钟', onPressed: () => onOpenAssessment(packId), ); } return _StageStep( title: state.a0AssessmentReady ? '第二套评估 24 小时后开放' : 'A0 课程已学完', note: state.a0AssessmentReady ? '第一套评估已通过。等待期间继续巩固。' : '$usable。继续按时复习、做情境对话,达到要求后开放阶段评估。', action: '安排一题巩固练习', minutes: '3 分钟', onPressed: onStartReinforcement, ); } } class _StageStep { const _StageStep({ required this.title, required this.note, required this.action, required this.minutes, required this.onPressed, }); final String title; final String note; final String action; final String minutes; final VoidCallback onPressed; } class _FrameworkNote extends StatelessWidget { const _FrameworkNote(); @override Widget build(BuildContext context) => Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: AppColors.warm, borderRadius: BorderRadius.circular(14), ), child: Row( children: [ Icon(Icons.info_outline, color: AppColors.warmInk), SizedBox(width: 8), Expanded( child: Text( '文字回答可用于理解与写作练习;口语掌握须以录音或语音识别结果为准。可在“我的”配置 AI 服务。', style: TextStyle( color: AppColors.warmInk, fontSize: 13, height: 1.45, ), ), ), ], ), ); }