commit
d241e1d253
|
@ -154,6 +154,11 @@ export class AddonModQuizPrefetchHandler extends CoreCourseModulePrefetchHandler
|
||||||
* @return {boolean|Promise<boolean>} Whether the module can be downloaded. The promise should never be rejected.
|
* @return {boolean|Promise<boolean>} Whether the module can be downloaded. The promise should never be rejected.
|
||||||
*/
|
*/
|
||||||
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
isDownloadable(module: any, courseId: number): boolean | Promise<boolean> {
|
||||||
|
if (this.sitesProvider.getCurrentSite().isOfflineDisabled()) {
|
||||||
|
// Don't allow downloading the quiz if offline is disabled to prevent wasting a lot of data when opening it.
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const siteId = this.sitesProvider.getCurrentSiteId();
|
const siteId = this.sitesProvider.getCurrentSiteId();
|
||||||
|
|
||||||
return this.quizProvider.getQuiz(courseId, module.id, false, siteId).then((quiz) => {
|
return this.quizProvider.getQuiz(courseId, module.id, false, siteId).then((quiz) => {
|
||||||
|
|
|
@ -1492,7 +1492,8 @@ export class AddonModQuizProvider {
|
||||||
* @return {boolean} Whether offline is enabled.
|
* @return {boolean} Whether offline is enabled.
|
||||||
*/
|
*/
|
||||||
isQuizOffline(quiz: any): boolean {
|
isQuizOffline(quiz: any): boolean {
|
||||||
return !!quiz.allowofflineattempts;
|
// Don't allow downloading the quiz if offline is disabled to prevent wasting a lot of data when opening it.
|
||||||
|
return !!quiz.allowofflineattempts && !this.sitesProvider.getCurrentSite().isOfflineDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,6 +16,7 @@ import { NgModule } from '@angular/core';
|
||||||
import { AddonRemoteThemesProvider } from './providers/remotethemes';
|
import { AddonRemoteThemesProvider } from './providers/remotethemes';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreInitDelegate } from '@providers/init';
|
import { CoreInitDelegate } from '@providers/init';
|
||||||
|
import { CoreLoggerProvider } from '@providers/logger';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
|
@ -29,7 +30,9 @@ import { CoreSitesProvider } from '@providers/sites';
|
||||||
})
|
})
|
||||||
export class AddonRemoteThemesModule {
|
export class AddonRemoteThemesModule {
|
||||||
constructor(initDelegate: CoreInitDelegate, remoteThemesProvider: AddonRemoteThemesProvider, eventsProvider: CoreEventsProvider,
|
constructor(initDelegate: CoreInitDelegate, remoteThemesProvider: AddonRemoteThemesProvider, eventsProvider: CoreEventsProvider,
|
||||||
sitesProvider: CoreSitesProvider) {
|
sitesProvider: CoreSitesProvider, loggerProvider: CoreLoggerProvider) {
|
||||||
|
|
||||||
|
const logger = loggerProvider.getInstance('AddonRemoteThemesModule');
|
||||||
|
|
||||||
// Preload the current site styles.
|
// Preload the current site styles.
|
||||||
initDelegate.registerProcess({
|
initDelegate.registerProcess({
|
||||||
|
@ -53,7 +56,9 @@ export class AddonRemoteThemesModule {
|
||||||
eventsProvider.on(CoreEventsProvider.SITE_ADDED, (data) => {
|
eventsProvider.on(CoreEventsProvider.SITE_ADDED, (data) => {
|
||||||
addingSite = data.siteId;
|
addingSite = data.siteId;
|
||||||
|
|
||||||
remoteThemesProvider.addSite(data.siteId).finally(() => {
|
remoteThemesProvider.addSite(data.siteId).catch((error) => {
|
||||||
|
logger.error('Error adding site', error);
|
||||||
|
}).then(() => {
|
||||||
if (addingSite == data.siteId) {
|
if (addingSite == data.siteId) {
|
||||||
addingSite = false;
|
addingSite = false;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +73,9 @@ export class AddonRemoteThemesModule {
|
||||||
// Update styles when current site is updated.
|
// Update styles when current site is updated.
|
||||||
eventsProvider.on(CoreEventsProvider.SITE_UPDATED, (data) => {
|
eventsProvider.on(CoreEventsProvider.SITE_UPDATED, (data) => {
|
||||||
if (data.siteId === sitesProvider.getCurrentSiteId()) {
|
if (data.siteId === sitesProvider.getCurrentSiteId()) {
|
||||||
remoteThemesProvider.load(data.siteId);
|
remoteThemesProvider.load(data.siteId).catch((error) => {
|
||||||
|
logger.error('Error loading site after site update', error);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,7 @@ export class CoreSite {
|
||||||
protected db: SQLiteDB;
|
protected db: SQLiteDB;
|
||||||
protected cleanUnicode = false;
|
protected cleanUnicode = false;
|
||||||
protected lastAutoLogin = 0;
|
protected lastAutoLogin = 0;
|
||||||
|
protected offlineDisabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a site.
|
* Create a site.
|
||||||
|
@ -234,6 +235,7 @@ export class CoreSite {
|
||||||
this.wsProvider = injector.get(CoreWSProvider);
|
this.wsProvider = injector.get(CoreWSProvider);
|
||||||
|
|
||||||
this.logger = logger.getInstance('CoreWSProvider');
|
this.logger = logger.getInstance('CoreWSProvider');
|
||||||
|
this.calculateOfflineDisabled();
|
||||||
|
|
||||||
if (this.id) {
|
if (this.id) {
|
||||||
this.initDB();
|
this.initDB();
|
||||||
|
@ -376,6 +378,7 @@ export class CoreSite {
|
||||||
setConfig(config: any): void {
|
setConfig(config: any): void {
|
||||||
config.tool_mobile_disabledfeatures = this.textUtils.treatDisabledFeatures(config.tool_mobile_disabledfeatures);
|
config.tool_mobile_disabledfeatures = this.textUtils.treatDisabledFeatures(config.tool_mobile_disabledfeatures);
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.calculateOfflineDisabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -530,6 +533,10 @@ export class CoreSite {
|
||||||
const initialToken = this.token;
|
const initialToken = this.token;
|
||||||
data = data || {};
|
data = data || {};
|
||||||
|
|
||||||
|
if (!this.appProvider.isOnline() && this.offlineDisabled) {
|
||||||
|
return Promise.reject(this.wsProvider.createFakeWSError('core.errorofflinedisabled', true));
|
||||||
|
}
|
||||||
|
|
||||||
// Check if the method is available, use a prefixed version if possible.
|
// Check if the method is available, use a prefixed version if possible.
|
||||||
// We ignore this check when we do not have the site info, as the list of functions is not loaded yet.
|
// We ignore this check when we do not have the site info, as the list of functions is not loaded yet.
|
||||||
if (this.getInfo() && !this.wsAvailable(method, false)) {
|
if (this.getInfo() && !this.wsAvailable(method, false)) {
|
||||||
|
@ -560,6 +567,13 @@ export class CoreSite {
|
||||||
wsPreSets.cleanUnicode = false;
|
wsPreSets.cleanUnicode = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.offlineDisabled) {
|
||||||
|
// Offline is disabled, don't use cache.
|
||||||
|
preSets.getFromCache = false;
|
||||||
|
preSets.saveToCache = false;
|
||||||
|
preSets.emergencyCache = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Enable text filtering by default.
|
// Enable text filtering by default.
|
||||||
data.moodlewssettingfilter = preSets.filter === false ? false : true;
|
data.moodlewssettingfilter = preSets.filter === false ? false : true;
|
||||||
data.moodlewssettingfileurl = preSets.rewriteurls === false ? false : true;
|
data.moodlewssettingfileurl = preSets.rewriteurls === false ? false : true;
|
||||||
|
@ -1351,6 +1365,22 @@ export class CoreSite {
|
||||||
return !!disabledFeatures.match(regEx);
|
return !!disabledFeatures.match(regEx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate if offline is disabled in the site.
|
||||||
|
*/
|
||||||
|
calculateOfflineDisabled(): void {
|
||||||
|
this.offlineDisabled = this.isFeatureDisabled('NoDelegate_CoreOffline');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get whether offline is disabled in the site.
|
||||||
|
*
|
||||||
|
* @return {boolean} Whether it's disabled.
|
||||||
|
*/
|
||||||
|
isOfflineDisabled(): boolean {
|
||||||
|
return this.offlineDisabled;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the site version is greater than one or several versions.
|
* Check if the site version is greater than one or several versions.
|
||||||
* This function accepts a string or an array of strings. If array, the last version must be the highest.
|
* This function accepts a string or an array of strings. If array, the last version must be the highest.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<core-navbar-buttons>
|
<core-navbar-buttons>
|
||||||
<core-context-menu>
|
<core-context-menu>
|
||||||
<core-context-menu-item *ngIf="displayEnableDownload" [priority]="2000" [content]="'core.settings.enabledownloadsection' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item>
|
<core-context-menu-item *ngIf="displayEnableDownload" [priority]="2000" [content]="'core.settings.enabledownloadsection' | translate" (action)="toggleDownload()" [iconAction]="downloadEnabledIcon"></core-context-menu-item>
|
||||||
<core-context-menu-item [priority]="1900" [content]="prefetchCourseData.title | translate" (action)="prefetchCourse()" [iconAction]="prefetchCourseData.prefetchCourseIcon" [closeOnClick]="false"></core-context-menu-item>
|
<core-context-menu-item [hidden]="!downloadCourseEnabled" [priority]="1900" [content]="prefetchCourseData.title | translate" (action)="prefetchCourse()" [iconAction]="prefetchCourseData.prefetchCourseIcon" [closeOnClick]="false"></core-context-menu-item>
|
||||||
</core-context-menu>
|
</core-context-menu>
|
||||||
</core-navbar-buttons>
|
</core-navbar-buttons>
|
||||||
<ion-content>
|
<ion-content>
|
||||||
|
|
|
@ -52,6 +52,7 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
prefetchCourseIcon: 'spinner',
|
prefetchCourseIcon: 'spinner',
|
||||||
title: 'core.course.downloadcourse'
|
title: 'core.course.downloadcourse'
|
||||||
};
|
};
|
||||||
|
downloadCourseEnabled: boolean;
|
||||||
moduleId: number;
|
moduleId: number;
|
||||||
displayEnableDownload: boolean;
|
displayEnableDownload: boolean;
|
||||||
displayRefresher: boolean;
|
displayRefresher: boolean;
|
||||||
|
@ -75,6 +76,7 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
// Get the title to display. We dont't have sections yet.
|
// Get the title to display. We dont't have sections yet.
|
||||||
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
this.title = courseFormatDelegate.getCourseTitle(this.course);
|
||||||
this.displayEnableDownload = courseFormatDelegate.displayEnableDownload(this.course);
|
this.displayEnableDownload = courseFormatDelegate.displayEnableDownload(this.course);
|
||||||
|
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||||
|
|
||||||
this.completionObserver = eventsProvider.on(CoreEventsProvider.COMPLETION_MODULE_VIEWED, (data) => {
|
this.completionObserver = eventsProvider.on(CoreEventsProvider.COMPLETION_MODULE_VIEWED, (data) => {
|
||||||
if (data && data.courseId == this.course.id) {
|
if (data && data.courseId == this.course.id) {
|
||||||
|
@ -82,12 +84,14 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Listen for changes in course status.
|
if (this.downloadCourseEnabled) {
|
||||||
this.courseStatusObserver = eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => {
|
// Listen for changes in course status.
|
||||||
if (data.courseId == this.course.id) {
|
this.courseStatusObserver = eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => {
|
||||||
this.updateCourseStatus(data.status);
|
if (data.courseId == this.course.id) {
|
||||||
}
|
this.updateCourseStatus(data.status);
|
||||||
}, sitesProvider.getCurrentSiteId());
|
}
|
||||||
|
}, sitesProvider.getCurrentSiteId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -103,6 +107,11 @@ export class CoreCourseSectionPage implements OnDestroy {
|
||||||
this.loadData().finally(() => {
|
this.loadData().finally(() => {
|
||||||
this.dataLoaded = true;
|
this.dataLoaded = true;
|
||||||
|
|
||||||
|
if (!this.downloadCourseEnabled) {
|
||||||
|
// Cannot download the whole course, stop.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine the course prefetch status.
|
// Determine the course prefetch status.
|
||||||
this.determineCoursePrefetchIcon().then(() => {
|
this.determineCoursePrefetchIcon().then(() => {
|
||||||
if (this.prefetchCourseData.prefetchCourseIcon == 'spinner') {
|
if (this.prefetchCourseData.prefetchCourseIcon == 'spinner') {
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
<ion-item tappable text-wrap detail-none (click)="openCourse(course)" [title]="course.fullname" class="core-course-link">
|
<ion-item tappable text-wrap detail-none (click)="openCourse(course)" [title]="course.fullname" class="core-course-link">
|
||||||
<h2><core-format-text [text]="course.fullname"></core-format-text></h2>
|
<h2><core-format-text [text]="course.fullname"></core-format-text></h2>
|
||||||
|
|
||||||
<div class="core-button-spinner">
|
<div class="core-button-spinner" *ngIf="downloadCourseEnabled">
|
||||||
<!-- Download course. -->
|
<!-- Download course. -->
|
||||||
<button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourse($event)" [attr.aria-label]="prefetchCourseData.title | translate">
|
<button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourse($event)" [attr.aria-label]="prefetchCourseData.title | translate">
|
||||||
<ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon>
|
<ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon>
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { NavController } from 'ionic-angular';
|
||||||
import { CoreEventsProvider } from '@providers/events';
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
|
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
||||||
import { CoreCourseFormatDelegate } from '@core/course/providers/format-delegate';
|
import { CoreCourseFormatDelegate } from '@core/course/providers/format-delegate';
|
||||||
import { CoreCourseProvider } from '@core/course/providers/course';
|
import { CoreCourseProvider } from '@core/course/providers/course';
|
||||||
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
import { CoreCourseHelperProvider } from '@core/course/providers/helper';
|
||||||
|
@ -41,25 +42,56 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
prefetchCourseIcon: 'spinner',
|
prefetchCourseIcon: 'spinner',
|
||||||
title: 'core.course.downloadcourse'
|
title: 'core.course.downloadcourse'
|
||||||
};
|
};
|
||||||
|
downloadCourseEnabled: boolean;
|
||||||
|
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
protected courseStatusObserver;
|
protected courseStatusObserver;
|
||||||
|
protected siteUpdatedObserver;
|
||||||
|
|
||||||
constructor(@Optional() private navCtrl: NavController, private courseHelper: CoreCourseHelperProvider,
|
constructor(@Optional() private navCtrl: NavController, private courseHelper: CoreCourseHelperProvider,
|
||||||
private courseFormatDelegate: CoreCourseFormatDelegate, private domUtils: CoreDomUtilsProvider,
|
private courseFormatDelegate: CoreCourseFormatDelegate, private domUtils: CoreDomUtilsProvider,
|
||||||
private courseProvider: CoreCourseProvider, eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider) {
|
private courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
|
||||||
// Listen for status change in course.
|
private sitesProvider: CoreSitesProvider, private coursesProvider: CoreCoursesProvider) { }
|
||||||
this.courseStatusObserver = eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => {
|
|
||||||
if (data.courseId == this.course.id) {
|
|
||||||
this.updateCourseStatus(data.status);
|
|
||||||
}
|
|
||||||
}, sitesProvider.getCurrentSiteId());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Component being initialized.
|
||||||
*/
|
*/
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||||
|
|
||||||
|
if (this.downloadCourseEnabled) {
|
||||||
|
this.initPrefetchCourse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh the enabled flag if site is updated.
|
||||||
|
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
||||||
|
const wasEnabled = this.downloadCourseEnabled;
|
||||||
|
|
||||||
|
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||||
|
|
||||||
|
if (!wasEnabled && this.downloadCourseEnabled) {
|
||||||
|
// Download course is enabled now, initialize it.
|
||||||
|
this.initPrefetchCourse();
|
||||||
|
}
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize prefetch course.
|
||||||
|
*/
|
||||||
|
initPrefetchCourse(): void {
|
||||||
|
if (typeof this.courseStatusObserver != 'undefined') {
|
||||||
|
// Already initialized.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen for status change in course.
|
||||||
|
this.courseStatusObserver = this.eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => {
|
||||||
|
if (data.courseId == this.course.id) {
|
||||||
|
this.updateCourseStatus(data.status);
|
||||||
|
}
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
// Determine course prefetch icon.
|
// Determine course prefetch icon.
|
||||||
this.courseHelper.getCourseStatusIconAndTitle(this.course.id).then((data) => {
|
this.courseHelper.getCourseStatusIconAndTitle(this.course.id).then((data) => {
|
||||||
this.prefetchCourseData.prefetchCourseIcon = data.icon;
|
this.prefetchCourseData.prefetchCourseIcon = data.icon;
|
||||||
|
@ -81,6 +113,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -126,8 +159,7 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.isDestroyed = true;
|
this.isDestroyed = true;
|
||||||
|
|
||||||
if (this.courseStatusObserver) {
|
this.siteUpdatedObserver && this.siteUpdatedObserver.off();
|
||||||
this.courseStatusObserver.off();
|
this.courseStatusObserver && this.courseStatusObserver.off();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,7 +41,7 @@
|
||||||
<ion-item *ngIf="!isEnrolled && !selfEnrolInstances.length && !paypalEnabled">
|
<ion-item *ngIf="!isEnrolled && !selfEnrolInstances.length && !paypalEnabled">
|
||||||
<p>{{ 'core.courses.notenrollable' | translate }}</p>
|
<p>{{ 'core.courses.notenrollable' | translate }}</p>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<a ion-item *ngIf="canAccessCourse" (click)="prefetchCourse()" detail-none [attr.aria-label]="prefetchCourseData.title | translate">
|
<a ion-item *ngIf="canAccessCourse && downloadCourseEnabled" (click)="prefetchCourse()" detail-none [attr.aria-label]="prefetchCourseData.title | translate">
|
||||||
<ion-icon *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" [name]="prefetchCourseData.prefetchCourseIcon" item-start></ion-icon>
|
<ion-icon *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" [name]="prefetchCourseData.prefetchCourseIcon" item-start></ion-icon>
|
||||||
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" item-start></ion-spinner>
|
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" item-start></ion-spinner>
|
||||||
<h2>{{ 'core.course.downloadcourse' | translate }}</h2>
|
<h2>{{ 'core.course.downloadcourse' | translate }}</h2>
|
||||||
|
|
|
@ -45,6 +45,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
|
||||||
prefetchCourseIcon: 'spinner',
|
prefetchCourseIcon: 'spinner',
|
||||||
title: 'core.course.downloadcourse'
|
title: 'core.course.downloadcourse'
|
||||||
};
|
};
|
||||||
|
downloadCourseEnabled: boolean;
|
||||||
|
|
||||||
protected guestWSAvailable: boolean;
|
protected guestWSAvailable: boolean;
|
||||||
protected isGuestEnabled = false;
|
protected isGuestEnabled = false;
|
||||||
|
@ -67,16 +68,20 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
|
||||||
private translate: TranslateService, private eventsProvider: CoreEventsProvider,
|
private translate: TranslateService, private eventsProvider: CoreEventsProvider,
|
||||||
private courseOptionsDelegate: CoreCourseOptionsDelegate, private courseHelper: CoreCourseHelperProvider,
|
private courseOptionsDelegate: CoreCourseOptionsDelegate, private courseHelper: CoreCourseHelperProvider,
|
||||||
private courseProvider: CoreCourseProvider) {
|
private courseProvider: CoreCourseProvider) {
|
||||||
|
|
||||||
this.course = navParams.get('course');
|
this.course = navParams.get('course');
|
||||||
this.isMobile = appProvider.isMobile();
|
this.isMobile = appProvider.isMobile();
|
||||||
this.isDesktop = appProvider.isDesktop();
|
this.isDesktop = appProvider.isDesktop();
|
||||||
|
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||||
|
|
||||||
// Listen for status change in course.
|
if (this.downloadCourseEnabled) {
|
||||||
this.courseStatusObserver = eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => {
|
// Listen for status change in course.
|
||||||
if (data.courseId == this.course.id) {
|
this.courseStatusObserver = this.eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => {
|
||||||
this.updateCourseStatus(data.status);
|
if (data.courseId == this.course.id) {
|
||||||
}
|
this.updateCourseStatus(data.status);
|
||||||
}, sitesProvider.getCurrentSiteId());
|
}
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,6 +106,11 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
|
||||||
});
|
});
|
||||||
|
|
||||||
this.getCourse().finally(() => {
|
this.getCourse().finally(() => {
|
||||||
|
if (!this.downloadCourseEnabled) {
|
||||||
|
// Cannot download the whole course, stop.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Determine course prefetch icon.
|
// Determine course prefetch icon.
|
||||||
this.courseHelper.getCourseStatusIconAndTitle(this.course.id).then((data) => {
|
this.courseHelper.getCourseStatusIconAndTitle(this.course.id).then((data) => {
|
||||||
this.prefetchCourseData.prefetchCourseIcon = data.icon;
|
this.prefetchCourseData.prefetchCourseIcon = data.icon;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<ion-icon name="search"></ion-icon>
|
<ion-icon name="search"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
<core-context-menu>
|
<core-context-menu>
|
||||||
<core-context-menu-item [hidden]="!courses || courses.length < 2" [priority]="800" [content]="'core.courses.downloadcourses' | translate" (action)="prefetchCourses()" [iconAction]="prefetchCoursesData.icon" [closeOnClick]="false" [badge]="prefetchCoursesData.badge"></core-context-menu-item>
|
<core-context-menu-item [hidden]="!downloadAllCoursesEnabled || !courses || courses.length < 2" [priority]="800" [content]="'core.courses.downloadcourses' | translate" (action)="prefetchCourses()" [iconAction]="prefetchCoursesData.icon" [closeOnClick]="false" [badge]="prefetchCoursesData.badge"></core-context-menu-item>
|
||||||
<core-context-menu-item [hidden]="!courses || courses.length <= 5" [priority]="700" [content]="'core.courses.filtermycourses' | translate" (action)="switchFilter()" [iconAction]="'funnel'"></core-context-menu-item>
|
<core-context-menu-item [hidden]="!courses || courses.length <= 5" [priority]="700" [content]="'core.courses.filtermycourses' | translate" (action)="switchFilter()" [iconAction]="'funnel'"></core-context-menu-item>
|
||||||
</core-context-menu>
|
</core-context-menu>
|
||||||
</ion-buttons>
|
</ion-buttons>
|
||||||
|
|
|
@ -37,6 +37,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
|
||||||
showFilter = false;
|
showFilter = false;
|
||||||
coursesLoaded = false;
|
coursesLoaded = false;
|
||||||
prefetchCoursesData: any = {};
|
prefetchCoursesData: any = {};
|
||||||
|
downloadAllCoursesEnabled: boolean;
|
||||||
|
|
||||||
protected prefetchIconInitialized = false;
|
protected prefetchIconInitialized = false;
|
||||||
protected myCoursesObserver;
|
protected myCoursesObserver;
|
||||||
|
@ -53,6 +54,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
|
||||||
*/
|
*/
|
||||||
ionViewDidLoad(): void {
|
ionViewDidLoad(): void {
|
||||||
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||||
|
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||||
|
|
||||||
this.fetchCourses().finally(() => {
|
this.fetchCourses().finally(() => {
|
||||||
this.coursesLoaded = true;
|
this.coursesLoaded = true;
|
||||||
|
@ -62,8 +64,17 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
|
||||||
this.fetchCourses();
|
this.fetchCourses();
|
||||||
}, this.sitesProvider.getCurrentSiteId());
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
|
// Refresh the enabled flags if site is updated.
|
||||||
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
||||||
|
const wasEnabled = this.downloadAllCoursesEnabled;
|
||||||
|
|
||||||
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||||
|
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||||
|
|
||||||
|
if (!wasEnabled && this.downloadAllCoursesEnabled && this.coursesLoaded) {
|
||||||
|
// Download all courses is enabled now, initialize it.
|
||||||
|
this.initPrefetchCoursesIcon();
|
||||||
|
}
|
||||||
}, this.sitesProvider.getCurrentSiteId());
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -176,7 +187,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy {
|
||||||
* Initialize the prefetch icon for the list of courses.
|
* Initialize the prefetch icon for the list of courses.
|
||||||
*/
|
*/
|
||||||
protected initPrefetchCoursesIcon(): void {
|
protected initPrefetchCoursesIcon(): void {
|
||||||
if (this.prefetchIconInitialized) {
|
if (this.prefetchIconInitialized || !this.downloadAllCoursesEnabled) {
|
||||||
// Already initialized.
|
// Already initialized.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@
|
||||||
<ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option>
|
<ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option>
|
||||||
</ion-select>
|
</ion-select>
|
||||||
<!-- Download all courses. -->
|
<!-- Download all courses. -->
|
||||||
<div *ngIf="courses[courses.selected] && courses[courses.selected].length > 1" class="core-button-spinner" float-end>
|
<div *ngIf="downloadAllCoursesEnabled && courses[courses.selected] && courses[courses.selected].length > 1" class="core-button-spinner" float-end>
|
||||||
<button *ngIf="prefetchCoursesData[courses.selected].icon && prefetchCoursesData[courses.selected].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
|
<button *ngIf="prefetchCoursesData[courses.selected].icon && prefetchCoursesData[courses.selected].icon != 'spinner'" ion-button icon-only clear color="dark" (click)="prefetchCourses()">
|
||||||
<ion-icon [name]="prefetchCoursesData[courses.selected].icon"></ion-icon>
|
<ion-icon [name]="prefetchCoursesData[courses.selected].icon"></ion-icon>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
|
|
||||||
import { Component, OnDestroy } from '@angular/core';
|
import { Component, OnDestroy } from '@angular/core';
|
||||||
import { IonicPage, NavController } from 'ionic-angular';
|
import { IonicPage, NavController } from 'ionic-angular';
|
||||||
|
import { CoreEventsProvider } from '@providers/events';
|
||||||
import { CoreSitesProvider } from '@providers/sites';
|
import { CoreSitesProvider } from '@providers/sites';
|
||||||
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
import { CoreDomUtilsProvider } from '@providers/utils/dom';
|
||||||
import { CoreCoursesProvider } from '../../providers/courses';
|
import { CoreCoursesProvider } from '../../providers/courses';
|
||||||
|
@ -64,20 +65,38 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
|
||||||
past: {},
|
past: {},
|
||||||
future: {}
|
future: {}
|
||||||
};
|
};
|
||||||
|
downloadAllCoursesEnabled: boolean;
|
||||||
|
|
||||||
protected prefetchIconsInitialized = false;
|
protected prefetchIconsInitialized = false;
|
||||||
protected isDestroyed;
|
protected isDestroyed;
|
||||||
|
protected updateSiteObserver;
|
||||||
|
|
||||||
constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider,
|
constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider,
|
||||||
private domUtils: CoreDomUtilsProvider, private myOverviewProvider: CoreCoursesMyOverviewProvider,
|
private domUtils: CoreDomUtilsProvider, private myOverviewProvider: CoreCoursesMyOverviewProvider,
|
||||||
private courseHelper: CoreCourseHelperProvider, private sitesProvider: CoreSitesProvider,
|
private courseHelper: CoreCourseHelperProvider, private sitesProvider: CoreSitesProvider,
|
||||||
private siteHomeProvider: CoreSiteHomeProvider, private courseOptionsDelegate: CoreCourseOptionsDelegate) { }
|
private siteHomeProvider: CoreSiteHomeProvider, private courseOptionsDelegate: CoreCourseOptionsDelegate,
|
||||||
|
private eventsProvider: CoreEventsProvider) {
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* View loaded.
|
* View loaded.
|
||||||
*/
|
*/
|
||||||
ionViewDidLoad(): void {
|
ionViewDidLoad(): void {
|
||||||
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||||
|
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||||
|
|
||||||
|
// Refresh the enabled flags if site is updated.
|
||||||
|
this.updateSiteObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
||||||
|
const wasEnabled = this.downloadAllCoursesEnabled;
|
||||||
|
|
||||||
|
this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite();
|
||||||
|
this.downloadAllCoursesEnabled = !this.coursesProvider.isDownloadCoursesDisabledInSite();
|
||||||
|
|
||||||
|
if (!wasEnabled && this.downloadAllCoursesEnabled && this.courses.loaded) {
|
||||||
|
// Download all courses is enabled now, initialize it.
|
||||||
|
this.initPrefetchCoursesIcons();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Decide which tab to load first.
|
// Decide which tab to load first.
|
||||||
this.siteHomeProvider.isAvailable().then((enabled) => {
|
this.siteHomeProvider.isAvailable().then((enabled) => {
|
||||||
|
@ -378,7 +397,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
|
||||||
* Initialize the prefetch icon for selected courses.
|
* Initialize the prefetch icon for selected courses.
|
||||||
*/
|
*/
|
||||||
protected initPrefetchCoursesIcons(): void {
|
protected initPrefetchCoursesIcons(): void {
|
||||||
if (this.prefetchIconsInitialized) {
|
if (this.prefetchIconsInitialized || !this.downloadAllCoursesEnabled) {
|
||||||
// Already initialized.
|
// Already initialized.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -410,5 +429,6 @@ export class CoreCoursesMyOverviewPage implements OnDestroy {
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.isDestroyed = true;
|
this.isDestroyed = true;
|
||||||
|
this.updateSiteObserver && this.updateSiteObserver.off();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -120,6 +120,54 @@ export class CoreCoursesProvider {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if download a whole course is disabled in a certain site.
|
||||||
|
*
|
||||||
|
* @param {string} [siteId] Site Id. If not defined, use current site.
|
||||||
|
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
|
||||||
|
*/
|
||||||
|
isDownloadCourseDisabled(siteId?: string): Promise<boolean> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
return this.isDownloadCoursesDisabledInSite(site);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if download a whole course is disabled in a certain site.
|
||||||
|
*
|
||||||
|
* @param {CoreSite} [site] Site. If not defined, use current site.
|
||||||
|
* @return {boolean} Whether it's disabled.
|
||||||
|
*/
|
||||||
|
isDownloadCourseDisabledInSite(site?: CoreSite): boolean {
|
||||||
|
site = site || this.sitesProvider.getCurrentSite();
|
||||||
|
|
||||||
|
return site.isFeatureDisabled('NoDelegate_CoreCourseDownload');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if download all courses is disabled in a certain site.
|
||||||
|
*
|
||||||
|
* @param {string} [siteId] Site Id. If not defined, use current site.
|
||||||
|
* @return {Promise<boolean>} Promise resolved with true if disabled, rejected or resolved with false otherwise.
|
||||||
|
*/
|
||||||
|
isDownloadCoursesDisabled(siteId?: string): Promise<boolean> {
|
||||||
|
return this.sitesProvider.getSite(siteId).then((site) => {
|
||||||
|
return this.isDownloadCoursesDisabledInSite(site);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if download all courses is disabled in a certain site.
|
||||||
|
*
|
||||||
|
* @param {CoreSite} [site] Site. If not defined, use current site.
|
||||||
|
* @return {boolean} Whether it's disabled.
|
||||||
|
*/
|
||||||
|
isDownloadCoursesDisabledInSite(site?: CoreSite): boolean {
|
||||||
|
site = site || this.sitesProvider.getCurrentSite();
|
||||||
|
|
||||||
|
return site.isFeatureDisabled('NoDelegate_CoreCoursesDownload');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if My Courses is disabled in a certain site.
|
* Check if My Courses is disabled in a certain site.
|
||||||
*
|
*
|
||||||
|
|
|
@ -77,6 +77,7 @@
|
||||||
"errorinvalidform": "The form contains invalid data. Please make sure to fill all required fields and that the data is valid.",
|
"errorinvalidform": "The form contains invalid data. Please make sure to fill all required fields and that the data is valid.",
|
||||||
"errorinvalidresponse": "Invalid response received. Please contact your Moodle site administrator if the error persists.",
|
"errorinvalidresponse": "Invalid response received. Please contact your Moodle site administrator if the error persists.",
|
||||||
"errorloadingcontent": "Error loading content.",
|
"errorloadingcontent": "Error loading content.",
|
||||||
|
"errorofflinedisabled": "Offline browsing is disabled on your site. You need to be connected to the internet to use the app.",
|
||||||
"erroropenfilenoapp": "Error opening the file: no app found to open this kind of file.",
|
"erroropenfilenoapp": "Error opening the file: no app found to open this kind of file.",
|
||||||
"erroropenfilenoextension": "Error opening the file: the file doesn't have extension.",
|
"erroropenfilenoextension": "Error opening the file: the file doesn't have extension.",
|
||||||
"erroropenpopup": "This activity is trying to open a popup. This is not supported in this app.",
|
"erroropenpopup": "This activity is trying to open a popup. This is not supported in this app.",
|
||||||
|
|
Loading…
Reference in New Issue