Merge pull request #2834 from dpalou/MOBILE-3320

Mobile 3320
main
Pau Ferrer Ocaña 2021-06-16 16:34:33 +02:00 committed by GitHub
commit a680aba66b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 108 additions and 32 deletions

View File

@ -74,7 +74,7 @@
</ion-select> </ion-select>
</ion-item> </ion-item>
<ion-item class="ion-text-wrap" (click)="openRespondents()" [detail]="access.canviewreports && completedCount > 0" <ion-item class="ion-text-wrap" (click)="openRespondents()" [detail]="access.canviewreports && completedCount > 0"
button> [button]="access.canviewreports && completedCount > 0">
<ion-label> <ion-label>
<h2>{{ 'addon.mod_feedback.completed_feedbacks' | translate }}</h2> <h2>{{ 'addon.mod_feedback.completed_feedbacks' | translate }}</h2>
</ion-label> </ion-label>

View File

@ -154,8 +154,8 @@
</ion-item> </ion-item>
</ion-card> </ion-card>
<ion-card> <ion-card *ngIf="completed">
<ion-grid *ngIf="completed"> <ion-grid>
<ion-row class="ion-align-items-center"> <ion-row class="ion-align-items-center">
<ion-col *ngIf="access!.canviewanalysis"> <ion-col *ngIf="access!.canviewanalysis">
<ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap"> <ion-button expand="block" fill="outline" (click)="showAnalysis()" class="ion-text-wrap">

View File

@ -172,11 +172,12 @@ export class AddonModFeedbackProvider {
return array.concat(responses); return array.concat(responses);
}, <OfflineResponsesArray> []).map((valueEntry) => { }, <OfflineResponsesArray> []).map((valueEntry) => {
const parts = valueEntry.id.split('_'); const parts = valueEntry.id.split('_');
const item = (parts[1] || '').replace(/\[.*\]/, ''); // Remove [0] and similar.
return { return {
...valueEntry, ...valueEntry,
typ: parts[0], typ: parts[0],
item: Number(parts[1]), item: Number(item),
}; };
}); });

View File

@ -93,9 +93,7 @@ export class AddonModFeedbackPrefetchHandlerService extends CoreCourseActivityPr
* @inheritdoc * @inheritdoc
*/ */
async isDownloadable(module: CoreCourseAnyModuleData, courseId: number): Promise<boolean> { async isDownloadable(module: CoreCourseAnyModuleData, courseId: number): Promise<boolean> {
const feedback = await AddonModFeedback.getFeedback(courseId, module.id, { const feedback = await AddonModFeedback.getFeedback(courseId, module.id);
readingStrategy: CoreSitesReadingStrategy.PREFER_CACHE,
});
const now = CoreTimeUtils.timestamp(); const now = CoreTimeUtils.timestamp();

View File

@ -80,6 +80,7 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
hasOffline = false; hasOffline = false;
isOpeningPage = false; isOpeningPage = false;
protected listeningResize = false;
protected fetchContentDefaultError = 'addon.mod_h5pactivity.errorgetactivity'; protected fetchContentDefaultError = 'addon.mod_h5pactivity.errorgetactivity';
protected syncEventName = AddonModH5PActivitySyncProvider.AUTO_SYNCED; protected syncEventName = AddonModH5PActivitySyncProvider.AUTO_SYNCED;
protected site: CoreSite; protected site: CoreSite;
@ -372,8 +373,7 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata); CoreCourse.checkModuleCompletion(this.courseId, this.module.completiondata);
window.addEventListener('resize', this.contentResized.bind(this)); this.setResizeListener();
this.contentResized();
} }
/** /**
@ -488,6 +488,19 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
} }
} }
/**
* Set the resize listener if needed.
*/
setResizeListener(): void {
if (!this.playing || this.listeningResize) {
return;
}
this.listeningResize = true;
window.addEventListener('resize', this.contentResized.bind(this));
this.contentResized();
}
/** /**
* On content resize, change visibility of the main menu: show on portrait and hide on landscape. * On content resize, change visibility of the main menu: show on portrait and hide on landscape.
*/ */
@ -495,6 +508,25 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
this.mainMenuPage.changeVisibility(Platform.isPortrait()); this.mainMenuPage.changeVisibility(Platform.isPortrait());
} }
/**
* @inheritdoc
*/
ionViewDidEnter(): void {
this.setResizeListener();
}
/**
* @inheritdoc
*/
ionViewWillLeave(): void {
this.mainMenuPage.changeVisibility(true);
if (this.listeningResize) {
this.listeningResize = false;
window.removeEventListener('resize', this.resizeFunction);
}
}
/** /**
* Component destroyed. * Component destroyed.
*/ */
@ -503,10 +535,6 @@ export class AddonModH5PActivityIndexComponent extends CoreCourseModuleMainActiv
this.observer?.off(); this.observer?.off();
window.removeEventListener('message', this.messageListenerFunction); window.removeEventListener('message', this.messageListenerFunction);
if (this.playing) {
window.removeEventListener('resize', this.resizeFunction);
}
} }
} }

View File

@ -470,13 +470,13 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
/** /**
* Review the lesson. * Review the lesson.
*/ */
review(): void { async review(): Promise<void> {
if (!this.retakeToReview || !this.lesson) { if (!this.retakeToReview || !this.lesson) {
// No retake to review, stop. // No retake to review, stop.
return; return;
} }
CoreNavigator.navigateToSitePath( await CoreNavigator.navigateToSitePath(
`${AddonModLessonModuleHandlerService.PAGE_NAME}/${this.courseId}/${this.module.id}/player`, `${AddonModLessonModuleHandlerService.PAGE_NAME}/${this.courseId}/${this.module.id}/player`,
{ {
params: { params: {
@ -487,6 +487,8 @@ export class AddonModLessonIndexComponent extends CoreCourseModuleMainActivityCo
}, },
}, },
); );
this.retakeToReview = undefined;
} }
/** /**

View File

@ -186,13 +186,14 @@
</ion-list> </ion-list>
<!-- End of lesson reached. --> <!-- End of lesson reached. -->
<ion-card class="core-warning-card" *ngIf="eolData && !processData && eolData.offline?.value">
<ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_lesson.finishretakeoffline' | translate }}</ion-label>
</ion-item>
</ion-card>
<ion-card *ngIf="eolData && !processData"> <ion-card *ngIf="eolData && !processData">
<div class="core-warning-card" *ngIf="eolData.offline?.value">
<ion-item>
<ion-icon name="fas-exclamation-triangle" slot="start" aria-hidden="true"></ion-icon>
<ion-label>{{ 'addon.mod_lesson.finishretakeoffline' | translate }}</ion-label>
</ion-item>
</div>
<ion-card-header class="ion-text-wrap" *ngIf="eolData.gradelesson"> <ion-card-header class="ion-text-wrap" *ngIf="eolData.gradelesson">
<ion-card-title>{{ 'addon.mod_lesson.congratulations' | translate }}</ion-card-title> <ion-card-title>{{ 'addon.mod_lesson.congratulations' | translate }}</ion-card-title>

View File

@ -272,8 +272,7 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave {
// If lesson has offline data already, use offline mode. // If lesson has offline data already, use offline mode.
this.offline = await AddonModLessonOffline.hasOfflineData(this.lesson.id); this.offline = await AddonModLessonOffline.hasOfflineData(this.lesson.id);
if (!this.offline && !CoreApp.isOnline() && AddonModLesson.isLessonOffline(this.lesson) && if (!this.offline && !CoreApp.isOnline() && AddonModLesson.isLessonOffline(this.lesson) && !this.review) {
!this.review) {
// Lesson doesn't have offline data, but it allows offline and the device is offline. Use offline mode. // Lesson doesn't have offline data, but it allows offline and the device is offline. Use offline mode.
this.offline = true; this.offline = true;
} }
@ -586,11 +585,12 @@ export class AddonModLessonPlayerPage implements OnInit, OnDestroy, CanLeave {
this.originalData = undefined; this.originalData = undefined;
} }
if (data.displaymenu && !this.displayMenu) { // Don't display the navigation menu in review mode, using them displays errors.
if (data.displaymenu && !this.displayMenu && !this.review) {
// Load the menu. // Load the menu.
this.loadMenu(); this.loadMenu();
} }
this.displayMenu = !!data.displaymenu; this.displayMenu = !this.review && !!data.displaymenu;
if (!this.firstPageLoaded) { if (!this.firstPageLoaded) {
this.firstPageLoaded = true; this.firstPageLoaded = true;

View File

@ -18,7 +18,7 @@
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
<core-loading [hideUntil]="loaded"> <core-loading [hideUntil]="loaded" class="core-loading-fullheight">
<core-navigation-bar [previous]="previousSco" [next]="nextSco" (action)="loadSco($event)"></core-navigation-bar> <core-navigation-bar [previous]="previousSco" [next]="nextSco" (action)="loadSco($event)"></core-navigation-bar>
<core-iframe *ngIf="loaded && src" [src]="src" [iframeWidth]="scormWidth" [iframeHeight]="scormHeight"></core-iframe> <core-iframe *ngIf="loaded && src" [src]="src" [iframeWidth]="scormWidth" [iframeHeight]="scormHeight"></core-iframe>

View File

@ -533,6 +533,22 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
})); }));
} }
/**
* @inheritdoc
*/
ionViewDidEnter(): void {
if (this.scorm && this.scorm.popup) {
this.mainMenuPage.changeVisibility(false);
}
}
/**
* @inheritdoc
*/
ionViewWillLeave(): void {
this.mainMenuPage.changeVisibility(true);
}
/** /**
* Component being destroyed. * Component being destroyed.
*/ */
@ -549,8 +565,6 @@ export class AddonModScormPlayerPage implements OnInit, OnDestroy {
this.goOfflineObserver?.off(); this.goOfflineObserver?.off();
}, 500); }, 500);
this.mainMenuPage.changeVisibility(true);
// Unblock the SCORM so it can be synced. // Unblock the SCORM so it can be synced.
CoreSync.unblockOperation(AddonModScormProvider.COMPONENT, this.scorm.id, 'player'); CoreSync.unblockOperation(AddonModScormProvider.COMPONENT, this.scorm.id, 'player');
} }

View File

@ -345,6 +345,8 @@ export class AddonModWorkshopSyncProvider extends CoreSyncBaseProvider<AddonModW
attachmentsId, attachmentsId,
siteId, siteId,
); );
break;
case AddonModWorkshopAction.UPDATE: case AddonModWorkshopAction.UPDATE:
await AddonModWorkshop.updateSubmissionOnline( await AddonModWorkshop.updateSubmissionOnline(
submissionId, submissionId,
@ -353,6 +355,8 @@ export class AddonModWorkshopSyncProvider extends CoreSyncBaseProvider<AddonModW
attachmentsId, attachmentsId,
siteId, siteId,
); );
break;
case AddonModWorkshopAction.DELETE: case AddonModWorkshopAction.DELETE:
await AddonModWorkshop.deleteSubmissionOnline(submissionId, siteId); await AddonModWorkshop.deleteSubmissionOnline(submissionId, siteId);
} }

View File

@ -51,8 +51,8 @@
@include margin(10px, 0, 0, 0); @include margin(10px, 0, 0, 0);
} }
&.core-loading-noheight .core-loading-content { &.core-loading-fullheight .core-loading-content {
height: auto; height: 100%;
} }
&.core-loading-loaded { &.core-loading-loaded {

View File

@ -64,4 +64,18 @@ export class CoreCourseModuleMainActivityPage<ActivityType extends CoreCourseMod
this.activityComponent?.ionViewDidLeave(); this.activityComponent?.ionViewDidLeave();
} }
/**
* User will enter the page.
*/
ionViewWillEnter(): void {
this.activityComponent?.ionViewWillEnter();
}
/**
* User will leave the page.
*/
ionViewWillLeave(): void {
this.activityComponent?.ionViewWillLeave();
}
} }

View File

@ -452,4 +452,18 @@ export class CoreCourseModuleMainResourceComponent implements OnInit, OnDestroy,
this.isCurrentView = false; this.isCurrentView = false;
} }
/**
* User will enter the page that contains the component. This function should be called by the page that contains the component.
*/
ionViewWillEnter(): void {
// To be overridden.
}
/**
* User will leave the page that contains the component. This function should be called by the page that contains the component.
*/
ionViewWillLeave(): void {
// To be overridden.
}
} }

View File

@ -9,7 +9,7 @@
</ion-toolbar> </ion-toolbar>
</ion-header> </ion-header>
<ion-content> <ion-content>
<core-loading [hideUntil]="readyToCapture"> <core-loading [hideUntil]="readyToCapture" class="core-loading-fullheight">
<div class="core-av-wrapper"> <div class="core-av-wrapper">
<!-- Video stream for image and video. --> <!-- Video stream for image and video. -->
<video *ngIf="!isAudio" [hidden]="hasCaptured" class="core-webcam-stream" autoplay #streamVideo></video> <video *ngIf="!isAudio" [hidden]="hasCaptured" class="core-webcam-stream" autoplay #streamVideo></video>

View File

@ -72,7 +72,7 @@ export class CoreH5PIframeComponent implements OnChanges, OnDestroy {
this.subscription = router.events this.subscription = router.events
.pipe(filter(event => event instanceof NavigationEnd)) .pipe(filter(event => event instanceof NavigationEnd))
.subscribe((event: NavigationEnd) => { .subscribe((event: NavigationEnd) => {
if (!this.iframeLoadedOnce || event.urlAfterRedirects == this.currentPageRoute) { if (!this.iframeLoadedOnce || event.urlAfterRedirects !== this.currentPageRoute) {
return; return;
} }