MOBILE-2417 quiz: Show question status while attempting quiz
parent
e6c5607463
commit
9d2f5950d4
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue