import 'dart:async'; import 'dart:developer'; import 'package:flutter/widgets.dart'; import 'package:mnemo_cards/features/tests/test_state_holder.dart'; import 'package:mnemo_cards/features/tests/test_widgets/test_image.dart'; import 'package:mnemo_cards/features/packs/pack_cache_manager.dart'; import 'package:mnemo_cards/main.dart'; import 'package:mnemo_cards/theme/themes.dart'; import 'package:mnemo_cards/utils/iterable_helper.dart'; import 'package:mnemo_cards/utils/string_helper.dart'; import 'package:mnemo_cards_common/mnemo_cards_common.dart'; import 'package:rxdart/rxdart.dart'; import '../../managers/repository/http_repository.dart'; import 'question_states/test_question_state.dart'; class TestManager extends ChangeNotifier { final PackCacheManager packCacheManager; final HttpRepository _repository; final List questions = []; Color color = borderGray; final PageController pageController = PageController(); final TestHolder testHolder = TestHolder(); Future> loadTests({String? packId}) async { final tests = (await _repository.getTests(packId: packId ?? '')) .map((e) => TestDto.fromJson(e)) .toList(); return tests; } void skip(int id) { testHolder.skip(id); notifyListeners(); } Stream> loadTestsStream({String? packId}) { return Stream.periodic( Duration(seconds: 60), ) .startWith(null) .asyncMap( (tests) async => loadTests(packId: packId) .catchError((_) => Future.value([])), ) .where((test) => test.isNotEmpty); } TestQuestionState? getState(int id) => testHolder.testQuestionState(id); Iterable get states => testHolder.state.questions.values; Future setActiveTest(String id, {String? packId}) async { clearStates(); if (packId != null) { await packCacheManager.loadPackFromCache(packId); } TestDto? test; try { test = await _repository.getTest(id); } on Object catch (e, s) { log('error when loading test ${id}'); } if (test == null) { appRouter.maybePop(); } questions.clear(); questions.addAll(test!.questions); color = test.color?.asColor ?? borderGray; testHolder.setQuestions(questions); } void setState(int id, TestQuestionState state) { testHolder.setQuestionState(id, state); log('Set state $id $state'); notifyListeners(); } TestManager( this.packCacheManager, this._repository, ); void clearStates() { testHolder.clear(); notifyListeners(); } AbstractTestQuestion getTest(int index) => questions[index]; void nextTest() { pageController.animateToPage( pageController.page!.toInt() + 1, duration: Duration(milliseconds: 300), curve: Curves.ease, ); } void prevTest() { pageController.animateToPage( pageController.page!.toInt() - 1, duration: Duration(milliseconds: 300), curve: Curves.ease, ); } Future preloadImages(BuildContext context) async { for (final question in questions) { switch (question.questionType) { case TestQuestionType.simple: final images = [ (question as SimpleTestQuestionBody).image, ...question.buttons.map((e) => e.image) ].whereNotNull(); for (final image in images) { try { final testImage = TestImage.image(image); await precacheImage( (await testImage.loadImage())!, context, ); } catch (e) { rethrow; } } case TestQuestionType.input_buttons: final images = [ (question as InputButtonsTestQuestionBody).image, ].whereNotNull(); for (final image in images) { try { final testImage = TestImage.image(image); await precacheImage( (await testImage.loadImage())!, context, ); } catch (e) { rethrow; } } case TestQuestionType.matrix: // TODO: Handle this case. case TestQuestionType.match: // TODO: Handle this case. case TestQuestionType.undefined: // TODO: Handle this case. } } } Future loadImage(String packId, String path) async { final bytes = await packCacheManager.loadPackFile(packId, path); return MemoryImage(bytes!); } }