feat: 完善听力口语辅助状态记录、练习分块与复习抽查间隔机制
This commit is contained in:
@@ -6,15 +6,23 @@ class _SpeakingStep extends StatefulWidget {
|
||||
required this.segmentId,
|
||||
required this.text,
|
||||
this.tip = '',
|
||||
this.chunks = const [],
|
||||
this.examples = const [],
|
||||
required this.buildIndex,
|
||||
required this.onBuildProgress,
|
||||
required this.keepRecording,
|
||||
required this.onContinue,
|
||||
});
|
||||
final String segmentId;
|
||||
final String text;
|
||||
final String tip;
|
||||
final List<String> chunks;
|
||||
final List<String> examples;
|
||||
final int buildIndex;
|
||||
final ValueChanged<int> onBuildProgress;
|
||||
final AppState state;
|
||||
final bool keepRecording;
|
||||
final VoidCallback onContinue;
|
||||
final ValueChanged<bool> onContinue;
|
||||
|
||||
@override
|
||||
State<_SpeakingStep> createState() => _SpeakingStepState();
|
||||
@@ -89,12 +97,57 @@ class _SpeakingStepState extends State<_SpeakingStep>
|
||||
if (widget.tip.isNotEmpty)
|
||||
SectionCard(
|
||||
tint: AppColors.warm,
|
||||
child: Text(
|
||||
widget.tip,
|
||||
style: TextStyle(color: AppColors.warmInk),
|
||||
),
|
||||
child: Text(widget.tip, style: TextStyle(color: AppColors.warmInk)),
|
||||
),
|
||||
SegmentUsage(segmentId: widget.segmentId, state: widget.state),
|
||||
if (widget.chunks.length >= 2)
|
||||
SectionCard(
|
||||
tint: AppColors.surfaceMuted,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text('拆开练(可选)'),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
widget.buildIndex == 0
|
||||
? '先听词块,再逐步合成整句。'
|
||||
: widget.chunks.take(widget.buildIndex).join(' '),
|
||||
),
|
||||
TextButton.icon(
|
||||
onPressed: () async {
|
||||
final next = widget.buildIndex < widget.chunks.length
|
||||
? widget.buildIndex + 1
|
||||
: 1;
|
||||
await VoiceService.instance.speak(
|
||||
widget.chunks.take(next).join(' '),
|
||||
);
|
||||
widget.onBuildProgress(next);
|
||||
},
|
||||
icon: const Icon(Icons.play_arrow),
|
||||
label: Text(
|
||||
widget.buildIndex == widget.chunks.length
|
||||
? '从头再练'
|
||||
: '听下一段并跟读',
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (widget.examples.isNotEmpty)
|
||||
ExpansionTile(
|
||||
title: Text('更多示范句(${widget.examples.length})'),
|
||||
children: [
|
||||
for (final example in widget.examples)
|
||||
ListTile(
|
||||
title: LexiconText(example, state: widget.state),
|
||||
trailing: IconButton(
|
||||
tooltip: '播放示范句',
|
||||
icon: const Icon(Icons.volume_up_outlined),
|
||||
onPressed: () => VoiceService.instance.speak(example),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
SecondaryButton(
|
||||
label: transcribing
|
||||
? '正在 AI 识别发音…'
|
||||
@@ -146,8 +199,10 @@ class _SpeakingStepState extends State<_SpeakingStep>
|
||||
),
|
||||
),
|
||||
PrimaryButton(
|
||||
label: transcript.isEmpty ? '我已跟读,继续' : '确认并继续',
|
||||
onPressed: widget.onContinue,
|
||||
label: recordingPath == null ? '跳过跟读,继续' : '录音完成,继续',
|
||||
onPressed: (listening || transcribing)
|
||||
? null
|
||||
: () => widget.onContinue(recordingPath != null),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user