You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
mohemm-flutter-app/lib/ui/marathon/marathon_provider.dart

609 lines
20 KiB
Dart

import 'dart:async';
import 'dart:developer';
import 'package:appinio_swiper/appinio_swiper.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:mohem_flutter_app/api/marathon/demo_marathon_repo.dart';
import 'package:mohem_flutter_app/api/marathon/marathon_api_client.dart';
import 'package:mohem_flutter_app/app_state/app_state.dart';
import 'package:mohem_flutter_app/classes/consts.dart';
import 'package:mohem_flutter_app/classes/utils.dart';
import 'package:mohem_flutter_app/config/routes.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_generic_model.dart';
import 'package:mohem_flutter_app/models/marathon/marathon_model.dart';
import 'package:mohem_flutter_app/models/marathon/question_model.dart';
import 'package:mohem_flutter_app/models/marathon/winner_model.dart';
import 'package:mohem_flutter_app/models/privilege_list_model.dart';
import 'package:mohem_flutter_app/ui/marathon/widgets/question_card.dart';
import 'package:video_player/video_player.dart';
class MarathonProvider extends ChangeNotifier {
//************************************************ VARIABLES **********************************************************
final AppinioSwiperController swiperController = AppinioSwiperController();
MarathonDetailModel marathonDetailModel = MarathonDetailModel();
MarathonDetailModel demoMarathonDetailModel = MarathonDetailModel();
List<CardContent> cardContentList = <CardContent>[];
QuestionModel currentQuestion = QuestionModel();
List<QuestionCardStatus> answerStatusesList = <QuestionCardStatus>[];
QuestionCardStatus questionCardStatus = QuestionCardStatus.question;
List<WinnerModel>? selectedWinners;
int? selectedOptionIndex;
String? selectedOptionId;
int? totalQualifiers;
Locale savedLocale = const Locale("en", "US");
String? gapTimeImage;
String? gapTimeText;
int? gapTimeType;
bool iAmWinner = false;
bool isGettingQualifiers = false;
bool isPrivilegedWithMarathon = false;
bool _isLoading = false;
bool get isLoading => _isLoading;
set isLoading(bool value) {
_isLoading = value;
notifyListeners();
}
bool _isUpComingMarathon = true;
bool get isUpComingMarathon => _isUpComingMarathon;
set isUpComingMarathon(bool value) {
_isUpComingMarathon = value;
notifyListeners();
}
bool _itsMarathonTime = false;
bool get itsMarathonTime => _itsMarathonTime;
set itsMarathonTime(bool value) {
_itsMarathonTime = value;
notifyListeners();
}
bool _canPlayDemo = true;
bool get canPlayDemo => _canPlayDemo;
set canPlayDemo(bool value) {
_canPlayDemo = value;
notifyListeners();
}
bool _isButtonEnabled = false;
bool get isButtonEnabled => _isButtonEnabled;
set isButtonEnabled(bool value) {
_isButtonEnabled = value;
notifyListeners();
}
bool _isUserWaiting = false;
bool get isUserWaiting => _isUserWaiting;
set isUserWaiting(bool value) {
_isUserWaiting = value;
notifyListeners();
}
bool _isMarathonCompleted = false;
bool get isMarathonCompleted => _isMarathonCompleted;
set isMarathonCompleted(bool value) {
_isMarathonCompleted = value;
notifyListeners();
}
bool isUserOutOfGame = false;
set updateIsUserOutOfGame(bool value) {
isUserOutOfGame = value;
notifyListeners();
}
int _currentQuestionNumber = 0;
int get currentQuestionNumber => _currentQuestionNumber;
set currentQuestionNumber(int value) {
_currentQuestionNumber = value;
notifyListeners();
}
int _totalMarathoners = 0;
int get totalMarathoners => _totalMarathoners;
set totalMarathoners(int value) {
_totalMarathoners = value;
notifyListeners();
}
//****************SPONSOR VIDEO PLAYER**********
late VideoPlayerController videoController;
Future<void> initializeVideoPlayer() async {
videoController = VideoPlayerController.network(ApiConsts.marathonBaseUrlServices + marathonDetailModel.sponsors!.first.video!);
await videoController.initialize();
await videoController.play();
await videoController.setVolume(1.0);
await videoController.setLooping(false);
totalSponsorVideoSeconds = videoController.value.duration.inSeconds;
notifyListeners();
}
void disposeVideoPlayer() {
videoController.dispose();
notifyListeners();
}
// 9c47d281-c5b5-4b5d-a90a-08dacb8cbdb6
// MarathonI
//************************************************ TIMERS **********************************************************
int sponsorsSecondsCounter = 0;
int totalSponsorVideoSeconds = 0;
Timer timerForSponsorVideo = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});
void startTimerForSponsorVideo() {
const Duration oneSec = Duration(seconds: 1);
timerForSponsorVideo = Timer.periodic(
oneSec,
(Timer timer) async {
sponsorsSecondsCounter++;
if (totalSponsorVideoSeconds == 0) {
timer.cancel();
notifyListeners();
return;
} else {
totalSponsorVideoSeconds--;
}
notifyListeners();
},
);
}
int totalSecondsToWaitForMarathon = 30;
set updateTotalSecondsToWaitForMarathon(int value) {
totalSecondsToWaitForMarathon = value;
notifyListeners();
}
Timer timerToWaitForMarathon = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});
void startTimerToWaitForMarathon() {
const Duration oneSec = Duration(seconds: 1);
timerToWaitForMarathon = Timer.periodic(
oneSec,
(Timer timer) async {
if (totalSecondsToWaitForMarathon == 0) {
timer.cancel();
if (isUserWaiting) {
await callNextQuestionApi();
} else {
isButtonEnabled = false;
}
return;
} else {
totalSecondsToWaitForMarathon--;
}
notifyListeners();
},
);
}
int totalCurrentQuestionTime = 0;
int currentGapTime = 0;
Timer timerForQuestion = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});
int callCountThreshold = 0;
void startTimerForQuestion() {
const Duration oneSec = Duration(seconds: 1);
timerForQuestion = Timer.periodic(
oneSec,
(Timer timer) async {
// This 1 is just to show the color of answer tile for 1 and then update card status
if (totalCurrentQuestionTime - currentGapTime == 0) {
if (callCountThreshold == 0) {
getCorrectAnswerAndUpdateAnswerColor();
}
}
if (totalCurrentQuestionTime - currentGapTime == -2) {
if (callCountThreshold == 0) {
updateCardStatusToAnswer();
}
// scheduleMicrotask(() async {
// if (AppState().getIsDemoMarathon || isUserOutOfGame) {
// await callNextQuestionApi();
// } else {
// await callSubmitOptionApi().then((bool value) async {
// updateIsUserOutOfGame = !value;
// await callNextQuestionApi();
// });
// }
// });
if (currentQuestionNumber == (AppState().getIsDemoMarathon ? demoMarathonDetailModel.totalQuestions! : marathonDetailModel.totalQuestions!)) {
isGettingQualifiers = true;
updateQuestionCardStatus(QuestionCardStatus.findingWinner);
timer.cancel();
cancelTimer();
notifyListeners();
}
totalCurrentQuestionTime--;
callCountThreshold = 0;
}
if (totalCurrentQuestionTime == 0) {
gapTimeImage = currentQuestion.gapImage;
gapTimeText = currentQuestion.gapText;
gapTimeType = currentQuestion.gapType;
updateCardData();
return;
} else {
if (totalCurrentQuestionTime - currentGapTime != -2) {
totalCurrentQuestionTime--;
callCountThreshold = 0;
}
}
notifyListeners();
},
);
}
int totalSecondsToWaitForWinner = 30;
Timer timerForWinnerSelection = Timer.periodic(const Duration(seconds: 1), (Timer timer) {});
void startTimerForWinnerSelection() {
const Duration oneSec = Duration(seconds: 1);
timerForWinnerSelection = Timer.periodic(
oneSec,
(Timer timer) async {
if (totalSecondsToWaitForWinner == 1) {
timer.cancel();
await callGetSelectedWinnersApi().whenComplete(() => updateQuestionCardStatus(QuestionCardStatus.winnerFound));
return;
} else if (totalSecondsToWaitForWinner == 15) {
totalSecondsToWaitForWinner--;
await callGetQualifiersApi();
} else {
totalSecondsToWaitForWinner--;
}
notifyListeners();
},
);
}
//************************************************ FUNCTIONS **********************************************************
void updateLanguageAsPerMarathon(BuildContext context, MarathonDetailModel detailModel) {
savedLocale = context.locale;
if (detailModel.selectedLanguage == 1) {
context.setLocale(const Locale("en", "US"));
} else if (detailModel.selectedLanguage == 2) {
context.setLocale(const Locale("ar", "SA"));
} else if (detailModel.selectedLanguage == 3) {
} else {
context.setLocale(const Locale("en", "US"));
}
}
Future<bool> callSubmitOptionApi() async {
return await MarathonApiClient().submitSelectedOption(marathonId: marathonDetailModel.id!, questionId: currentQuestion.id, selectedAnswerId: selectedOptionId);
}
Future<void> callGetQualifiersApi() async {
if (AppState().getIsDemoMarathon) {
totalQualifiers = isUserOutOfGame ? 0 : 1;
} else {
totalQualifiers = await MarathonApiClient().getQualifiers(marathonId: marathonDetailModel.id!);
}
isGettingQualifiers = false;
notifyListeners();
}
Future<void> callGetSelectedWinnersApi() async {
if (AppState().getIsDemoMarathon) {
return;
}
selectedWinners = await MarathonApiClient().getSelectedWinner(marathonId: marathonDetailModel.id!);
if (selectedWinners != null) {
selectedWinners!.removeWhere((WinnerModel element) {
if (element.employeeId == AppState().memberInformationList!.eMPLOYEENUMBER) {
iAmWinner = true;
return true;
} else {
return false;
}
});
}
notifyListeners();
}
Future<void> callNextQuestionApi() async {
if (currentQuestionNumber < (AppState().getIsDemoMarathon ? demoMarathonDetailModel.totalQuestions! : marathonDetailModel.totalQuestions!)) {
if (currentQuestionNumber == 0) {
if (!AppState().getIsDemoMarathon) {
Utils.showLoading(AppRoutes.navigatorKey.currentContext!);
}
currentQuestion = AppState().getIsDemoMarathon
? await DemoMarathonRepo().getDemoNextQuestion(currentQuestionNumber: currentQuestionNumber)
: (await MarathonApiClient().getNextQuestion(questionId: null, marathonId: marathonDetailModel.id!));
gapTimeImage = currentQuestion.gapImage;
gapTimeText = currentQuestion.gapText;
gapTimeType = currentQuestion.gapType;
startTimerForQuestion();
updateCardData();
if (Utils.isLoading) {
Utils.hideLoading(AppRoutes.navigatorKey.currentContext!);
}
if (!AppState().getIsDemoMarathon) {
totalMarathoners = await MarathonApiClient().getMarathonersCount(marathonId: marathonDetailModel.id!);
}
Navigator.pushReplacementNamed(AppRoutes.navigatorKey.currentContext!, AppRoutes.marathonScreen);
} else {
currentQuestion = AppState().getIsDemoMarathon
? await DemoMarathonRepo().getDemoNextQuestion(currentQuestionNumber: currentQuestionNumber)
: (await MarathonApiClient().getNextQuestion(questionId: currentQuestion.id, marathonId: marathonDetailModel.id!));
}
notifyListeners();
}
}
void updateCardData() {
if (currentQuestionNumber > 0) {
// swiperController.swipeLeft();
}
selectedOptionIndex = null;
currentQuestionNumber++;
cardContentList.add(const CardContent());
totalCurrentQuestionTime = currentQuestion.questionTime! + currentQuestion.nextQuestGap!;
currentGapTime = currentQuestion.nextQuestGap!;
totalMarathoners = currentQuestion.remainingParticipantCount!;
questionCardStatus = QuestionCardStatus.question;
notifyListeners();
}
void populateQuestionStatusesList() {
answerStatusesList.clear();
if (demoMarathonDetailModel.totalQuestions != null) {
for (int i = 0; i < demoMarathonDetailModel.totalQuestions!; i++) {
answerStatusesList.add(QuestionCardStatus.question);
}
notifyListeners();
}
if (isUpComingMarathon) {
if (marathonDetailModel.totalQuestions != null) {
for (int i = 0; i < marathonDetailModel.totalQuestions!; i++) {
answerStatusesList.add(QuestionCardStatus.question);
}
notifyListeners();
}
}
}
void updateAnswerStatusesList(QuestionCardStatus status) {
answerStatusesList[currentQuestionNumber - 1] = status;
notifyListeners();
}
void addItemToList(CardContent value) {
cardContentList.add(value);
notifyListeners();
}
void updateCurrentQuestionOptionStatus({required QuestionsOptionStatus status, required int selectedOptIndex, required int correctOptionIndex}) {
for (int i = 0; i < currentQuestion.questionOptions!.length; i++) {
currentQuestion.questionOptions![i].optionStatus = QuestionsOptionStatus.unSelected;
}
if (status == QuestionsOptionStatus.wrong) {
currentQuestion.questionOptions![correctOptionIndex].optionStatus = QuestionsOptionStatus.correct; // if person's answer is wrong we have to show him the actual right answer
}
currentQuestion.questionOptions![selectedOptIndex].optionStatus = status;
selectedOptionId = currentQuestion.questionOptions![selectedOptIndex].id;
selectedOptionIndex = selectedOptIndex;
notifyListeners();
}
void updateQuestionCardStatus(QuestionCardStatus status) {
if (status == QuestionCardStatus.wrongAnswer || status == QuestionCardStatus.skippedAnswer) {
if (AppState().getIsDemoMarathon) {
updateIsUserOutOfGame = true;
}
}
questionCardStatus = status;
notifyListeners();
}
void getCorrectAnswerAndUpdateAnswerColor() {
log("correctOptionIndex");
callCountThreshold = 1;
int correctOptionIndex = -1;
if (demoMarathonDetailModel.displayCorrectAnswer ?? false) {
correctOptionIndex = currentQuestion.questionOptions!.indexWhere((QuestionOptions element) => element.isCorrectOption ?? false);
log("correctOptionIndex: $correctOptionIndex");
}
if (selectedOptionIndex != null) {
scheduleMicrotask(() async {
if (AppState().getIsDemoMarathon) {
if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.correct, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
} else {
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.wrong, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
}
} else {
await callSubmitOptionApi().then((bool value) async {
updateIsUserOutOfGame = !value;
if (value) {
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.correct, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
} else {
updateCurrentQuestionOptionStatus(status: QuestionsOptionStatus.wrong, selectedOptIndex: selectedOptionIndex!, correctOptionIndex: correctOptionIndex);
}
});
}
});
} else {
if (!AppState().getIsDemoMarathon) {
scheduleMicrotask(() async {
await callSubmitOptionApi().then((bool value) async {
updateIsUserOutOfGame = !value;
});
});
}
}
}
void updateCardStatusToAnswer() {
if (currentQuestionNumber == 0) {
return;
}
callCountThreshold = 1;
scheduleMicrotask(() async {
await callNextQuestionApi();
});
if (selectedOptionIndex == null) {
updateQuestionCardStatus(QuestionCardStatus.skippedAnswer);
updateAnswerStatusesList(QuestionCardStatus.skippedAnswer);
return;
}
if (AppState().getIsDemoMarathon) {
if (currentQuestion.questionOptions![selectedOptionIndex!].isCorrectOption!) {
updateQuestionCardStatus(QuestionCardStatus.correctAnswer);
updateAnswerStatusesList(QuestionCardStatus.correctAnswer);
} else {
updateQuestionCardStatus(QuestionCardStatus.wrongAnswer);
updateAnswerStatusesList(QuestionCardStatus.wrongAnswer);
}
return;
}
if (!isUserOutOfGame) {
updateQuestionCardStatus(QuestionCardStatus.correctAnswer);
updateAnswerStatusesList(QuestionCardStatus.correctAnswer);
return;
}
updateQuestionCardStatus(QuestionCardStatus.wrongAnswer);
updateAnswerStatusesList(QuestionCardStatus.wrongAnswer);
}
void resetValues() async {
_currentQuestionNumber = 0;
iAmWinner = false;
cardContentList.clear();
itsMarathonTime = false;
timerForWinnerSelection.cancel();
timerForSponsorVideo.cancel();
timerToWaitForMarathon.cancel();
timerForQuestion.cancel();
_isMarathonCompleted = false;
isUserOutOfGame = false;
isButtonEnabled = false;
isUserWaiting = false;
canPlayDemo = true;
totalCurrentQuestionTime = 0;
sponsorsSecondsCounter = 0;
totalSponsorVideoSeconds = 0;
totalSecondsToWaitForWinner = 30;
totalSecondsToWaitForMarathon = 30;
AppState().setIsDemoMarathon = false;
currentGapTime = 0;
currentQuestion = QuestionModel();
if (answerStatusesList.isNotEmpty) {
for (int i = 0; i < answerStatusesList.length; i++) {
answerStatusesList[i] = QuestionCardStatus.question;
}
}
AppRoutes.navigatorKey.currentContext!.setLocale(savedLocale);
notifyListeners();
}
void cancelTimer() {
timerForQuestion.cancel();
notifyListeners();
}
bool checkIfPrivilegedForMarathon() {
for (PrivilegeListModel element in AppState().privilegeListModel!) {
if (element.serviceName == "Marathon") {
if (element.previlege != null) {
return element.previlege!;
}
}
}
return false;
}
Future<void> getMarathonDetailsFromApi() async {
isLoading = true;
notifyListeners();
isPrivilegedWithMarathon = checkIfPrivilegedForMarathon();
demoMarathonDetailModel = await DemoMarathonRepo().getDemoMarathonDetails();
if (isPrivilegedWithMarathon) {
marathonDetailModel = await MarathonApiClient().getMarathonDetails();
updateTotalSecondsToWaitForMarathon = marathonDetailModel.marathonBufferTime ?? 30;
if (marathonDetailModel.id == null) {
isUpComingMarathon = false;
isLoading = false;
populateQuestionStatusesList();
notifyListeners();
return;
}
isUpComingMarathon = true;
if (DateTime.parse(marathonDetailModel.startTime!).isAfter(DateTime.now())) {
itsMarathonTime = false;
}
populateQuestionStatusesList();
}
isLoading = false;
notifyListeners();
}
Future<void> onJoinMarathonPressed(BuildContext context) async {
try {
Utils.showLoading(AppRoutes.navigatorKey.currentContext!);
MarathonApiClient().joinMarathonAsParticipant().then((MarathonGenericModel? marathonGenericModel) async {
Utils.hideLoading(AppRoutes.navigatorKey.currentContext!);
if (marathonGenericModel != null && marathonGenericModel.data != null) {
isUserWaiting = true;
Navigator.pushReplacementNamed(context, AppRoutes.marathonWaitingScreen);
} else if (marathonGenericModel!.data == null) {
Utils.showToast(marathonGenericModel.message.toString());
}
});
} catch (e) {
Utils.hideLoading(AppRoutes.navigatorKey.currentContext!);
Utils.confirmDialog(context, e.toString());
}
}
Future<void> onJoinDemoMarathonPressed(BuildContext context) async {
AppState().setIsDemoMarathon = true;
await callNextQuestionApi();
}
}