Merge pull request #5666 from pangeachat/5658-audio-practice-issues
5658 audio practice issues
This commit is contained in:
commit
f52f9c3744
6 changed files with 66 additions and 62 deletions
|
|
@ -456,6 +456,10 @@ class AudioPlayerState extends State<AudioPlayerWidget> {
|
|||
final duration = Duration(milliseconds: durationInt);
|
||||
_durationString = duration.minuteSecondString;
|
||||
}
|
||||
|
||||
if (widget.autoplay) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) => _onButtonTap());
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
|||
|
|
@ -97,7 +97,7 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
|
|||
|
||||
final ValueNotifier<bool> hintPressedNotifier = ValueNotifier<bool>(false);
|
||||
|
||||
final Set<String> _selectedCorrectAnswers = {};
|
||||
final Set<String> _clickedChoices = {};
|
||||
|
||||
// Track if we're showing the completion message for audio activities
|
||||
final ValueNotifier<bool> showingAudioCompletion = ValueNotifier<bool>(false);
|
||||
|
|
@ -347,7 +347,7 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
|
|||
activityState.value = const AsyncState.loading();
|
||||
selectedMorphChoice.value = null;
|
||||
hintPressedNotifier.value = false;
|
||||
_selectedCorrectAnswers.clear();
|
||||
_clickedChoices.clear();
|
||||
final nextActivityCompleter = _queue.removeFirst();
|
||||
|
||||
try {
|
||||
|
|
@ -565,6 +565,14 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
|
|||
if (_currentActivity == null) return;
|
||||
final activity = _currentActivity!;
|
||||
|
||||
// Mark this choice as clicked so it can't be clicked again
|
||||
if (_clickedChoices.contains(choiceContent)) {
|
||||
return;
|
||||
} else {
|
||||
setState(() {
|
||||
_clickedChoices.add(choiceContent);
|
||||
});
|
||||
}
|
||||
// Track the selection for display
|
||||
if (activity is MorphPracticeActivityModel) {
|
||||
selectedMorphChoice.value = SelectedMorphChoice(
|
||||
|
|
@ -577,9 +585,6 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
|
|||
|
||||
final isAudioActivity =
|
||||
activity.activityType == ActivityTypeEnum.lemmaAudio;
|
||||
if (isAudioActivity && isCorrect) {
|
||||
_selectedCorrectAnswers.add(choiceContent);
|
||||
}
|
||||
|
||||
if (isCorrect && !isAudioActivity) {
|
||||
// Non-audio activities disable choices after first correct answer
|
||||
|
|
@ -587,9 +592,17 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
|
|||
}
|
||||
|
||||
// Update activity record
|
||||
// For audio activities, find the token that matches the clicked word
|
||||
final tokenForChoice = isAudioActivity
|
||||
? activity.tokens.firstWhere(
|
||||
(t) => t.text.content.toLowerCase() == choiceContent.toLowerCase(),
|
||||
orElse: () => activity.tokens.first,
|
||||
)
|
||||
: activity.tokens.first;
|
||||
|
||||
PracticeRecordController.onSelectChoice(
|
||||
choiceContent,
|
||||
activity.tokens.first,
|
||||
tokenForChoice,
|
||||
activity,
|
||||
);
|
||||
|
||||
|
|
@ -602,11 +615,11 @@ class AnalyticsPracticeState extends State<AnalyticsPractice>
|
|||
|
||||
if (!isCorrect) return;
|
||||
|
||||
// For audio activities, check if all answers have been selected
|
||||
// For audio activities, check if all correct answers have been clicked
|
||||
if (isAudioActivity) {
|
||||
final allAnswers = activity.multipleChoiceContent.answers;
|
||||
final allSelected = allAnswers.every(
|
||||
(answer) => _selectedCorrectAnswers.contains(answer),
|
||||
(answer) => _clickedChoices.contains(answer),
|
||||
);
|
||||
|
||||
if (!allSelected) {
|
||||
|
|
|
|||
|
|
@ -247,6 +247,7 @@ class _AnalyticsPracticeCenterContent extends StatelessWidget {
|
|||
child: Center(
|
||||
child: AudioPlayerWidget(
|
||||
null,
|
||||
key: ValueKey('audio_${activity.eventId}'),
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
linkColor: Theme.of(context).colorScheme.secondary,
|
||||
fontSize:
|
||||
|
|
|
|||
|
|
@ -1,52 +0,0 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:fluffychat/l10n/l10n.dart';
|
||||
import 'package:fluffychat/pangea/analytics_practice/choice_cards/game_choice_card.dart';
|
||||
import 'package:fluffychat/pangea/common/widgets/word_audio_button.dart';
|
||||
import 'package:fluffychat/widgets/matrix.dart';
|
||||
|
||||
/// Displays an audio button with a select label in a row layout
|
||||
/// TODO: needs a better design and button handling
|
||||
class AudioChoiceCard extends StatelessWidget {
|
||||
final String text;
|
||||
final String targetId;
|
||||
final VoidCallback onPressed;
|
||||
final bool isCorrect;
|
||||
final double height;
|
||||
final bool isEnabled;
|
||||
|
||||
const AudioChoiceCard({
|
||||
required this.text,
|
||||
required this.targetId,
|
||||
required this.onPressed,
|
||||
required this.isCorrect,
|
||||
this.height = 72.0,
|
||||
this.isEnabled = true,
|
||||
super.key,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GameChoiceCard(
|
||||
shouldFlip: false,
|
||||
targetId: targetId,
|
||||
onPressed: onPressed,
|
||||
isCorrect: isCorrect,
|
||||
height: height,
|
||||
isEnabled: isEnabled,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: WordAudioButton(
|
||||
text: text,
|
||||
uniqueID: "vocab_practice_choice_$text",
|
||||
langCode:
|
||||
MatrixState.pangeaController.userController.userL2!.langCode,
|
||||
),
|
||||
),
|
||||
Text(L10n.of(context).select),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
import 'package:fluffychat/pangea/analytics_practice/analytics_practice_session_model.dart';
|
||||
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/lemma_activity_generator.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/message_activity_request.dart';
|
||||
import 'package:fluffychat/pangea/practice_activities/multiple_choice_activity_model.dart';
|
||||
|
|
@ -16,7 +17,8 @@ class VocabAudioActivityGenerator {
|
|||
wordsInMessage.add(t.text.content.toLowerCase());
|
||||
}
|
||||
|
||||
// Extract up to 3 additional words as answers
|
||||
// Extract up to 3 additional words as answers, from shuffled message
|
||||
audioExample.tokens.shuffle();
|
||||
final otherWords = audioExample.tokens
|
||||
.where(
|
||||
(t) =>
|
||||
|
|
@ -50,9 +52,21 @@ class VocabAudioActivityGenerator {
|
|||
final allChoices = [...choicesList, ...answers];
|
||||
allChoices.shuffle();
|
||||
|
||||
final allTokens = audioExample?.tokens ?? req.target.tokens;
|
||||
final answerTokens = <PangeaToken>[];
|
||||
|
||||
answerTokens.add(token);
|
||||
if (audioExample != null) {
|
||||
for (final t in allTokens) {
|
||||
if (t != token && answers.contains(t.text.content.toLowerCase())) {
|
||||
answerTokens.add(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return MessageActivityResponse(
|
||||
activity: VocabAudioPracticeActivityModel(
|
||||
tokens: req.target.tokens,
|
||||
tokens: answerTokens,
|
||||
langCode: req.userL2,
|
||||
multipleChoiceContent: MultipleChoiceActivity(
|
||||
choices: allChoices.toSet(),
|
||||
|
|
|
|||
|
|
@ -358,6 +358,30 @@ class VocabAudioPracticeActivityModel
|
|||
required this.exampleMessage,
|
||||
});
|
||||
|
||||
@override
|
||||
OneConstructUse constructUse(String choiceContent) {
|
||||
final correct = multipleChoiceContent.isCorrect(choiceContent);
|
||||
final useType = correct
|
||||
? activityType.correctUse
|
||||
: activityType.incorrectUse;
|
||||
|
||||
// For audio activities, find the token that matches the clicked word
|
||||
final matchingToken = tokens.firstWhere(
|
||||
(t) => t.text.content.toLowerCase() == choiceContent.toLowerCase(),
|
||||
orElse: () => tokens.first,
|
||||
);
|
||||
|
||||
return OneConstructUse(
|
||||
useType: useType,
|
||||
constructType: ConstructTypeEnum.vocab,
|
||||
metadata: ConstructUseMetaData(roomId: null, timeStamp: DateTime.now()),
|
||||
category: matchingToken.pos,
|
||||
lemma: matchingToken.lemma.text,
|
||||
form: matchingToken.lemma.text,
|
||||
xp: useType.pointValue,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = super.toJson();
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue