import 'package:flutter/cupertino.dart'; import 'package:stacked/stacked.dart'; import 'package:stacked_services/stacked_services.dart'; import 'package:yimaru_app/models/option.dart'; import 'package:yimaru_app/services/status_checker_service.dart'; import 'package:yimaru_app/ui/common/enmus.dart'; import '../../../app/app.locator.dart'; import '../../../app/app.router.dart'; import '../../../models/question.dart'; import '../../../services/api_service.dart'; import '../../common/app_colors.dart'; import '../../common/ui_helpers.dart'; class AssessmentViewModel extends BaseViewModel { // Dependency injection final _apiService = locator(); final _dialogService = locator(); final _statusChecker = locator(); final _navigationService = locator(); // In-app navigation int _currentPage = 0; int get currentPage => _currentPage; int _previousPage = 0; int get previousPage => _previousPage; final PageController _pageController = PageController(); PageController get pageController => _pageController; // Assessment int _currentQuestion = 0; int get currentQuestion => _currentQuestion; List _assessments = []; List get assessments => _assessments; ProficiencyLevels _proficiencyLevel = ProficiencyLevels.none; ProficiencyLevels get proficiencyLevel => _proficiencyLevel; final Map _selectedAnswers = {}; Map get selectedAnswers => _selectedAnswers; // User data final Map _userData = {}; Map get userData => _userData; // Assessment Map evaluateAssessment() { if (_currentQuestion == 5) { // A1 final correctCount = countCorrectAnswersUntil(5); if (correctCount > 3) { return {'continue': true, 'level': ProficiencyLevels.a1}; } else { return {'continue': false, 'level': ProficiencyLevels.a1}; } } else if (_currentQuestion == 10) { // A2 final correctCount = countCorrectAnswersUntil(10); if (correctCount > 3) { return {'continue': true, 'level': ProficiencyLevels.a2}; } else { return {'continue': false, 'level': ProficiencyLevels.a2}; } } else if (_currentQuestion == 16) { // B1 final correctCount = countCorrectAnswersUntil(16); if (correctCount > 4) { return {'continue': true, 'level': ProficiencyLevels.b1}; } else { return {'continue': false, 'level': ProficiencyLevels.b1}; } } else if (_currentQuestion == 22) { final correctCount = countCorrectAnswersUntil(16); if (correctCount > 4) { return {'continue': false, 'level': ProficiencyLevels.b2}; } else { return {'continue': false, 'level': ProficiencyLevels.b2}; } } else { return {'continue': true, 'level': ProficiencyLevels.none}; } } int countCorrectAnswersUntil(int untilQuestion) { int count = 0; for (int i = 1; i <= untilQuestion; i++) { final answer = _selectedAnswers[i.toString()]; if (answer is Map && answer['correct'] == true) { count++; } } return count; } bool isSelectedAnswer({required int question, required String answer}) { return _selectedAnswers[question.toString()]?['option'] == answer; } void setSelectedAnswer({required int question, required Option? option}) { bool correct = false; if (option?.isCorrect ?? false) { correct = true; } final data = { question.toString(): { 'correct': correct, 'option': option?.optionText, 'answer': _assessments[question - 1] .options ?.firstWhere((e) => e.isCorrect ?? false) .optionText } }; _selectedAnswers.addAll(data); rebuildUi(); } // User data void clearUserData() { _userData.clear(); } void addUserData(Map data) { _userData.addAll(data); } void initUserData(Map data) { clearUserData(); _userData.addAll(data); } // Question navigation void nextQuestion() { _currentQuestion++; Map response = evaluateAssessment(); if (_currentQuestion == _assessments.length) { _proficiencyLevel = response['level']; next(); } else { if (response['level'] == ProficiencyLevels.none) { _pageController.jumpToPage(_currentQuestion); } else { if (response['continue']) { _pageController.jumpToPage(_currentQuestion); } else { _proficiencyLevel = response['level']; next(); } } } rebuildUi(); } void previousQuestion() { if (_currentQuestion != 0) { _currentQuestion--; _pageController.previousPage( duration: const Duration(microseconds: 100), curve: Curves.linear); rebuildUi(); } } // In-app navigation void goBack() { if (_currentPage == 0) { _navigationService.back(); } else if (_currentPage == 2) { _currentPage = 0; rebuildUi(); } else if (_currentPage == 3) { if (_proficiencyLevel != ProficiencyLevels.none) { _currentPage--; } else { _currentPage = 0; } rebuildUi(); } } void next({int? page}) async { if (page == null) { if (_previousPage != 0) { _currentPage = _previousPage; } else { _currentPage++; } } else { _previousPage = _currentPage; _currentPage = page; } rebuildUi(); } // Dialog Future abort() async { bool? response = await showAbortDialog(); if (response != null && response) { next(page: 3); } } Future showAbortDialog() async { DialogResponse? response = await _dialogService.showDialog( cancelTitle: 'No', buttonTitle: 'Yes', barrierDismissible: true, title: 'Abort Assessment', cancelTitleColor: kcDarkGrey, buttonTitleColor: kcPrimaryColor, description: 'Are you sure to abort the assessment ?', ); return response?.confirmed; } // Navigation void pop() => _navigationService.back(); Future replaceWithHome() async => await _navigationService.clearStackAndShow(Routes.homeView); Future navigateToLanguage() async => await _navigationService.navigateToLanguageView(); // Remote api call // Complete profile Future completeProfile() async => await runBusyFuture(_completeProfile(), busyObject: StateObjects.profileCompletion); Future _completeProfile() async { if (await _statusChecker.checkConnection()) { Map response = await _apiService.completeProfile(_userData); if (response['status'] == ResponseStatus.success) { clearUserData(); await replaceWithHome(); showSuccessToast(response['message']); } else { showErrorToast(response['message']); } } } // Assessments Future _getAssessments() async { if (await _statusChecker.checkConnection()) { _assessments = await _apiService.getAssessments(); } } Future getAssessments() async => await runBusyFuture(_getAssessments()); }