From 5e3061165fbfaa934a2d853a8c90d5519593ff00 Mon Sep 17 00:00:00 2001 From: Dmitry Date: Sat, 20 Dec 2025 19:27:45 +0300 Subject: [PATCH] admin --- .../input_buttons_question_generator.dart | 20 +++++++++++++- .../simple_question_generator.dart | 27 ++++++++++++++++--- .../lib/tests/test_manager.dart | 20 +++++++++++--- .../lib/domain/state/tests_state_manager.dart | 2 +- .../widgets/game/answer_options.dart | 2 +- 5 files changed, 62 insertions(+), 9 deletions(-) diff --git a/mnemo_cards_backend/lib/tests/generators/question_generators/input_buttons_question_generator.dart b/mnemo_cards_backend/lib/tests/generators/question_generators/input_buttons_question_generator.dart index b9da03b..ea5b1c4 100644 --- a/mnemo_cards_backend/lib/tests/generators/question_generators/input_buttons_question_generator.dart +++ b/mnemo_cards_backend/lib/tests/generators/question_generators/input_buttons_question_generator.dart @@ -12,6 +12,12 @@ class InputButtonsQuestionGenerator implements QuestionGenerator { final Random random; final Set? possibleTypes; + // UUID regex pattern (same as in test_manager.dart) + static final _uuidRegex = RegExp( + r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', + caseSensitive: false, + ); + InputButtonsQuestionGenerator( this.data, { this.seed, @@ -36,6 +42,17 @@ class InputButtonsQuestionGenerator implements QuestionGenerator { return types[random.nextInt(types.length)]; } + /// Checks if a string is a valid UUID + bool _isUuid(String value) => _uuidRegex.hasMatch(value.trim()); + + /// Gets audio UUID from answerItem.audio if it's a valid UUID, otherwise returns null + /// This allows using UUID from MinIO instead of text-based audio identifiers + String? _getAudioUuid(TestDataItem answerItem) { + final audioValue = answerItem.audio; + if (audioValue == null || audioValue.trim().isEmpty) return null; + return _isUuid(audioValue) ? audioValue.trim() : null; + } + Future inputButtonsTestQuestion( TestDataItem answerItem, { InputButtonsQuestionType? type, @@ -58,7 +75,8 @@ class InputButtonsQuestionGenerator implements QuestionGenerator { String? questionAudio = null; if (questionType.audioQuestion) { - questionAudio = 'es-ES_${answerItem.audio}'; + // Use UUID from MinIO if available, otherwise null + questionAudio = _getAudioUuid(answerItem); } else if (withAudio) { // nothing to fo here } diff --git a/mnemo_cards_backend/lib/tests/generators/question_generators/simple_question_generator.dart b/mnemo_cards_backend/lib/tests/generators/question_generators/simple_question_generator.dart index aeae051..2bc96c8 100644 --- a/mnemo_cards_backend/lib/tests/generators/question_generators/simple_question_generator.dart +++ b/mnemo_cards_backend/lib/tests/generators/question_generators/simple_question_generator.dart @@ -11,6 +11,12 @@ class SimpleQuestionGenerator implements QuestionGenerator { final Random random; final Set? possibleTypes; + // UUID regex pattern (same as in test_manager.dart) + static final _uuidRegex = RegExp( + r'^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$', + caseSensitive: false, + ); + SimpleQuestionGenerator( this.data, { this.seed, @@ -36,6 +42,17 @@ class SimpleQuestionGenerator implements QuestionGenerator { return types[random.nextInt(types.length)]; } + /// Checks if a string is a valid UUID + bool _isUuid(String value) => _uuidRegex.hasMatch(value.trim()); + + /// Gets audio UUID from answerCard.audio if it's a valid UUID, otherwise returns null + /// This allows using UUID from MinIO instead of text-based audio identifiers + String? _getAudioUuid(TestDataItem answerCard) { + final audioValue = answerCard.audio; + if (audioValue == null || audioValue.trim().isEmpty) return null; + return _isUuid(audioValue) ? audioValue.trim() : null; + } + Future simpleTestQuestion( TestDataItem answerCard, { SimpleQuestionType? type, @@ -57,14 +74,18 @@ class SimpleQuestionGenerator implements QuestionGenerator { String? questionAudio = null; if (questionType.audioQuestion) { if (questionType.translationAnswers || questionType.imagesAnswers) { - questionAudio = 'es-ES_${answerCard.audio}'; + // Use UUID from MinIO if available, otherwise null + questionAudio = _getAudioUuid(answerCard); } } else if (withAudio) { if (questionText != null && questionType.originalQuestion) { - questionAudio = 'es-ES_$questionText'; + // For original questions with text, audio is handled separately + // Use UUID if available, otherwise null + questionAudio = _getAudioUuid(answerCard); } else if (questionType.translationAnswers || questionType.imagesAnswers) { - questionAudio = 'es-ES_${answerCard.audio}'; + // Use UUID from MinIO if available, otherwise null + questionAudio = _getAudioUuid(answerCard); } } final answers = [answerCard, ...otherCards]..shuffle(); diff --git a/mnemo_cards_backend/lib/tests/test_manager.dart b/mnemo_cards_backend/lib/tests/test_manager.dart index 9d6c1e5..16524a5 100644 --- a/mnemo_cards_backend/lib/tests/test_manager.dart +++ b/mnemo_cards_backend/lib/tests/test_manager.dart @@ -677,15 +677,29 @@ class TestManager { } // Create creation test data - final testDataItems = cards.map((card) { + // Get voices for all cards to use UUID from MinIO instead of text + final testDataItems = await Future.wait(cards.map((card) async { + // Get voices for this card + final voices = await _db.packDao.getCardVoices(card.id.toString()); + + // Use first voice's voiceUrl if it's a valid UUID, otherwise null + String? audioUuid; + if (voices.isNotEmpty) { + final voiceUrl = voices.first.voiceUrl.trim(); + // Check if voiceUrl is a valid UUID (object ID in MinIO) + if (_isUuid(voiceUrl)) { + audioUuid = voiceUrl; + } + } + return TestDataItem( id: card.id.toString(), original: card.original, translation: card.translation, image: card.image, - audio: card.original, // Use original as audio + audio: audioUuid, // Use UUID from MinIO if available ); - }).toList(); + })); final creationTestData = CreationTestData( items: testDataItems, diff --git a/mnemo_cards_web_v2/lib/domain/state/tests_state_manager.dart b/mnemo_cards_web_v2/lib/domain/state/tests_state_manager.dart index 5d8822f..55a6229 100644 --- a/mnemo_cards_web_v2/lib/domain/state/tests_state_manager.dart +++ b/mnemo_cards_web_v2/lib/domain/state/tests_state_manager.dart @@ -434,7 +434,7 @@ class TestsStateManager extends StateManager { questions.add(GameQuestion.multipleChoice( MultipleChoiceQuestion( id: 'q_${questions.length}', - question: question.text ?? '', + question: question.w ?? '', image: question.imageUrl ?? question.image, // Use presigned URL if available audio: question.audio, options: options, // Keep for backward compatibility diff --git a/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart b/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart index a90d25b..654ae0f 100644 --- a/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart +++ b/mnemo_cards_web_v2/lib/presentation/widgets/game/answer_options.dart @@ -44,7 +44,7 @@ class AnswerOptions extends StatelessWidget { // Adjust aspect ratio for image buttons (they need more space) final hasImages = hasOptionItems && question.optionItems.any((item) => item.image != null); - final childAspectRatio = hasImages ? 2.5 : 4.0; + final childAspectRatio = hasImages ? 1.1 : 4.0; return GridView.builder( shrinkWrap: true,