Skip to content

Commit 0cf2b3c

Browse files
authored
Merge pull request #2593 from dpalou/MOBILE-2272
Mobile 2272
2 parents f780b3a + 3df105b commit 0cf2b3c

File tree

47 files changed

+1395
-476
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

47 files changed

+1395
-476
lines changed

scripts/langindex.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1861,6 +1861,7 @@
18611861
"core.mainmenu.help": "moodle",
18621862
"core.mainmenu.logout": "moodle",
18631863
"core.mainmenu.website": "local_moodlemobileapp",
1864+
"core.maxfilesize": "moodle",
18641865
"core.maxsizeandattachments": "moodle",
18651866
"core.min": "moodle",
18661867
"core.mins": "moodle",
@@ -1944,8 +1945,8 @@
19441945
"core.question.certainty": "qbehaviour_deferredcbm",
19451946
"core.question.complete": "question",
19461947
"core.question.correct": "question",
1947-
"core.question.errorattachmentsnotsupported": "local_moodlemobileapp",
1948-
"core.question.errorinlinefilesnotsupported": "local_moodlemobileapp",
1948+
"core.question.errorattachmentsnotsupportedinsite": "local_moodlemobileapp",
1949+
"core.question.errorembeddedfilesnotsupportedinsite": "local_moodlemobileapp",
19491950
"core.question.errorquestionnotsupported": "local_moodlemobileapp",
19501951
"core.question.feedback": "question",
19511952
"core.question.howtodraganddrop": "local_moodlemobileapp",

src/addon/mod/lesson/providers/lesson-sync.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ export class AddonModLessonSyncProvider extends CoreCourseActivitySyncBaseProvid
411411
const params = this.urlUtils.extractUrlParams(response.data.reviewlesson.value);
412412
if (params && params.pageid) {
413413
// The retake can be reviewed, mark it as finished. Don't block the user for this.
414-
this.setRetakeFinishedInSync(lessonId, retake.retake, params.pageid, siteId);
414+
this.setRetakeFinishedInSync(lessonId, retake.retake, Number(params.pageid), siteId);
415415
}
416416
}
417417
}

src/addon/mod/quiz/pages/player/player.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -569,7 +569,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
569569

570570
// Prepare the answers to be sent for the attempt.
571571
protected prepareAnswers(): Promise<any> {
572-
return this.questionHelper.prepareAnswers(this.questions, this.getAnswers(), this.offline);
572+
return this.questionHelper.prepareAnswers(this.questions, this.getAnswers(), this.offline, this.component,
573+
this.quiz.coursemodule);
573574
}
574575

575576
/**
@@ -612,6 +613,8 @@ export class AddonModQuizPlayerPage implements OnInit, OnDestroy {
612613
if (this.formElement) {
613614
this.domUtils.triggerFormSubmittedEvent(this.formElement, !this.offline, this.sitesProvider.getCurrentSiteId());
614615
}
616+
617+
return this.questionHelper.clearTmpData(this.questions, this.component, this.quiz.coursemodule);
615618
});
616619
}
617620

src/addon/mod/quiz/providers/quiz-offline.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -342,8 +342,8 @@ export class AddonModQuizOfflineProvider {
342342
for (const slot in questionsWithAnswers) {
343343
const question = questionsWithAnswers[slot];
344344

345-
promises.push(this.behaviourDelegate.determineNewState(
346-
quiz.preferredbehaviour, AddonModQuizProvider.COMPONENT, attempt.id, question, siteId).then((state) => {
345+
promises.push(this.behaviourDelegate.determineNewState(quiz.preferredbehaviour, AddonModQuizProvider.COMPONENT,
346+
attempt.id, question, quiz.coursemodule, siteId).then((state) => {
347347
// Check if state has changed.
348348
if (state && state.name != question.state) {
349349
newStates[question.slot] = state.name;

src/addon/mod/quiz/providers/quiz-sync.ts

Lines changed: 145 additions & 110 deletions
Large diffs are not rendered by default.

src/addon/mod/quiz/providers/quiz.ts

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,8 @@ export class AddonModQuizProvider {
215215
};
216216

217217
return site.read('mod_quiz_get_attempt_data', params, preSets);
218+
}).then((result) => {
219+
return this.parseQuestions(result);
218220
});
219221
}
220222

@@ -389,7 +391,9 @@ export class AddonModQuizProvider {
389391
...this.sitesProvider.getReadingStrategyPreSets(options.readingStrategy), // Include reading strategy preSets.
390392
};
391393

392-
return site.read('mod_quiz_get_attempt_review', params, preSets);
394+
return site.read('mod_quiz_get_attempt_review', params, preSets).then((result) => {
395+
return this.parseQuestions(result);
396+
});
393397
});
394398
}
395399

@@ -427,6 +431,8 @@ export class AddonModQuizProvider {
427431

428432
return site.read('mod_quiz_get_attempt_summary', params, preSets).then((response) => {
429433
if (response && response.questions) {
434+
response = this.parseQuestions(response);
435+
430436
if (options.loadLocal) {
431437
return this.quizOfflineProvider.loadQuestionsLocalStates(attemptId, response.questions, site.getId());
432438
}
@@ -1560,6 +1566,27 @@ export class AddonModQuizProvider {
15601566
siteId);
15611567
}
15621568

1569+
/**
1570+
* Parse questions of a WS response.
1571+
*
1572+
* @param result Result to parse.
1573+
* @return Parsed result.
1574+
*/
1575+
parseQuestions(result: any): any {
1576+
for (let i = 0; i < result.questions.length; i++) {
1577+
const question = result.questions[i];
1578+
1579+
if (!question.settings) {
1580+
// Site doesn't return settings, stop.
1581+
break;
1582+
}
1583+
1584+
question.settings = this.textUtils.parseJSON(question.settings, null);
1585+
}
1586+
1587+
return result;
1588+
}
1589+
15631590
/**
15641591
* Process an attempt, saving its data.
15651592
*

src/addon/qbehaviour/deferredcbm/providers/handler.ts

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,14 @@ export class AddonQbehaviourDeferredCBMHandler implements CoreQuestionBehaviourH
4040
* @param component Component the question belongs to.
4141
* @param attemptId Attempt ID the question belongs to.
4242
* @param question The question.
43+
* @param componentId Component ID.
4344
* @param siteId Site ID. If not defined, current site.
4445
* @return New state (or promise resolved with state).
4546
*/
46-
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
47+
determineNewState(component: string, attemptId: number, question: any, componentId: string | number, siteId?: string)
4748
: CoreQuestionState | Promise<CoreQuestionState> {
4849
// Depends on deferredfeedback.
49-
return this.deferredFeedbackHandler.determineNewStateDeferred(component, attemptId, question, siteId,
50+
return this.deferredFeedbackHandler.determineNewStateDeferred(component, attemptId, question, componentId, siteId,
5051
this.isCompleteResponse.bind(this), this.isSameResponse.bind(this));
5152
}
5253

@@ -71,11 +72,13 @@ export class AddonQbehaviourDeferredCBMHandler implements CoreQuestionBehaviourH
7172
*
7273
* @param question The question.
7374
* @param answers Object with the question answers (without prefix).
75+
* @param component The component the question is related to.
76+
* @param componentId Component ID.
7477
* @return 1 if complete, 0 if not complete, -1 if cannot determine.
7578
*/
76-
protected isCompleteResponse(question: any, answers: any): number {
79+
protected isCompleteResponse(question: any, answers: any, component: string, componentId: string | number): number {
7780
// First check if the question answer is complete.
78-
const complete = this.questionDelegate.isCompleteResponse(question, answers);
81+
const complete = this.questionDelegate.isCompleteResponse(question, answers, component, componentId);
7982
if (complete > 0) {
8083
// Answer is complete, check the user answered CBM too.
8184
return answers['-certainty'] ? 1 : 0;
@@ -101,12 +104,14 @@ export class AddonQbehaviourDeferredCBMHandler implements CoreQuestionBehaviourH
101104
* @param prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
102105
* @param newAnswers Object with the new question answers.
103106
* @param newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
107+
* @param component The component the question is related to.
108+
* @param componentId Component ID.
104109
* @return Whether they're the same.
105110
*/
106-
protected isSameResponse(question: any, prevAnswers: any, prevBasicAnswers: any, newAnswers: any, newBasicAnswers: any)
107-
: boolean {
111+
protected isSameResponse(question: any, prevAnswers: any, prevBasicAnswers: any, newAnswers: any, newBasicAnswers: any,
112+
component: string, componentId: string | number): boolean {
108113
// First check if the question answer is the same.
109-
const same = this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers);
114+
const same = this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers, component, componentId);
110115
if (same) {
111116
// Same response, check the CBM is the same too.
112117
return prevAnswers['-certainty'] == newAnswers['-certainty'];

src/addon/qbehaviour/deferredfeedback/providers/handler.ts

Lines changed: 68 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@ import { CoreQuestionProvider, CoreQuestionState } from '@core/question/provider
2323
*
2424
* @param question The question.
2525
* @param answers Object with the question answers (without prefix).
26+
* @param component The component the question is related to.
27+
* @param componentId Component ID.
2628
* @return 1 if complete, 0 if not complete, -1 if cannot determine.
2729
*/
28-
export type isCompleteResponseFunction = (question: any, answers: any) => number;
30+
export type isCompleteResponseFunction = (question: any, answers: any, component: string, componentId: string | number) => number;
2931

3032
/**
3133
* Check if two responses are the same.
@@ -35,10 +37,12 @@ export type isCompleteResponseFunction = (question: any, answers: any) => number
3537
* @param prevBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
3638
* @param newAnswers Object with the new question answers.
3739
* @param newBasicAnswers Object with the previous basic" answers (without sequencecheck, certainty, ...).
40+
* @param component The component the question is related to.
41+
* @param componentId Component ID.
3842
* @return Whether they're the same.
3943
*/
4044
export type isSameResponseFunction = (question: any, prevAnswers: any, prevBasicAnswers: any, newAnswers: any,
41-
newBasicAnswers: any) => boolean;
45+
newBasicAnswers: any, component: string, componentId: string | number) => boolean;
4246

4347
/**
4448
* Handler to support deferred feedback question behaviour.
@@ -58,12 +62,13 @@ export class AddonQbehaviourDeferredFeedbackHandler implements CoreQuestionBehav
5862
* @param component Component the question belongs to.
5963
* @param attemptId Attempt ID the question belongs to.
6064
* @param question The question.
65+
* @param componentId Component ID.
6166
* @param siteId Site ID. If not defined, current site.
6267
* @return New state (or promise resolved with state).
6368
*/
64-
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
69+
determineNewState(component: string, attemptId: number, question: any, componentId: string | number, siteId?: string)
6570
: CoreQuestionState | Promise<CoreQuestionState> {
66-
return this.determineNewStateDeferred(component, attemptId, question, siteId);
71+
return this.determineNewStateDeferred(component, attemptId, question, componentId, siteId);
6772
}
6873

6974
/**
@@ -72,75 +77,82 @@ export class AddonQbehaviourDeferredFeedbackHandler implements CoreQuestionBehav
7277
* @param component Component the question belongs to.
7378
* @param attemptId Attempt ID the question belongs to.
7479
* @param question The question.
80+
* @param componentId Component ID.
7581
* @param siteId Site ID. If not defined, current site.
7682
* @param isCompleteFn Function to override the default isCompleteResponse check.
7783
* @param isSameFn Function to override the default isSameResponse check.
7884
* @return Promise resolved with state.
7985
*/
80-
determineNewStateDeferred(component: string, attemptId: number, question: any, siteId?: string,
81-
isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction): Promise<CoreQuestionState> {
86+
async determineNewStateDeferred(component: string, attemptId: number, question: any, componentId: string | number,
87+
siteId?: string, isCompleteFn?: isCompleteResponseFunction, isSameFn?: isSameResponseFunction)
88+
: Promise<CoreQuestionState> {
8289

8390
// Check if we have local data for the question.
84-
return this.questionProvider.getQuestion(component, attemptId, question.slot, siteId).catch(() => {
91+
let dbQuestion;
92+
try {
93+
dbQuestion = await this.questionProvider.getQuestion(component, attemptId, question.slot, siteId);
94+
} catch (error) {
8595
// No entry found, use the original data.
86-
return question;
87-
}).then((dbQuestion) => {
88-
const state = this.questionProvider.getState(dbQuestion.state);
96+
dbQuestion = question;
97+
}
8998

90-
if (state.finished || !state.active) {
91-
// Question is finished, it cannot change.
92-
return state;
93-
}
99+
const state = this.questionProvider.getState(dbQuestion.state);
94100

95-
// We need to check if the answers have changed. Retrieve current stored answers.
96-
return this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId)
97-
.then((prevAnswers) => {
101+
if (state.finished || !state.active) {
102+
// Question is finished, it cannot change.
103+
return state;
104+
}
98105

99-
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers);
106+
const newBasicAnswers = this.questionProvider.getBasicAnswers(question.answers);
100107

101-
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true);
102-
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers);
108+
if (dbQuestion.state) {
109+
// Question already has a state stored. Check if answer has changed.
110+
let prevAnswers = await this.questionProvider.getQuestionAnswers(component, attemptId, question.slot, false, siteId);
103111

104-
// If answers haven't changed the state is the same.
105-
if (isSameFn) {
106-
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers)) {
107-
return state;
108-
}
109-
} else {
110-
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers)) {
111-
return state;
112-
}
113-
}
112+
prevAnswers = this.questionProvider.convertAnswersArrayToObject(prevAnswers, true);
113+
const prevBasicAnswers = this.questionProvider.getBasicAnswers(prevAnswers);
114114

115-
// Answers have changed. Now check if the response is complete and calculate the new state.
116-
let complete: number,
117-
newState: string;
118-
if (isCompleteFn) {
119-
// Pass all the answers since some behaviours might need the extra data.
120-
complete = isCompleteFn(question, question.answers);
121-
} else {
122-
// Only pass the basic answers since questions should be independent of extra data.
123-
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers);
115+
// If answers haven't changed the state is the same.
116+
if (isSameFn) {
117+
if (isSameFn(question, prevAnswers, prevBasicAnswers, question.answers, newBasicAnswers,
118+
component, componentId)) {
119+
return state;
124120
}
125-
126-
if (complete < 0) {
127-
newState = 'cannotdeterminestatus';
128-
} else if (complete > 0) {
129-
newState = 'complete';
130-
} else {
131-
const gradable = this.questionDelegate.isGradableResponse(question, newBasicAnswers);
132-
if (gradable < 0) {
133-
newState = 'cannotdeterminestatus';
134-
} else if (gradable > 0) {
135-
newState = 'invalid';
136-
} else {
137-
newState = 'todo';
138-
}
121+
} else {
122+
if (this.questionDelegate.isSameResponse(question, prevBasicAnswers, newBasicAnswers, component, componentId)) {
123+
return state;
139124
}
125+
}
126+
}
127+
128+
// Answers have changed. Now check if the response is complete and calculate the new state.
129+
let complete: number;
130+
let newState: string;
131+
132+
if (isCompleteFn) {
133+
// Pass all the answers since some behaviours might need the extra data.
134+
complete = isCompleteFn(question, question.answers, component, componentId);
135+
} else {
136+
// Only pass the basic answers since questions should be independent of extra data.
137+
complete = this.questionDelegate.isCompleteResponse(question, newBasicAnswers, component, componentId);
138+
}
139+
140+
if (complete < 0) {
141+
newState = 'cannotdeterminestatus';
142+
} else if (complete > 0) {
143+
newState = 'complete';
144+
} else {
145+
const gradable = this.questionDelegate.isGradableResponse(question, newBasicAnswers, component, componentId);
146+
if (gradable < 0) {
147+
newState = 'cannotdeterminestatus';
148+
} else if (gradable > 0) {
149+
newState = 'invalid';
150+
} else {
151+
newState = 'todo';
152+
}
153+
}
140154

141-
return this.questionProvider.getState(newState);
142-
});
143-
});
155+
return this.questionProvider.getState(newState);
144156
}
145157

146158
/**

src/addon/qbehaviour/informationitem/providers/handler.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,11 @@ export class AddonQbehaviourInformationItemHandler implements CoreQuestionBehavi
3535
* @param component Component the question belongs to.
3636
* @param attemptId Attempt ID the question belongs to.
3737
* @param question The question.
38+
* @param componentId Component ID.
3839
* @param siteId Site ID. If not defined, current site.
3940
* @return New state (or promise resolved with state).
4041
*/
41-
determineNewState(component: string, attemptId: number, question: any, siteId?: string)
42+
determineNewState(component: string, attemptId: number, question: any, componentId: string | number, siteId?: string)
4243
: CoreQuestionState | Promise<CoreQuestionState> {
4344
if (question.answers['-seen']) {
4445
return this.questionProvider.getState('complete');

0 commit comments

Comments
 (0)