feat: 优化口语防重复问答、课程推进流转、键盘输入流畅度与竖屏锁定
- AI口语约束:在对话系统提示词与单轮指导中增加防重复问答约束,避免重复寒暄及索取已提供信息,根据历史自然向前推进 - 课程流转:修复多段课程学完后今日任务卡片流转下一课,及退出重进定位逻辑 - 竖屏锁定:在 Flutter、Android 及 iOS 平台配置仅支持竖屏显示 - 对话交互:优化对话界面文本输入重绘与词汇查询,解决键盘输入卡顿 - 测试用例:补充并更新单轮约束、状态流转与返回键退出测试,212项测试全绿
This commit is contained in:
@@ -8,6 +8,7 @@ import 'package:kouyu_english/features/review/review_page.dart';
|
||||
import 'package:kouyu_english/features/shell/learning_shell.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:kouyu_english/core/courses/course_repository.dart';
|
||||
import 'support/app_assets.dart';
|
||||
|
||||
void main() {
|
||||
@@ -221,4 +222,83 @@ void main() {
|
||||
expect(find.text('四技能评估'), findsOneWidget);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'LessonFlow on complete step: back button finalizes segment and advances lesson',
|
||||
(tester) async {
|
||||
await tester.runAsync(
|
||||
() => CourseRepository.instance.load(levels: {'A0'}),
|
||||
);
|
||||
final state = AppState()..finishOnboarding();
|
||||
expect(state.activeLessonId, 'a0-01');
|
||||
|
||||
await tester.pumpWidget(MaterialApp(home: LearningShell(state: state)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Tap '开始今天的学习' to enter LessonFlow
|
||||
await tester.tap(find.text('开始今天的学习'));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Complete all steps of a0-01
|
||||
state.completePreview();
|
||||
state.completeListening(recognized: true);
|
||||
state.completeSpeaking();
|
||||
state.completeReading();
|
||||
state.completeWriting(assisted: false, rawAnswer: 'hello');
|
||||
state.completeLessonDialogue();
|
||||
state.completeIndependentAttempt(assisted: false, rawAnswer: 'hello');
|
||||
expect(state.lessonStep, LessonStep.complete);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// We should be in lesson flow complete screen
|
||||
expect(find.text('本段已保存'), findsOneWidget);
|
||||
expect(find.text('回到首页'), findsOneWidget);
|
||||
expect(find.byIcon(Icons.arrow_back), findsOneWidget);
|
||||
|
||||
// Tap the top-left AppBar back button instead of '回到首页'
|
||||
await tester.tap(find.byIcon(Icons.arrow_back));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Should be back on the 学习 tab, and lesson must have advanced to a0-02
|
||||
expect(state.completedLessonIds, contains('a0-01'));
|
||||
expect(state.activeLessonId, 'a0-02');
|
||||
expect(find.textContaining('第 2 课 · '), findsWidgets);
|
||||
},
|
||||
);
|
||||
|
||||
testWidgets(
|
||||
'TodayTaskCard reflects multi-segment progress and completed fallback',
|
||||
(tester) async {
|
||||
await tester.runAsync(
|
||||
() => CourseRepository.instance.load(levels: {'A0'}),
|
||||
);
|
||||
final state = AppState()..finishOnboarding();
|
||||
state.activeLessonId = 'a0-04'; // a0-04 has 3 segments
|
||||
|
||||
await tester.pumpWidget(MaterialApp(home: LearningShell(state: state)));
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Segment 1 (initial)
|
||||
expect(find.text('今日新课'), findsOneWidget);
|
||||
expect(find.text('开始今天的学习'), findsOneWidget);
|
||||
|
||||
// Now complete segment 1
|
||||
state.completeSegment('a0-04', 0);
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Segment 2 (resuming)
|
||||
expect(find.text('继续课程'), findsOneWidget);
|
||||
expect(find.text('继续学习第 2 段'), findsOneWidget);
|
||||
expect(find.textContaining('第 2/3 段'), findsWidgets);
|
||||
|
||||
// If activeLessonId is marked as completed, card targets next incomplete
|
||||
state.completedLessonIds.add('a0-04');
|
||||
state.notifyListeners();
|
||||
await tester.pumpAndSettle();
|
||||
|
||||
// Should target a0-01 or next incomplete, not show completed lesson
|
||||
expect(find.text('继续课程'), findsNothing);
|
||||
expect(find.textContaining('第 1 课 · '), findsWidgets);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user