MOBILE-2334 assign: Fix errors with offline and sync

main
Dani Palou 2018-04-19 13:28:22 +02:00
parent dc74546f3d
commit ae290c3c05
20 changed files with 107 additions and 97 deletions

View File

@ -105,6 +105,9 @@ export class AddonModAssignIndexComponent extends CoreCourseModuleMainActivityCo
if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) { if (this.assign && data.assignmentId == this.assign.id && data.userId == this.userId) {
// Assignment submitted, check completion. // Assignment submitted, check completion.
this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus); this.courseProvider.checkModuleCompletion(this.courseId, this.module.completionstatus);
// Reload data since it can have offline data now.
this.showLoadingAndRefresh(true, false);
} }
}, this.siteId); }, this.siteId);

View File

@ -200,7 +200,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
*/ */
copyPrevious(): void { copyPrevious(): void {
if (!this.appProvider.isOnline()) { if (!this.appProvider.isOnline()) {
this.domUtils.showErrorModal('mm.core.networkerrormsg', true); this.domUtils.showErrorModal('core.networkerrormsg', true);
return; return;
} }
@ -229,9 +229,6 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
// Now go to edit. // Now go to edit.
this.goToEdit(); this.goToEdit();
// Invalidate and refresh data to update this view.
this.invalidateAndRefresh();
if (!this.assign.submissiondrafts) { if (!this.assign.submissiondrafts) {
// No drafts allowed, so it was submitted. Trigger event. // No drafts allowed, so it was submitted. Trigger event.
this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, { this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, {
@ -239,12 +236,17 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
submissionId: this.userSubmission.id, submissionId: this.userSubmission.id,
userId: this.currentUserId userId: this.currentUserId
}, this.siteId); }, this.siteId);
} else {
// Invalidate and refresh data to update this view.
this.invalidateAndRefresh();
} }
}).catch((error) => { }).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'core.error', true); this.domUtils.showErrorModalDefault(error, 'core.error', true);
}).finally(() => { }).finally(() => {
modal.dismiss(); modal.dismiss();
}); });
}).catch(() => {
// Cancelled.
}); });
} }
@ -382,7 +384,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
// Check if there's any offline data for this submission. // Check if there's any offline data for this submission.
promises.push(this.assignOfflineProvider.getSubmission(assign.id, this.submitId).then((data) => { promises.push(this.assignOfflineProvider.getSubmission(assign.id, this.submitId).then((data) => {
this.hasOffline = data && data.plugindata && Object.keys(data.plugindata).length > 0; this.hasOffline = data && data.pluginData && Object.keys(data.pluginData).length > 0;
this.submittedOffline = data && data.submitted; this.submittedOffline = data && data.submitted;
}).catch(() => { }).catch(() => {
// No offline data found. // No offline data found.
@ -505,6 +507,9 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
return; return;
} }
// Make sure outcomes is an array.
gradeInfo.outcomes = gradeInfo.outcomes || [];
if (!this.isDestroyed) { if (!this.isDestroyed) {
// Block the assignment. // Block the assignment.
this.syncProvider.blockOperation(AddonModAssignProvider.COMPONENT, this.assign.id); this.syncProvider.blockOperation(AddonModAssignProvider.COMPONENT, this.assign.id);
@ -556,8 +561,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
this.originalGrades.grade = this.grade.grade; this.originalGrades.grade = this.grade.grade;
} }
this.grade.applyToAll = data.applytoall; this.grade.applyToAll = data.applyToAll;
this.grade.addAttempt = data.addattempt; this.grade.addAttempt = data.addAttempt;
this.originalGrades.applyToAll = this.grade.applyToAll; this.originalGrades.applyToAll = this.grade.applyToAll;
this.originalGrades.addAttempt = this.grade.addAttempt; this.originalGrades.addAttempt = this.grade.addAttempt;
@ -600,7 +605,7 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
* @param {any} status Submission status. * @param {any} status Submission status.
*/ */
protected setStatusNameAndClass(status: any): void { protected setStatusNameAndClass(status: any): void {
if (this.hasOffline) { if (this.hasOffline || this.submittedOffline) {
// Offline data. // Offline data.
this.statusTranslated = this.translate.instant('core.notsent'); this.statusTranslated = this.translate.instant('core.notsent');
this.statusColor = 'warning'; this.statusColor = 'warning';
@ -669,9 +674,6 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy {
this.assignProvider.submitForGrading(this.assign.id, this.courseId, acceptStatement, this.userSubmission.timemodified, this.assignProvider.submitForGrading(this.assign.id, this.courseId, acceptStatement, this.userSubmission.timemodified,
this.hasOffline).then(() => { this.hasOffline).then(() => {
// Invalidate and refresh data.
this.invalidateAndRefresh();
// Submitted, trigger event. // Submitted, trigger event.
this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, { this.eventsProvider.trigger(AddonModAssignProvider.SUBMITTED_FOR_GRADING_EVENT, {
assignmentId: this.assign.id, assignmentId: this.assign.id,

View File

@ -128,13 +128,13 @@ export class AddonModAssignFeedbackCommentsComponent extends AddonModAssignFeedb
return this.assignOfflineProvider.getSubmissionGrade(this.assign.id, this.userId).catch(() => { return this.assignOfflineProvider.getSubmissionGrade(this.assign.id, this.userId).catch(() => {
// No offline data found. // No offline data found.
}).then((offlineData) => { }).then((offlineData) => {
if (offlineData && offlineData.plugindata && offlineData.plugindata.assignfeedbackcomments_editor) { if (offlineData && offlineData.pluginData && offlineData.pluginData.assignfeedbackcomments_editor) {
// Save offline as draft. // Save offline as draft.
this.isSent = false; this.isSent = false;
this.feedbackDelegate.saveFeedbackDraft(this.assign.id, this.userId, this.plugin, this.feedbackDelegate.saveFeedbackDraft(this.assign.id, this.userId, this.plugin,
offlineData.plugindata.assignfeedbackcomments_editor); offlineData.pluginData.assignfeedbackcomments_editor);
return offlineData.plugindata.assignfeedbackcomments_editor.text; return offlineData.pluginData.assignfeedbackcomments_editor.text;
} }
// No offline data found, return online text. // No offline data found, return online text.

View File

@ -46,7 +46,6 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed
*/ */
discardDraft(assignId: number, userId: number, siteId?: string): void | Promise<any> { discardDraft(assignId: number, userId: number, siteId?: string): void | Promise<any> {
const id = this.getDraftId(assignId, userId, siteId); const id = this.getDraftId(assignId, userId, siteId);
if (typeof this.drafts[id] != 'undefined') { if (typeof this.drafts[id] != 'undefined') {
delete this.drafts[id]; delete this.drafts[id];
} }
@ -129,8 +128,8 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed
return this.assignOfflineProvider.getSubmissionGrade(assign.id, userId).catch(() => { return this.assignOfflineProvider.getSubmissionGrade(assign.id, userId).catch(() => {
// No offline data found. // No offline data found.
}).then((data) => { }).then((data) => {
if (data && data.plugindata && data.plugindata.assignfeedbackcomments_editor) { if (data && data.pluginData && data.pluginData.assignfeedbackcomments_editor) {
return data.plugindata.assignfeedbackcomments_editor.text; return data.pluginData.assignfeedbackcomments_editor.text;
} }
// No offline data found, get text from plugin. // No offline data found, get text from plugin.
@ -172,15 +171,6 @@ export class AddonModAssignFeedbackCommentsHandler implements AddonModAssignFeed
return true; return true;
} }
/**
* Whether or not the handler is enabled for edit on a site level.
*
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled for edit on a site level.
*/
isEnabledForEdit(): boolean | Promise<boolean> {
return true;
}
/** /**
* Prepare and add to pluginData the data to send to the server based on the draft data saved. * Prepare and add to pluginData the data to send to the server based on the draft data saved.
* *

View File

@ -17,7 +17,10 @@
<!-- Submission statement. --> <!-- Submission statement. -->
<ion-item text-wrap *ngIf="submissionStatement"> <ion-item text-wrap *ngIf="submissionStatement">
<ion-label><core-format-text [text]="submissionStatement"></core-format-text></ion-label> <ion-label><core-format-text [text]="submissionStatement"></core-format-text></ion-label>
<ion-checkbox item-end name="submissionstatement"></ion-checkbox> <ion-checkbox item-end name="submissionstatement" [(ngModel)]="submissionStatementAccepted"></ion-checkbox>
<!-- ion-checkbox doesn't use an input. Create a hidden input to hold the value. -->
<input item-content type="hidden" [ngModel]="submissionStatementAccepted" name="submissionstatement">
</ion-item> </ion-item>
<addon-mod-assign-submission-plugin *ngFor="let plugin of userSubmission.plugins" [assign]="assign" [submission]="userSubmission" [plugin]="plugin" [edit]="true" [allowOffline]="allowOffline"></addon-mod-assign-submission-plugin> <addon-mod-assign-submission-plugin *ngFor="let plugin of userSubmission.plugins" [assign]="assign" [submission]="userSubmission" [plugin]="plugin" [edit]="true" [allowOffline]="allowOffline"></addon-mod-assign-submission-plugin>

View File

@ -40,6 +40,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
userSubmission: any; // The user submission. userSubmission: any; // The user submission.
allowOffline: boolean; // Whether offline is allowed. allowOffline: boolean; // Whether offline is allowed.
submissionStatement: string; // The submission statement. submissionStatement: string; // The submission statement.
submissionStatementAccepted: boolean; // Whether submission statement is accepted.
loaded: boolean; // Whether data has been loaded. loaded: boolean; // Whether data has been loaded.
protected moduleId: number; // Module ID the submission belongs to. protected moduleId: number; // Module ID the submission belongs to.
@ -125,7 +126,9 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, this.isBlind).then((response) => { return this.assignProvider.getSubmissionStatus(this.assign.id, this.userId, this.isBlind).then((response) => {
const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt); const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(this.assign, response.lastattempt);
if (this.assignHelper.canEditSubmissionOffline(this.assign, userSubmission)) { // Check if the user can edit it in offline.
return this.assignHelper.canEditSubmissionOffline(this.assign, userSubmission).then((canEditOffline) => {
if (canEditOffline) {
return response; return response;
} }
@ -134,6 +137,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
return Promise.reject(err); return Promise.reject(err);
}); });
});
}).then((response) => { }).then((response) => {
if (!response.lastattempt.canedit) { if (!response.lastattempt.canedit) {
// Can't edit. Reject. // Can't edit. Reject.
@ -152,7 +156,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
// Check if there's any offline data for this submission. // Check if there's any offline data for this submission.
return this.assignOfflineProvider.getSubmission(this.assign.id, this.userId).then((data) => { return this.assignOfflineProvider.getSubmission(this.assign.id, this.userId).then((data) => {
this.hasOffline = data && data.plugindata && Object.keys(data.plugindata).length > 0; this.hasOffline = data && data.pluginData && Object.keys(data.pluginData).length > 0;
}).catch(() => { }).catch(() => {
// No offline data found. // No offline data found.
this.hasOffline = false; this.hasOffline = false;
@ -262,7 +266,7 @@ export class AddonModAssignEditPage implements OnInit, OnDestroy {
protected saveSubmission(): Promise<any> { protected saveSubmission(): Promise<any> {
const inputData = this.getInputData(); const inputData = this.getInputData();
if (this.submissionStatement && !inputData.submissionstatement) { if (this.submissionStatement && (!inputData.submissionstatement || inputData.submissionstatement === 'false')) {
return Promise.reject(this.translate.instant('addon.mod_assign.acceptsubmissionstatement')); return Promise.reject(this.translate.instant('addon.mod_assign.acceptsubmissionstatement'));
} }

View File

@ -218,7 +218,7 @@ export class AddonModAssignSubmissionListPage implements OnInit, OnDestroy {
* @param {any} submission The submission to load. * @param {any} submission The submission to load.
*/ */
loadSubmission(submission: any): void { loadSubmission(submission: any): void {
if (this.selectedSubmissionId === submission.id) { if (this.selectedSubmissionId === submission.id && this.splitviewCtrl.isOn()) {
// Already selected. // Already selected.
return; return;
} }

View File

@ -412,7 +412,6 @@ export class AddonModAssignOfflineProvider {
return { return {
assignId: assignId, assignId: assignId,
courseId: courseId, courseId: courseId,
pluginData: '{}',
userId: userId, userId: userId,
onlineTimemodified: timemodified, onlineTimemodified: timemodified,
timecreated: now, timecreated: now,
@ -420,8 +419,9 @@ export class AddonModAssignOfflineProvider {
}; };
}).then((submission) => { }).then((submission) => {
// Mark the submission. // Mark the submission.
submission.submitted = !!submitted; submission.submitted = submitted ? 1 : 0;
submission.submissionstatement = !!acceptStatement; submission.submissionStatement = acceptStatement ? 1 : 0;
submission.pluginData = submission.pluginData ? JSON.stringify(submission.pluginData) : '{}';
return site.getDb().insertRecord(this.SUBMISSIONS_TABLE, submission); return site.getDb().insertRecord(this.SUBMISSIONS_TABLE, submission);
}); });
@ -452,7 +452,7 @@ export class AddonModAssignOfflineProvider {
courseId: courseId, courseId: courseId,
pluginData: pluginData ? JSON.stringify(pluginData) : '{}', pluginData: pluginData ? JSON.stringify(pluginData) : '{}',
userId: userId, userId: userId,
submitted: !!submitted, submitted: submitted ? 1 : 0,
timecreated: now, timecreated: now,
timemodified: now, timemodified: now,
onlineTimemodified: timemodified onlineTimemodified: timemodified
@ -489,9 +489,9 @@ export class AddonModAssignOfflineProvider {
courseId: courseId, courseId: courseId,
grade: grade, grade: grade,
attemptNumber: attemptNumber, attemptNumber: attemptNumber,
addAttempt: !!addAttempt, addAttempt: addAttempt ? 1 : 0,
workflowState: workflowState, workflowState: workflowState,
applyToAll: !!applyToAll, applyToAll: applyToAll ? 1 : 0,
outcomes: outcomes ? JSON.stringify(outcomes) : '{}', outcomes: outcomes ? JSON.stringify(outcomes) : '{}',
pluginData: pluginData ? JSON.stringify(pluginData) : '{}', pluginData: pluginData ? JSON.stringify(pluginData) : '{}',
timemodified: now timemodified: now

View File

@ -213,7 +213,7 @@ export class AddonModAssignSyncProvider extends CoreSyncBaseProvider {
return Promise.reject(null); return Promise.reject(null);
} }
courseId = submissions.length > 0 ? submissions[0].courseid : grades[0].courseid; courseId = submissions.length > 0 ? submissions[0].courseId : grades[0].courseId;
return this.assignProvider.getAssignmentById(courseId, assignId, siteId).then((assignData) => { return this.assignProvider.getAssignmentById(courseId, assignId, siteId).then((assignData) => {
assign = assignData; assign = assignData;

View File

@ -200,7 +200,12 @@ export class AddonModAssignProvider {
return site.read('mod_assign_get_user_mappings', params, preSets).then((response) => { return site.read('mod_assign_get_user_mappings', params, preSets).then((response) => {
// Search the user. // Search the user.
if (userId && userId > 0 && response.assignments && response.assignments.length) { if (response.assignments && response.assignments.length) {
if (!userId || userId < 0) {
// User not valid, stop.
return -1;
}
const assignment = response.assignments[0]; const assignment = response.assignments[0];
if (assignment.assignmentid == assignId) { if (assignment.assignmentid == assignId) {
@ -212,6 +217,8 @@ export class AddonModAssignProvider {
} }
} }
} }
} else if (response.warnings && response.warnings.length) {
return Promise.reject(response.warnings[0]);
} }
return Promise.reject(null); return Promise.reject(null);

View File

@ -95,12 +95,4 @@ export class AddonModAssignDefaultFeedbackHandler implements AddonModAssignFeedb
isEnabled(): boolean | Promise<boolean> { isEnabled(): boolean | Promise<boolean> {
return true; return true;
} }
/**
* Whether or not the handler is enabled for edit on a site level.
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled for edit on a site level.
*/
isEnabledForEdit(): boolean | Promise<boolean> {
return false;
}
} }

View File

@ -102,13 +102,6 @@ export interface AddonModAssignFeedbackHandler extends CoreDelegateHandler {
*/ */
hasDraftData?(assignId: number, userId: number, siteId?: string): boolean | Promise<boolean>; hasDraftData?(assignId: number, userId: number, siteId?: string): boolean | Promise<boolean>;
/**
* Whether or not the handler is enabled for edit on a site level.
*
* @return {boolean|Promise<boolean>} Whether or not the handler is enabled for edit on a site level.
*/
isEnabledForEdit?(): boolean | Promise<boolean>;
/** /**
* Prefetch any required data for the plugin. * Prefetch any required data for the plugin.
* This should NOT prefetch files. Files to be prefetched should be returned by the getPluginFiles function. * This should NOT prefetch files. Files to be prefetched should be returned by the getPluginFiles function.
@ -258,16 +251,6 @@ export class AddonModAssignFeedbackDelegate extends CoreDelegate {
return this.hasHandler(pluginType, true); return this.hasHandler(pluginType, true);
} }
/**
* Check if a feedback plugin is supported for edit.
*
* @param {string} pluginType Type of the plugin.
* @return {Promise<boolean>} Whether it's supported for edit.
*/
isPluginSupportedForEdit(pluginType: string): Promise<boolean> {
return Promise.resolve(this.executeFunctionOnEnabled(pluginType, 'isEnabledForEdit'));
}
/** /**
* Prefetch any required data for a feedback plugin. * Prefetch any required data for a feedback plugin.
* *

View File

@ -46,25 +46,32 @@ export class AddonModAssignHelperProvider {
* @param {any} submission Submission. * @param {any} submission Submission.
* @return {boolean} Whether it can be edited offline. * @return {boolean} Whether it can be edited offline.
*/ */
canEditSubmissionOffline(assign: any, submission: any): boolean { canEditSubmissionOffline(assign: any, submission: any): Promise<boolean> {
if (!submission) { if (!submission) {
return false; return Promise.resolve(false);
} }
if (submission.status == AddonModAssignProvider.SUBMISSION_STATUS_NEW || if (submission.status == AddonModAssignProvider.SUBMISSION_STATUS_NEW ||
submission.status == AddonModAssignProvider.SUBMISSION_STATUS_REOPENED) { submission.status == AddonModAssignProvider.SUBMISSION_STATUS_REOPENED) {
// It's a new submission, allow creating it in offline. // It's a new submission, allow creating it in offline.
return true; return Promise.resolve(true);
} }
const promises = [];
let canEdit = true;
for (let i = 0; i < submission.plugins.length; i++) { for (let i = 0; i < submission.plugins.length; i++) {
const plugin = submission.plugins[i]; const plugin = submission.plugins[i];
if (!this.submissionDelegate.canPluginEditOffline(assign, submission, plugin)) { promises.push(this.submissionDelegate.canPluginEditOffline(assign, submission, plugin).then((canEditPlugin) => {
return false; if (!canEditPlugin) {
canEdit = false;
} }
}));
} }
return true; return Promise.all(promises).then(() => {
return canEdit;
});
} }
/** /**

View File

@ -153,7 +153,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
if (response.lastattempt) { if (response.lastattempt) {
const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(assign, response.lastattempt); const userSubmission = this.assignProvider.getSubmissionObjectFromAttempt(assign, response.lastattempt);
if (userSubmission) { if (userSubmission && userSubmission.plugins) {
// Add submission plugin files. // Add submission plugin files.
userSubmission.plugins.forEach((plugin) => { userSubmission.plugins.forEach((plugin) => {
promises.push(this.submissionDelegate.getPluginFiles(assign, userSubmission, plugin, siteId)); promises.push(this.submissionDelegate.getPluginFiles(assign, userSubmission, plugin, siteId));
@ -161,7 +161,7 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
} }
} }
if (response.feedback) { if (response.feedback && response.feedback.plugins) {
// Add feedback plugin files. // Add feedback plugin files.
response.feedback.plugins.forEach((plugin) => { response.feedback.plugins.forEach((plugin) => {
promises.push(this.feedbackDelegate.getPluginFiles(assign, response, plugin, siteId)); promises.push(this.feedbackDelegate.getPluginFiles(assign, response, plugin, siteId));
@ -237,7 +237,9 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
blindMarking = assign.blindmarking && !assign.revealidentities; blindMarking = assign.blindmarking && !assign.revealidentities;
if (blindMarking) { if (blindMarking) {
subPromises.push(this.assignProvider.getAssignmentUserMappings(assign.id, undefined, siteId)); subPromises.push(this.assignProvider.getAssignmentUserMappings(assign.id, undefined, siteId).catch(() => {
// Ignore errors.
}));
} }
subPromises.push(this.prefetchSubmissions(assign, courseId, module.id, userId, siteId)); subPromises.push(this.prefetchSubmissions(assign, courseId, module.id, userId, siteId));
@ -342,9 +344,11 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
if (userSubmission && userSubmission.id) { if (userSubmission && userSubmission.id) {
// Prefetch submission plugins data. // Prefetch submission plugins data.
if (userSubmission.plugins) {
userSubmission.plugins.forEach((plugin) => { userSubmission.plugins.forEach((plugin) => {
promises.push(this.submissionDelegate.prefetch(assign, userSubmission, plugin, siteId)); promises.push(this.submissionDelegate.prefetch(assign, userSubmission, plugin, siteId));
}); });
}
// Get ID of the user who did the submission. // Get ID of the user who did the submission.
if (userSubmission.userid) { if (userSubmission.userid) {
@ -365,10 +369,12 @@ export class AddonModAssignPrefetchHandler extends CoreCourseModulePrefetchHandl
} }
// Prefetch feedback plugins data. // Prefetch feedback plugins data.
if (submission.feedback.plugins) {
submission.feedback.plugins.forEach((plugin) => { submission.feedback.plugins.forEach((plugin) => {
promises.push(this.feedbackDelegate.prefetch(assign, submission, plugin, siteId)); promises.push(this.feedbackDelegate.prefetch(assign, submission, plugin, siteId));
}); });
} }
}
// Prefetch user profiles. // Prefetch user profiles.
promises.push(this.userProvider.prefetchProfiles(userIds, courseId, siteId)); promises.push(this.userProvider.prefetchProfiles(userIds, courseId, siteId));

View File

@ -47,10 +47,10 @@ export class AddonModAssignSubmissionFileComponent extends AddonModAssignSubmiss
this.assignOfflineProvider.getSubmission(this.assign.id).catch(() => { this.assignOfflineProvider.getSubmission(this.assign.id).catch(() => {
// Error getting data, assume there's no offline submission. // Error getting data, assume there's no offline submission.
}).then((offlineData) => { }).then((offlineData) => {
if (offlineData && offlineData.plugindata && offlineData.plugindata.files_filemanager) { if (offlineData && offlineData.pluginData && offlineData.pluginData.files_filemanager) {
// It has offline data. // It has offline data.
let promise; let promise;
if (offlineData.plugindata.files_filemanager.offline) { if (offlineData.pluginData.files_filemanager.offline) {
promise = this.assignHelper.getStoredSubmissionFiles(this.assign.id, promise = this.assignHelper.getStoredSubmissionFiles(this.assign.id,
AddonModAssignSubmissionFileHandler.FOLDER_NAME); AddonModAssignSubmissionFileHandler.FOLDER_NAME);
} else { } else {
@ -58,7 +58,7 @@ export class AddonModAssignSubmissionFileComponent extends AddonModAssignSubmiss
} }
return promise.then((offlineFiles) => { return promise.then((offlineFiles) => {
const onlineFiles = offlineData.plugindata.files_filemanager.online || []; const onlineFiles = offlineData.pluginData.files_filemanager.online || [];
offlineFiles = this.fileUploaderProvider.markOfflineFiles(offlineFiles); offlineFiles = this.fileUploaderProvider.markOfflineFiles(offlineFiles);
this.files = onlineFiles.concat(offlineFiles); this.files = onlineFiles.concat(offlineFiles);

View File

@ -237,9 +237,9 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis
return this.assignOfflineProvider.getSubmission(assign.id, submission.userid).catch(() => { return this.assignOfflineProvider.getSubmission(assign.id, submission.userid).catch(() => {
// No offline data found. // No offline data found.
}).then((offlineData) => { }).then((offlineData) => {
if (offlineData && offlineData.plugindata && offlineData.plugindata.files_filemanager) { if (offlineData && offlineData.pluginData && offlineData.pluginData.files_filemanager) {
// Has offline data, return the number of files. // Has offline data, return the number of files.
return offlineData.plugindata.files_filemanager.offline + offlineData.plugindata.files_filemanager.online.length; return offlineData.pluginData.files_filemanager.offline + offlineData.pluginData.files_filemanager.online.length;
} }
// No offline data, return the number of online files. // No offline data, return the number of online files.
@ -333,7 +333,7 @@ export class AddonModAssignSubmissionFileHandler implements AddonModAssignSubmis
prepareSyncData(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string) prepareSyncData(assign: any, submission: any, plugin: any, offlineData: any, pluginData: any, siteId?: string)
: void | Promise<any> { : void | Promise<any> {
const filesData = offlineData && offlineData.plugindata && offlineData.plugindata.files_filemanager; const filesData = offlineData && offlineData.pluginData && offlineData.pluginData.files_filemanager;
if (filesData) { if (filesData) {
// Has some data to sync. // Has some data to sync.
let files = filesData.online || [], let files = filesData.online || [],

View File

@ -68,8 +68,8 @@ export class AddonModAssignSubmissionOnlineTextComponent extends AddonModAssignS
return this.assignOfflineProvider.getSubmission(this.assign.id).catch(() => { return this.assignOfflineProvider.getSubmission(this.assign.id).catch(() => {
// No offline data found. // No offline data found.
}).then((offlineData) => { }).then((offlineData) => {
if (offlineData && offlineData.plugindata && offlineData.plugindata.onlinetext_editor) { if (offlineData && offlineData.pluginData && offlineData.pluginData.onlinetext_editor) {
return offlineData.plugindata.onlinetext_editor.text; return offlineData.pluginData.onlinetext_editor.text;
} }
// No offline data found, return online text. // No offline data found, return online text.

View File

@ -188,8 +188,8 @@ export class AddonModAssignSubmissionOnlineTextHandler implements AddonModAssign
return this.assignOfflineProvider.getSubmission(assign.id, submission.userid).catch(() => { return this.assignOfflineProvider.getSubmission(assign.id, submission.userid).catch(() => {
// No offline data found. // No offline data found.
}).then((data) => { }).then((data) => {
if (data && data.plugindata && data.plugindata.onlinetext_editor) { if (data && data.pluginData && data.pluginData.onlinetext_editor) {
return data.plugindata.onlinetext_editor.text; return data.pluginData.onlinetext_editor.text;
} }
// No offline data found, get text from plugin. // No offline data found, get text from plugin.

View File

@ -128,12 +128,12 @@ export class CoreCourseModuleComponent implements OnInit, OnDestroy {
this.spinner = true; this.spinner = true;
// Get download size to ask for confirm if it's high. // Get download size to ask for confirm if it's high.
this.prefetchHandler.getDownloadSize(module, this.courseId).then((size) => { this.prefetchHandler.getDownloadSize(this.module, this.courseId).then((size) => {
return this.courseHelper.prefetchModule(this.prefetchHandler, this.module, size, this.courseId, refresh); return this.courseHelper.prefetchModule(this.prefetchHandler, this.module, size, this.courseId, refresh);
}).catch((error) => { }).catch((error) => {
// Error, hide spinner. // Error, hide spinner.
this.spinner = false; this.spinner = false;
if (!this.isDestroyed && error) { if (!this.isDestroyed) {
this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true); this.domUtils.showErrorModalDefault(error, 'core.errordownloading', true);
} }
}); });

View File

@ -426,6 +426,7 @@ export class CoreFileProvider {
return new Promise((resolve, reject): void => { return new Promise((resolve, reject): void => {
const reader = new FileReader(); const reader = new FileReader();
reader.onloadend = (evt): void => { reader.onloadend = (evt): void => {
const target = <any> evt.target; // Convert to <any> to be able to use non-standard properties. const target = <any> evt.target; // Convert to <any> to be able to use non-standard properties.
if (target.result !== undefined || target.result !== null) { if (target.result !== undefined || target.result !== null) {
@ -437,6 +438,18 @@ export class CoreFileProvider {
} }
}; };
// Check if the load starts. If it doesn't start in 3 seconds, reject.
// Sometimes in Android the read doesn't start for some reason, so the promise never finishes.
let hasStarted = false;
reader.onloadstart = (evt): void => {
hasStarted = true;
};
setTimeout(() => {
if (!hasStarted) {
reject();
}
}, 3000);
switch (format) { switch (format) {
case CoreFileProvider.FORMATDATAURL: case CoreFileProvider.FORMATDATAURL:
reader.readAsDataURL(fileData); reader.readAsDataURL(fileData);