import ' dart:async ' ;
import ' package:appinio_swiper/appinio_swiper.dart ' ;
import ' package:flutter/cupertino.dart ' ;
import ' package:flutter/foundation.dart ' ;
import ' package:flutter/material.dart ' ;
import ' package:mohem_flutter_app/api/marathon/marathon_api_client.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_model.dart ' ;
import ' package:mohem_flutter_app/models/marathon/question_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 ( ) ;
List < CardContent > cardContentList = < CardContent > [ ] ;
QuestionModel currentQuestion = QuestionModel ( ) ;
List < QuestionCardStatus > answerStatusesList = < QuestionCardStatus > [ ] ;
QuestionCardStatus questionCardStatus = QuestionCardStatus . question ;
int ? selectedOptionIndex ;
int currentQuestionTime = 0 ;
int totalSecondsToWaitForWinner = 30 ;
int totalSecondsToWaitForMarathon = 20 ;
int totalQualifiers = 0 ;
bool _isLoading = false ;
bool get isLoading = > _isLoading ;
set isLoading ( bool value ) {
_isLoading = value ;
notifyListeners ( ) ;
}
bool _itsMarathonTime = false ;
bool get itsMarathonTime = > _itsMarathonTime ;
set itsMarathonTime ( bool value ) {
_itsMarathonTime = 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 = 23 ;
int get totalMarathoners = > _totalMarathoners ;
set totalMarathoners ( int value ) {
_totalMarathoners = value ;
notifyListeners ( ) ;
}
//VIDEO PLAYER
late VideoPlayerController videoController ;
Future < void > initializeVideoPlayer ( ) async {
// videoController = VideoPlayerController.network(marathonDetailModel.sponsors!.first.video!)..initialize();
videoController = VideoPlayerController . network ( " http://clips.vorwaerts-gmbh.de/VfE_html5.mp4 " ) ;
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 ( ) ;
}
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 {
if ( totalSponsorVideoSeconds = = 0 ) {
timer . cancel ( ) ;
notifyListeners ( ) ;
return ;
} else {
totalSponsorVideoSeconds - - ;
}
notifyListeners ( ) ;
} ,
) ;
}
// FUNCTIONS
Timer timerToWaitForMarathon = Timer . periodic ( const Duration ( seconds: 1 ) , ( Timer timer ) { } ) ;
void startTimerToMarathon ( BuildContext context ) {
const Duration oneSec = Duration ( seconds: 1 ) ;
timerToWaitForMarathon = Timer . periodic (
oneSec ,
( Timer timer ) async {
if ( totalSecondsToWaitForMarathon = = 0 ) {
} else {
totalSecondsToWaitForMarathon - - ;
}
notifyListeners ( ) ;
} ,
) ;
}
void populateQuestionStatusesList ( ) {
if ( marathonDetailModel . totalQuestions ! = null ) {
for ( int i = 0 ; i < marathonDetailModel . totalQuestions ! - 1 ; i + + ) {
answerStatusesList . add ( QuestionCardStatus . question ) ;
}
notifyListeners ( ) ;
}
}
void updateAnswerStatusesList ( QuestionCardStatus status ) {
answerStatusesList [ currentQuestionNumber - 1 ] = status ;
notifyListeners ( ) ;
}
Future < void > callForNewQuestion ( QuestionModel newQuestion ) async {
if ( currentQuestionNumber < marathonDetailModel . totalQuestions ! ) {
if ( currentQuestionNumber = = 0 ) {
if ( Utils . isLoading ) {
Utils . hideLoading ( AppRoutes . navigatorKey . currentContext ! ) ;
}
startTimerForQuestion ( AppRoutes . navigatorKey . currentContext ! ) ;
Navigator . pushReplacementNamed ( AppRoutes . navigatorKey . currentContext ! , AppRoutes . marathonScreen ) ;
}
if ( currentQuestionNumber > 0 ) {
swipeCardLeft ( ) ;
}
selectedOptionIndex = null ;
currentQuestionNumber + + ;
currentQuestion = await MarathonApiClient ( ) . getNextQuestion ( selectedOptionId: null , questionId: null , marathonId: marathonDetailModel . id ! ) ;
cardContentList . add ( const CardContent ( ) ) ;
currentQuestionTime = newQuestion . questionTime ! ;
questionCardStatus = QuestionCardStatus . question ;
notifyListeners ( ) ;
}
}
void addItemToList ( CardContent value ) {
cardContentList . add ( value ) ;
notifyListeners ( ) ;
}
void updateCurrentQuestionOptionStatus ( QuestionsOptionStatus status , int index ) {
for ( int i = 0 ; i < currentQuestion . questionOptions ! . length ; i + + ) {
currentQuestion . questionOptions ! [ i ] . optionStatus = QuestionsOptionStatus . unSelected ;
}
currentQuestion . questionOptions ! [ index ] . optionStatus = status ;
selectedOptionIndex = index ;
notifyListeners ( ) ;
}
void updateQuestionCardStatus ( QuestionCardStatus status ) {
if ( status = = QuestionCardStatus . wrongAnswer | | status = = QuestionCardStatus . skippedAnswer ) {
updateIsUserOutOfGame = true ;
}
questionCardStatus = status ;
notifyListeners ( ) ;
}
void getCorrectAnswerAndUpdateAnswerColor ( ) {
if ( selectedOptionIndex ! = null ) {
if ( currentQuestion . questionOptions ! [ selectedOptionIndex ! ] . isCorrectOption ! ) {
updateCurrentQuestionOptionStatus ( QuestionsOptionStatus . correct , selectedOptionIndex ! ) ;
} else {
updateCurrentQuestionOptionStatus ( QuestionsOptionStatus . wrong , selectedOptionIndex ! ) ;
}
}
}
void updateCardStatusToAnswer ( ) {
if ( currentQuestionNumber = = 0 ) {
return ;
}
if ( selectedOptionIndex ! = null ) {
if ( currentQuestion . questionOptions ! [ selectedOptionIndex ! ] . isCorrectOption ! ) {
updateQuestionCardStatus ( QuestionCardStatus . correctAnswer ) ;
updateAnswerStatusesList ( QuestionCardStatus . correctAnswer ) ;
} else {
updateQuestionCardStatus ( QuestionCardStatus . wrongAnswer ) ;
updateAnswerStatusesList ( QuestionCardStatus . wrongAnswer ) ;
}
} else {
updateQuestionCardStatus ( QuestionCardStatus . skippedAnswer ) ;
updateAnswerStatusesList ( QuestionCardStatus . skippedAnswer ) ;
}
}
Timer timerForQuestion = Timer . periodic ( const Duration ( seconds: 1 ) , ( Timer timer ) { } ) ;
void startTimerForQuestion ( BuildContext context ) {
const Duration oneSec = Duration ( seconds: 1 ) ;
timerForQuestion = Timer . periodic (
oneSec ,
( Timer timer ) async {
if ( currentQuestionTime = = 2 ) {
getCorrectAnswerAndUpdateAnswerColor ( ) ;
}
if ( currentQuestionTime = = 0 ) {
// we can enable this check if we do not want to show the user QuestionGapImages
// if (!isUserOutOfGame) {
updateCardStatusToAnswer ( ) ;
// }
//todo: we will need to remove this -2 when API is all set
if ( currentQuestionNumber = = marathonDetailModel . totalQuestions ! - 1 ) {
updateQuestionCardStatus ( QuestionCardStatus . findingWinner ) ;
timer . cancel ( ) ;
cancelTimer ( ) ;
notifyListeners ( ) ;
return ;
}
} else {
currentQuestionTime - - ;
}
notifyListeners ( ) ;
} ,
) ;
}
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 = = 0 ) {
timer . cancel ( ) ;
updateQuestionCardStatus ( QuestionCardStatus . winnerFound ) ;
return ;
} else {
totalSecondsToWaitForWinner - - ;
}
notifyListeners ( ) ;
} ,
) ;
}
void swipeCardLeft ( ) {
swiperController . swipeLeft ( ) ;
notifyListeners ( ) ;
}
void resetValues ( ) async {
_currentQuestionNumber = 0 ;
cardContentList . clear ( ) ;
timerForWinnerSelection . cancel ( ) ;
timerForQuestion . cancel ( ) ;
_isMarathonCompleted = false ;
currentQuestionTime = 0 ;
currentQuestion = QuestionModel ( ) ;
notifyListeners ( ) ;
}
void cancelTimer ( ) {
timerForQuestion . cancel ( ) ;
notifyListeners ( ) ;
}
Future < void > getMarathonDetailsFromApi ( ) async {
isLoading = true ;
notifyListeners ( ) ;
await MarathonApiClient ( ) . getMarathonToken ( ) . whenComplete ( ( ) async {
marathonDetailModel = await MarathonApiClient ( ) . getMarathonDetails ( ) ;
populateQuestionStatusesList ( ) ;
isLoading = false ;
notifyListeners ( ) ;
} ) ;
}
Future < void > buildConnectionWithSignalR ( BuildContext context ) async {
Utils . showLoading ( context ) ;
try {
resetValues ( ) ;
// await MarathonApiClient().buildHubConnection(context, marathonDetailModel.sponsors!.first.sponsorPrizes!.first.id!);
} catch ( e ) {
if ( kDebugMode ) {
print ( " error in buildConnectionWithSignalR: ${ e . toString ( ) } " ) ;
}
Utils . hideLoading ( context ) ;
Utils . confirmDialog ( context , e . toString ( ) ) ;
}
}
Future < void > onJoinMarathonPressed ( BuildContext context ) async {
//TODO: here we need to put a check to make sure we should not display sponsor when remaining time to marathon is less than 30 seconds plus video duration e.g. 30 seconds + video duration time
// if (marathonDetailModel.sponsors!.first.video != null && marathonDetailModel.sponsors!.first.video != "") {
if ( false ) {
await initializeVideoPlayer ( ) . then ( ( _ ) {
startTimerForSponsorVideo ( ) ;
Navigator . pushNamed ( context , AppRoutes . marathonSponsorVideoScreen ) ;
} ) ;
} else {
// Utils.showLoading(context);
// await MarathonApiClient().getNextQuestion(selectedOptionId: null, questionId: null, marathonId: marathonDetailModel.id!);
// if (isJoined) {
//
// if (Utils.isLoading) {
// Utils.hideLoading(AppRoutes.navigatorKey.currentContext!);
// }
// }
// Navigator.pushReplacementNamed(context, AppRoutes.marathonWaitingScreen);
}
}
}