Merge pull request #2858 from dpalou/MOBILE-3320

Mobile 3320
main
Pau Ferrer Ocaña 2021-06-30 15:27:23 +02:00 committed by GitHub
commit 709d8bf43b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 47 additions and 33 deletions

View File

@ -270,10 +270,13 @@ export class AddonMessagesGroupConversationsPage implements OnInit, OnDestroy {
async ngOnInit(): Promise<void> { async ngOnInit(): Promise<void> {
this.route.queryParams.subscribe(async (params) => { this.route.queryParams.subscribe(async (params) => {
// When a child page loads this callback is triggered too. // When a child page loads this callback is triggered too.
this.selectedConversationId = const conversationId =CoreNavigator.getRouteNumberParam('conversationId', { params });
CoreNavigator.getRouteNumberParam('conversationId', { params }) ?? this.selectedConversationId; const userId = CoreNavigator.getRouteNumberParam('userId', { params });
this.selectedUserId = if (conversationId || userId) {
CoreNavigator.getRouteNumberParam('userId', { params }) ?? this.selectedUserId; // Update the selected ones.
this.selectedConversationId = conversationId;
this.selectedUserId = userId;
}
}); });
await this.fetchData(); await this.fetchData();

View File

@ -280,9 +280,11 @@
</ion-item> </ion-item>
</ng-container> </ng-container>
<addon-mod-assign-feedback-plugin *ngFor="let plugin of feedback!.plugins" [assign]="assign" <ng-container *ngIf="feedback">
<addon-mod-assign-feedback-plugin *ngFor="let plugin of feedback.plugins" [assign]="assign"
[submission]="userSubmission" [userId]="submitId" [plugin]="plugin" [canEdit]="canSaveGrades"> [submission]="userSubmission" [userId]="submitId" [plugin]="plugin" [canEdit]="canSaveGrades">
</addon-mod-assign-feedback-plugin> </addon-mod-assign-feedback-plugin>
</ng-container>
<!-- Workflow status. --> <!-- Workflow status. -->
<ion-item class="ion-text-wrap" *ngIf="workflowStatusTranslationId"> <ion-item class="ion-text-wrap" *ngIf="workflowStatusTranslationId">
@ -338,7 +340,7 @@
</ion-item> </ion-item>
<!-- Grader is hidden, display only the grade date. --> <!-- Grader is hidden, display only the grade date. -->
<ion-item class="ion-text-wrap" *ngIf="!grader && feedback!.gradeddate"> <ion-item class="ion-text-wrap" *ngIf="!grader && feedback?.gradeddate">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_assign.gradedon' | translate }}</h2> <h2>{{ 'addon.mod_assign.gradedon' | translate }}</h2>
<p>{{ feedback!.gradeddate * 1000 | coreFormatDate }}</p> <p>{{ feedback!.gradeddate * 1000 | coreFormatDate }}</p>

View File

@ -671,8 +671,8 @@ export class AddonModAssignSubmissionComponent implements OnInit, OnDestroy, Can
AddonModAssign.getSubmissionGradingStatusTranslationId(this.grade.gradingStatus); AddonModAssign.getSubmissionGradingStatusTranslationId(this.grade.gradingStatus);
} }
if (this.lastAttempt?.gradingstatus == 'graded' && !this.assign!.markingworkflow) { if (this.lastAttempt?.gradingstatus == 'graded' && !this.assign!.markingworkflow && this.userSubmission && feedback) {
if (this.feedback!.gradeddate < this.lastAttempt!.submission!.timemodified) { if (feedback.gradeddate < this.userSubmission.timemodified) {
this.lastAttempt.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT; this.lastAttempt.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT;
// Get grading text and color. // Get grading text and color.

View File

@ -29,6 +29,7 @@ import {
AddonModAssignSubmission, AddonModAssignSubmission,
AddonModAssignProvider, AddonModAssignProvider,
AddonModAssign, AddonModAssign,
AddonModAssignGrade,
} from '../../services/assign'; } from '../../services/assign';
import { AddonModAssignHelper, AddonModAssignSubmissionFormatted } from '../../services/assign-helper'; import { AddonModAssignHelper, AddonModAssignSubmissionFormatted } from '../../services/assign-helper';
import { AddonModAssignOffline } from '../../services/assign-offline'; import { AddonModAssignOffline } from '../../services/assign-offline';
@ -252,7 +253,10 @@ export class AddonModAssignSubmissionListPage implements AfterViewInit, OnDestro
// Get the last grade of the submission. // Get the last grade of the submission.
const grade = grades const grade = grades
.filter((grade) => grade.userid == submission.userid) .filter((grade) => grade.userid == submission.userid)
.reduce((a, b) => (a.timemodified > b.timemodified ? a : b)); .reduce(
(a, b) => (a && a.timemodified > b.timemodified ? a : b),
<AddonModAssignGrade | undefined> undefined,
);
if (grade && grade.timemodified < submission.timemodified) { if (grade && grade.timemodified < submission.timemodified) {
submission.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT; submission.gradingstatus = AddonModAssignProvider.GRADED_FOLLOWUP_SUBMIT;

View File

@ -1377,6 +1377,8 @@ export class AddonModAssignProvider {
// The WebService returned warnings, reject. // The WebService returned warnings, reject.
throw new CoreWSError(warnings[0]); throw new CoreWSError(warnings[0]);
} }
return;
} }
// WS not available, fallback to save_grade. // WS not available, fallback to save_grade.

View File

@ -458,6 +458,11 @@ export class AddonModAssignPrefetchHandlerService extends CoreCourseActivityPref
userIds.push(userSubmission.userid); userIds.push(userSubmission.userid);
} }
} }
if (assign.teamsubmission && submission.lastattempt.submissiongroup) {
// Prefetch group info.
promises.push(CoreGroups.getActivityAllowedGroups(assign.cmid));
}
} }
// Prefetch grade items. // Prefetch grade items.

View File

@ -190,7 +190,10 @@ export class AddonModLessonOfflineProvider {
const attempts = await this.getRetakeAttemptsForPage(lessonId, retake, retakeData.lastquestionpage, siteId); const attempts = await this.getRetakeAttemptsForPage(lessonId, retake, retakeData.lastquestionpage, siteId);
// Return the attempt with highest timemodified. // Return the attempt with highest timemodified.
return attempts.reduce((a, b) => a.timemodified > b.timemodified ? a : b); return attempts.reduce(
(a, b) => a && a.timemodified > b.timemodified ? a : b,
<AddonModLessonPageAttemptRecord | undefined> undefined,
);
} catch { } catch {
// Error, return undefined. // Error, return undefined.
} }

View File

@ -53,7 +53,7 @@
[access]="access" [assessmentId]="assessmentId" [userId]="profile && profile.id" [strategy]="strategy"> [access]="access" [assessmentId]="assessmentId" [userId]="profile && profile.id" [strategy]="strategy">
</addon-mod-workshop-assessment-strategy> </addon-mod-workshop-assessment-strategy>
<form ion-list [formGroup]="evaluateForm" *ngIf="evaluating" #evaluateFormEl> <form [formGroup]="evaluateForm" *ngIf="evaluating" #evaluateFormEl>
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label><h2>{{ 'addon.mod_workshop.assessmentsettings' | translate }}</h2></ion-label> <ion-label><h2>{{ 'addon.mod_workshop.assessmentsettings' | translate }}</h2></ion-label>
</ion-item> </ion-item>

View File

@ -13,7 +13,7 @@
</ion-header> </ion-header>
<ion-content> <ion-content>
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded">
<form ion-list [formGroup]="editForm" *ngIf="workshop" #editFormEl> <form [formGroup]="editForm" *ngIf="workshop" #editFormEl>
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label position="stacked"> <ion-label position="stacked">
<span core-mark-required="true"> <span core-mark-required="true">

View File

@ -97,7 +97,7 @@
</addon-mod-workshop-assessment> </addon-mod-workshop-assessment>
</ion-list> </ion-list>
<form ion-list [formGroup]="feedbackForm" *ngIf="canAddFeedback && submission" #feedbackFormEl> <form [formGroup]="feedbackForm" *ngIf="canAddFeedback && submission" #feedbackFormEl>
<ion-item class="ion-text-wrap"> <ion-item class="ion-text-wrap">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_workshop.feedbackauthor' | translate }}</h2> <h2>{{ 'addon.mod_workshop.feedbackauthor' | translate }}</h2>

View File

@ -632,7 +632,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
const completionModules = (<CoreCourseModule[]> []) const completionModules = (<CoreCourseModule[]> [])
.concat(...this.sections!.map((section) => section.modules)) .concat(...this.sections!.map((section) => section.modules))
.map((module) => module.completion && module.completion > 0 ? 1 : module.completion) .map((module) => module.completion && module.completion > 0 ? 1 : module.completion)
.reduce((accumulator, currentValue) => (accumulator || 0) + (currentValue || 0)); .reduce((accumulator, currentValue) => (accumulator || 0) + (currentValue || 0), 0);
const moduleProgressPercent = 100 / (completionModules || 1); const moduleProgressPercent = 100 / (completionModules || 1);
// Use min/max here to avoid floating point rounding errors over/under-flowing the progress bar. // Use min/max here to avoid floating point rounding errors over/under-flowing the progress bar.

View File

@ -52,9 +52,8 @@ export class CoreLoginHelperProvider {
static readonly FAQ_QRCODE_IMAGE_HTML = '<img src="assets/img/login/faq_qrcode.png" role="presentation" alt="">'; static readonly FAQ_QRCODE_IMAGE_HTML = '<img src="assets/img/login/faq_qrcode.png" role="presentation" alt="">';
protected logger: CoreLogger; protected logger: CoreLogger;
protected isSSOConfirmShown = false; protected sessionExpiredCheckingSite: Record<string, boolean> = {};
protected isOpenEditAlertShown = false; protected isOpenEditAlertShown = false;
protected isOpeningReconnect = false;
protected waitingForBrowser = false; protected waitingForBrowser = false;
constructor() { constructor() {
@ -885,6 +884,12 @@ export class CoreLoginHelperProvider {
return; // Site that triggered the event is not current site. return; // Site that triggered the event is not current site.
} }
if (this.sessionExpiredCheckingSite[siteId || '']) {
return; // Operation pending.
}
this.sessionExpiredCheckingSite[siteId || ''] = true;
try { try {
// Check authentication method. // Check authentication method.
const result = await CoreSites.checkSite(siteUrl); const result = await CoreSites.checkSite(siteUrl);
@ -895,9 +900,7 @@ export class CoreLoginHelperProvider {
if (this.isSSOLoginNeeded(result.code)) { if (this.isSSOLoginNeeded(result.code)) {
// SSO. User needs to authenticate in a browser. Check if we need to display a message. // SSO. User needs to authenticate in a browser. Check if we need to display a message.
if (!CoreApp.isSSOAuthenticationOngoing() && !this.isSSOConfirmShown && !this.waitingForBrowser) { if (!CoreApp.isSSOAuthenticationOngoing() && !this.waitingForBrowser) {
this.isSSOConfirmShown = true;
try { try {
if (this.shouldShowSSOConfirm(result.code)) { if (this.shouldShowSSOConfirm(result.code)) {
await CoreDomUtils.showConfirm(Translate.instant('core.login.' + await CoreDomUtils.showConfirm(Translate.instant('core.login.' +
@ -917,8 +920,6 @@ export class CoreLoginHelperProvider {
} catch (error) { } catch (error) {
// User cancelled, logout him. // User cancelled, logout him.
CoreSites.logout(); CoreSites.logout();
} finally {
this.isSSOConfirmShown = false;
} }
} }
} else { } else {
@ -932,10 +933,8 @@ export class CoreLoginHelperProvider {
}); });
if (providerToUse) { if (providerToUse) {
if (!CoreApp.isSSOAuthenticationOngoing() && !this.isSSOConfirmShown && !this.waitingForBrowser) { if (!CoreApp.isSSOAuthenticationOngoing() && !this.waitingForBrowser) {
// Open browser to perform the OAuth. // Open browser to perform the OAuth.
this.isSSOConfirmShown = true;
const confirmMessage = Translate.instant('core.login.' + const confirmMessage = Translate.instant('core.login.' +
(currentSite.isLoggedOut() ? 'loggedoutssodescription' : 'reconnectssodescription')); (currentSite.isLoggedOut() ? 'loggedoutssodescription' : 'reconnectssodescription'));
@ -955,8 +954,6 @@ export class CoreLoginHelperProvider {
} catch (error) { } catch (error) {
// User cancelled, logout him. // User cancelled, logout him.
CoreSites.logout(); CoreSites.logout();
} finally {
this.isSSOConfirmShown = false;
} }
} }
@ -965,14 +962,12 @@ export class CoreLoginHelperProvider {
} }
const info = currentSite.getInfo(); const info = currentSite.getInfo();
if (typeof info != 'undefined' && typeof info.username != 'undefined' && !this.isOpeningReconnect) { if (typeof info != 'undefined' && typeof info.username != 'undefined') {
// If current page is already reconnect, stop. // If current page is already reconnect, stop.
if (CoreNavigator.isCurrent('/login/reconnect')) { if (CoreNavigator.isCurrent('/login/reconnect')) {
return; return;
} }
this.isOpeningReconnect = true;
await CoreUtils.ignoreErrors(CoreNavigator.navigate('/login/reconnect', { await CoreUtils.ignoreErrors(CoreNavigator.navigate('/login/reconnect', {
params: { params: {
siteId, siteId,
@ -981,8 +976,6 @@ export class CoreLoginHelperProvider {
}, },
reset: true, reset: true,
})); }));
this.isOpeningReconnect = false;
} }
} }
} catch (error) { } catch (error) {
@ -992,6 +985,8 @@ export class CoreLoginHelperProvider {
CoreDomUtils.showErrorModalDefault(error, 'core.networkerrormsg', true); CoreDomUtils.showErrorModalDefault(error, 'core.networkerrormsg', true);
CoreSites.logout(); CoreSites.logout();
} }
} finally {
this.sessionExpiredCheckingSite[siteId || ''] = false;
} }
} }