import { assertExists } from '@ulangi/assert' ; import { LightBoxState , ScreenName } from '@ulangi/ulangi-common/enums' ; import { ErrorBag , Vocabulary } from '@ulangi/ulangi-common/interfaces' ; import { ObservableLightBox , ObservableReflexScreen , Observer , } from '@ulangi/ulangi-observable' ; import { boundClass } from 'autobind-decorator' ; import { observable } from 'mobx' ; import { RemoteLogger } from '../../RemoteLogger' ; import { config } from '../../constants/config' ; import { ReflexQuestionIterator } from '../../iterators/ReflexQuestionIterator' ; import { reflexStyles } from '../../styles/ReflexStyles' ; import { DialogDelegate } from '../dialog/DialogDelegate' ; import { NavigatorDelegate } from '../navigator/NavigatorDelegate' ; import { FetchVocabularyDelegate } from './FetchVocabularyDelegate' ; import { TimerDelegate } from './TimerDelegate' ; @ boundClass export class ReflexScreenDelegate { private observer : Observer ; private observableLightBox : ObservableLightBox ; private observableScreen : ObservableReflexScreen ; private questionIterator : ReflexQuestionIterator ; private fetchVocabularyDelegate : FetchVocabularyDelegate ; private timerDelegate : TimerDelegate ; private dialogDelegate : DialogDelegate ; private navigatorDelegate : NavigatorDelegate ; public constructor ( observer , observableLightBox , observableScreen , questionIterator , fetchVocabularyDelegate , timerDelegate , dialogDelegate , navigatorDelegate ) { this . observer = observer ; this . observableLightBox = observableLightBox ; this . observableScreen = observableScreen ; this . questionIterator = questionIterator ; this . fetchVocabularyDelegate = fetchVocabularyDelegate ; this . timerDelegate = timerDelegate ; this . dialogDelegate = dialogDelegate ; this . navigatorDelegate = navigatorDelegate ; } public startGame ( ) { RemoteLogger . logEvent ( 'start_reflex' ) ; this . fetchVocabularyDelegate . prepareFetch ( { onPreparing : this . showPreparingDialog , onPrepareSucceeded : ( ) : void => { this . fetchVocabularyDelegate . fetch ( { onFetchSucceeded : ( vocabularyList , noMore ) : void => { this . addVocabularyToQueueAndShuffle ( vocabularyList ) ; this . observableScreen . noMoreVocabulary = noMore ; if ( this . questionIterator . getNumberOfQuestionLeft ( ) === 0 ) { this . showNoVocabularyLightBox ( ) ; this . clearFetchVocabulary ( ) ; } else { this . navigatorDelegate . dismissLightBox ( ) ; this . observer . when ( ( ) : boolean => this . observableLightBox . state === LightBoxState . UNMOUNTED , ( ) : void => { this . disablePopGesture ( ) ; this . observableScreen . gameState . started = true ; this . next ( ) ; } ) ; } } , onFetchFailed : ( errorBag ) : void => { this . clearFetchVocabulary ( ) ; this . showPrepareFailedDialog ( errorBag ) ; } , } ) ; } , onPrepareFailed : ( errorBag ) : void => { this . clearFetchVocabulary ( ) ; this . showPrepareFailedDialog ( errorBag ) ; } , } ) ; } public clearGame ( ) { this . clearFetchVocabulary ( ) ; } public pause ( ) { this . timerDelegate . stopTimer ( ) ; this . showPausedLightBox ( ) ; } public quit ( ) { this . navigatorDelegate . dismissLightBox ( ) ; this . navigatorDelegate . dismissScreen ( ) ; } public continue ( ) { this . navigatorDelegate . dismissLightBox ( ) ; this . timerDelegate . startTimer ( { onTimeUp : this . handleTimeUp , } ) ; } public restart ( ) { this . timerDelegate . stopAndResetTimer ( ) ; this . observableScreen . gameState . reset ( false , config . reflex . timePerQuestion , false ) ; this . observableScreen . gameStats . reset ( 0 ) ; this . questionIterator . reset ( ) ; this . navigatorDelegate . dismissLightBox ( ) ; this . observer . when ( ( ) : boolean => this . observableLightBox . state === LightBoxState . UNMOUNTED , ( ) : void => { this . clearFetchVocabulary ( ) ; this . startGame ( ) ; } ) ; } public handleSelectAnswer ( answer ) { this . timerDelegate . stopTimer ( ) ; const question = assertExists ( this . observableScreen . gameState . currentQuestion , 'currentQuestion should not be null or undefined' ) ; if ( answer === 'YES' && question . correctMeaning === question . randomMeaning ) { this . handleAnswerCorrect ( ) ; } else if ( answer === 'NO' && question . correctMeaning !== question . randomMeaning ) { this . handleAnswerCorrect ( ) ; } else { this . gameOver ( 'Wrong Answer!' ) ; } } public handleIconPressed ( ) { if ( this . observableScreen . gameState . started === true ) { this . pause ( ) ; } else { this . navigatorDelegate . dismissScreen ( ) ; } } public selectCategory ( ) { this . navigatorDelegate . showModal ( ScreenName . CATEGORY_SELECTOR_SCREEN , { initialCategoryName : undefined , onSelect : ( categoryName ) : void => { this . observableScreen . selectedCategoryNames = observable . array ( [ categoryName , ] ) ; } , } ) ; } private disablePopGesture ( ) { this . navigatorDelegate . mergeOptions ( { popGesture : false , } ) ; } private clearFetchVocabulary ( ) { this . observableScreen . noMoreVocabulary = false ; this . fetchVocabularyDelegate . clearFetch ( ) ; } private handleAnswerCorrect ( ) { this . observableScreen . gameStats . score = this . observableScreen . gameStats . score + 1 ; this . next ( ) ; } private next ( ) { if ( ! this . questionIterator . isDone ( ) ) { this . observableScreen . gameState . currentQuestion = this . questionIterator . next ( ) ; this . timerDelegate . stopAndResetTimer ( ) ; this . timerDelegate . startTimer ( { onTimeUp : this . handleTimeUp , } ) ; } else { if ( this . observableScreen . noMoreVocabulary === true ) { this . gameOver ( 'No More Vocabulary!' ) ; } else { this . showWaitingLightBox ( ) ; } } if ( this . observableScreen . noMoreVocabulary === false ) { this . fetchVocabularyDelegate . fetchVocabularyIfBelowThreshold ( { onFetchSucceeded : ( vocabularyList , noMore ) : void => { this . addVocabularyToQueueAndShuffle ( vocabularyList ) ; this . observableScreen . noMoreVocabulary = noMore ; if ( this . observableScreen . gameState . waitingForFetching === true ) { this . dismissWaitingDialogAndNext ( ) ; } } , } ) ; } } private handleTimeUp ( ) { this . gameOver ( "Time's Up!" ) ; } private gameOver ( title ) { this . timerDelegate . stopTimer ( ) ; this . showGameOverLightBox ( title ) ; } private addVocabularyToQueueAndShuffle ( vocabularyList ) { this . questionIterator . merge ( new Map ( vocabularyList . map ( ( vocabulary ) : [ string , Vocabulary ] => [ vocabulary . vocabularyId , vocabulary , ] ) ) ) ; this . questionIterator . shuffleQueue ( ) ; } private dismissWaitingDialogAndNext ( ) { this . observableScreen . gameState . waitingForFetching = false ; this . navigatorDelegate . dismissLightBox ( ) ; this . observer . when ( ( ) : boolean => this . observableLightBox . state === LightBoxState . UNMOUNTED , ( ) : void => { this . next ( ) ; } ) ; } private showWaitingLightBox ( ) { this . observableScreen . gameState . waitingForFetching = true ; this . dialogDelegate . show ( { title : 'FETCHING VOCABULARY' , message : 'Fetching more vocabulary. Please wait...' , } ) ; } private showPausedLightBox ( ) { this . navigatorDelegate . showLightBox ( ScreenName . REFLEX_PAUSED_SCREEN , { continue : this . continue , restart : this . restart , quit : this . quit , } , reflexStyles . getLightBoxScreenStyles ( ) ) ; } private showGameOverLightBox ( title ) { this . navigatorDelegate . showLightBox ( ScreenName . REFLEX_GAME_OVER_SCREEN , { title , score : this . observableScreen . gameStats . score , restart : this . restart , quit : this . quit , } , reflexStyles . getLightBoxScreenStyles ( ) ) ; } private showNoVocabularyLightBox ( ) { this . dialogDelegate . show ( { title : 'FAILED TO START' , message : 'No vocabulary available to play. Please add some vocabulary.' , showCloseButton : true , closeOnTouchOutside : true , } ) ; } private showPreparingDialog ( ) { this . dialogDelegate . show ( { message : 'Preparing. Please wait...' , } ) ; } private showPrepareFailedDialog ( errorBag ) { this . dialogDelegate . showFailedDialog ( errorBag , { title : 'FAILED TO START' , } ) ; } }