Files

114 lines
3.3 KiB
Dart

import 'package:flutter/material.dart';
import '../../core/app_state.dart';
import '../../core/app_theme.dart';
import '../../core/courses/courses.dart';
import '../../widgets/app_widgets.dart';
/// 课程路径:全部课程按顺序排列,显示完成、当前与锁定状态。
class LessonPath extends StatelessWidget {
const LessonPath({
super.key,
required this.state,
required this.onOpenLesson,
});
final AppState state;
final ValueChanged<String> onOpenLesson;
@override
Widget build(BuildContext context) {
final done = allLessons
.where((lesson) => state.completedLessonIds.contains(lesson.id))
.length;
return SpacedColumn(
spacing: 10,
children: [
Row(
children: [
Expanded(
child: Text(
'课程路径',
style: Theme.of(context).textTheme.titleMedium,
),
),
Text(
'$done/${allLessons.length} 完成',
style: TextStyle(fontSize: 13, color: AppColors.muted),
),
],
),
if (state.reviewBacklog)
Text(
'复习有积压:先完成到期复习,新课暂时锁定;已学课程仍可重温。',
style: TextStyle(fontSize: 13, color: AppColors.warmInk),
),
for (final lesson in allLessons)
_LessonTile(
lesson: lesson,
state: state,
onTap: () => onOpenLesson(lesson.id),
),
],
);
}
}
class _LessonTile extends StatelessWidget {
const _LessonTile({
required this.lesson,
required this.state,
required this.onTap,
});
final SeedLesson lesson;
final AppState state;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
final completed = state.completedLessonIds.contains(lesson.id);
final current = lesson.id == state.activeLessonId && !completed;
final open =
state.isLessonUnlocked(lesson.id) &&
(!state.reviewBacklog || completed);
final segments = lesson.segments.length;
final segmentsDone = lesson.segments
.where((segment) => state.isSegmentComplete(segment.id))
.length;
return SectionCard(
tint: current ? AppColors.softGreen : null,
onTap: open ? onTap : null,
child: Row(
children: [
Icon(
completed
? Icons.check_circle
: open
? Icons.play_circle_outline
: Icons.lock_outline,
color: completed || current ? AppColors.green : AppColors.muted,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'第 ${lesson.number} 课 · ${lesson.title}',
style: const TextStyle(fontWeight: FontWeight.w600),
),
const SizedBox(height: 3),
Text(
segments > 1
? '${lesson.outcome} · 小段 $segmentsDone/$segments'
: lesson.outcome,
style: Theme.of(context).textTheme.bodyMedium,
),
],
),
),
],
),
);
}
}