MOBILE-2417 quiz: Show question status while attempting quiz

main
Dani Palou 2018-08-16 12:50:57 +02:00
parent e6c5607463
commit 9d2f5950d4
5 changed files with 69 additions and 4 deletions

View File

@ -1,5 +1,28 @@
page-addon-mod-quiz-navigation-modal { page-addon-mod-quiz-navigation-modal {
.addon-mod_quiz-selected, .item.addon-mod_quiz-selected { .addon-mod_quiz-selected, .item.addon-mod_quiz-selected {
background: $blue-light; border-left: 5px solid $core-splitview-selected;
font-weight: bold;
&.item-md {
padding-left: $item-md-padding-start - 5px;
}
&.item-ios {
padding-left: $item-ios-padding-start - 5px;
}
&.item-wp {
padding-left: $item-wp-padding-start - 5px;
}
}
.item.core-question-correct .item-inner {
background-image: url("data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2020'><path%20d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z'%20fill='%23394e00'/></svg>") !important;
}
.item.core-question-incorrect .item-inner {
background-image: url("data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2020'><path%20d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z'%20fill='%23cb3d4d'/></svg>") !important;
}
.item.core-question-answersaved .item-inner {
background-image: url("data:image/svg+xml;charset=utf-8,<svg%20xmlns='http://www.w3.org/2000/svg'%20viewBox='0%200%2012%2020'><path%20d='M2,20l-2-2l8-8L0,2l2-2l10,10L2,20z'%20fill='%233a3a3a'/></svg>") !important;
} }
} }

View File

@ -6,7 +6,7 @@
<button id="addon-mod_quiz-connection-error-button" ion-button icon-only [hidden]="!autoSaveError" (click)="showConnectionError($event)" [attr.aria-label]="'core.error' | translate"> <button id="addon-mod_quiz-connection-error-button" ion-button icon-only [hidden]="!autoSaveError" (click)="showConnectionError($event)" [attr.aria-label]="'core.error' | translate">
<ion-icon name="alert"></ion-icon> <ion-icon name="alert"></ion-icon>
</button> </button>
<button *ngIf="navigation && navigation.length" ion-button icon-only [attr.aria-label]="'addon.mod_quiz.opentoc' | translate" (click)="navigationModal.present()"> <button *ngIf="navigation && navigation.length" ion-button icon-only [attr.aria-label]="'addon.mod_quiz.opentoc' | translate" (click)="openNavigation()">
<ion-icon name="bookmark"></ion-icon> <ion-icon name="bookmark"></ion-icon>
</button> </button>
</ion-buttons> </ion-buttons>

View File

@ -70,6 +70,7 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
protected autoSave: AddonModQuizAutoSave; // Class to auto-save answers every certain time. protected autoSave: AddonModQuizAutoSave; // Class to auto-save answers every certain time.
protected autoSaveErrorSubscription: Subscription; // To be notified when an error happens in auto-save. protected autoSaveErrorSubscription: Subscription; // To be notified when an error happens in auto-save.
protected forceLeave = false; // If true, don't perform any check when leaving the view. protected forceLeave = false; // If true, don't perform any check when leaving the view.
protected reloadNavigaton = false; // Whether navigation needs to be reloaded because some data was sent to server.
constructor(navParams: NavParams, logger: CoreLoggerProvider, protected translate: TranslateService, constructor(navParams: NavParams, logger: CoreLoggerProvider, protected translate: TranslateService,
protected eventsProvider: CoreEventsProvider, protected sitesProvider: CoreSitesProvider, protected eventsProvider: CoreEventsProvider, protected sitesProvider: CoreSitesProvider,
@ -173,6 +174,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
// Behaviour checks are always in online. // Behaviour checks are always in online.
return this.quizProvider.processAttempt(this.quiz, this.attempt, answers, this.preflightData).then(() => { return this.quizProvider.processAttempt(this.quiz, this.attempt, answers, this.preflightData).then(() => {
this.reloadNavigaton = true; // Data sent to server, navigation should be reloaded.
// Reload the current page. // Reload the current page.
const scrollElement = this.content.getScrollElement(), const scrollElement = this.content.getScrollElement(),
scrollTop = scrollElement.scrollTop || 0, scrollTop = scrollElement.scrollTop || 0,
@ -224,7 +227,9 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
// First try to save the attempt data. We only save it if we're not seeing the summary. // First try to save the attempt data. We only save it if we're not seeing the summary.
const promise = this.showSummary ? Promise.resolve() : this.processAttempt(false, false); const promise = this.showSummary ? Promise.resolve() : this.processAttempt(false, false);
promise.then(() => { promise.then(() => {
// Attempt data successfully saved, load the page or summary. if (!this.showSummary) {
this.reloadNavigaton = true; // Data sent to server, navigation should be reloaded.
}
// Attempt data successfully saved, load the page or summary. // Attempt data successfully saved, load the page or summary.
let subPromise; let subPromise;
@ -460,11 +465,44 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
*/ */
protected loadNavigation(): Promise<void> { protected loadNavigation(): Promise<void> {
// We use the attempt summary to build the navigation because it contains all the questions. // We use the attempt summary to build the navigation because it contains all the questions.
return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, this.offline).then((questions) => { return this.quizProvider.getAttemptSummary(this.attempt.id, this.preflightData, this.offline, true, true)
.then((questions) => {
questions.forEach((question) => {
question.stateClass = this.questionHelper.getQuestionStateClass(question.state);
});
this.navigation = questions; this.navigation = questions;
}); });
} }
/**
* Open the navigation modal.
*
* @return {Promise<any>} Promise resolved when done.
*/
openNavigation(): Promise<any> {
let promise;
if (this.reloadNavigaton) {
// Some data has changed, reload the navigation.
const modal = this.domUtils.showModalLoading();
promise = this.loadNavigation().catch(() => {
// Ignore errors.
}).then(() => {
modal.dismiss();
this.reloadNavigaton = false;
});
} else {
promise = Promise.resolve();
}
return promise.finally(() => {
this.navigationModal.present();
});
}
// Prepare the answers to be sent for the attempt. // Prepare the answers to be sent for the attempt.
protected prepareAnswers(): Promise<any> { protected prepareAnswers(): Promise<any> {
return this.questionHelper.prepareAnswers(this.questions, this.getAnswers(), this.offline); return this.questionHelper.prepareAnswers(this.questions, this.getAnswers(), this.offline);

View File

@ -474,6 +474,9 @@ ion-col ion-select {
.core-question-incorrect { .core-question-incorrect {
background-color: $core-question-state-incorrect-color; background-color: $core-question-state-incorrect-color;
} }
.core-question-answersaved {
background-color: $core-question-saved-color-bg;
}
.core-question-warning { .core-question-warning {
color: $core-question-warning-color; color: $core-question-warning-color;

View File

@ -234,6 +234,7 @@ $core-question-incorrect-color-bg: $red-light !default;
$core-question-feedback-color: $yellow-dark !default; $core-question-feedback-color: $yellow-dark !default;
$core-question-feedback-color-bg: $yellow-light !default; $core-question-feedback-color-bg: $yellow-light !default;
$core-question-warning-color: $red !default; $core-question-warning-color: $red !default;
$core-question-saved-color-bg: $gray-light !default;
$core-question-state-correct-color: $green-light !default; $core-question-state-correct-color: $green-light !default;
$core-question-state-partial-color: $yellow-light !default; $core-question-state-partial-color: $yellow-light !default;