forked from CIT/Vmeda.Online
		
	MOBILE-2310 courses: Apply download courses
This commit is contained in:
		
							parent
							
								
									fe2c4cce74
								
							
						
					
					
						commit
						04085d5929
					
				| @ -242,6 +242,10 @@ export class CoreCourseSectionPage implements OnDestroy { | ||||
|                     // Ignore errors (shouldn't happen).
 | ||||
|                 }); | ||||
|             } | ||||
|         }).catch((error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|  | ||||
| @ -2,11 +2,11 @@ | ||||
|     <a ion-item text-wrap detail-none (click)="openCourse(course)" [title]="course.fullname"> | ||||
|         <h2 float-start><core-format-text [text]="course.fullname"></core-format-text></h2> | ||||
|         <!-- Download course. --> | ||||
|         <!--<button [hidden]="!downloadButton.isDownload" ion-button icon-only clear color="dark" float-end> | ||||
|             <ion-icon name="cloud-download"></ion-icon> | ||||
|         </button>--> | ||||
|         <button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" float-end (click)="prefetchCourse($event)"> | ||||
|             <ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon> | ||||
|         </button> | ||||
|         <!-- Download course spinner. --> | ||||
|         <!-- <ion-spinner *ngIf="prefetchCourseIcon == 'spinner'" class="core-course-download-spinner"></ion-spinner> --> | ||||
|         <ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" class="core-course-download-spinner" float-end></ion-spinner> | ||||
|     </a> | ||||
|     <ion-item text-wrap *ngIf="course.summary && course.summary.length"> | ||||
|         <p> | ||||
|  | ||||
| @ -12,10 +12,15 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component, Input, OnInit } from '@angular/core'; | ||||
| import { Component, Input, OnInit, OnDestroy } from '@angular/core'; | ||||
| import { NavController } from 'ionic-angular'; | ||||
| import { TranslateService } from '@ngx-translate/core'; | ||||
| import { CoreEventsProvider } from '../../../../providers/events'; | ||||
| import { CoreSitesProvider } from '../../../../providers/sites'; | ||||
| import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | ||||
| import { CoreCourseFormatDelegate } from '../../../course/providers/format-delegate'; | ||||
| import { CoreCourseProvider } from '../../../course/providers/course'; | ||||
| import { CoreCourseHelperProvider } from '../../../course/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * This component is meant to display a course for a list of courses with progress. | ||||
| @ -29,32 +34,52 @@ import { CoreCourseFormatDelegate } from '../../../course/providers/format-deleg | ||||
|     selector: 'core-courses-course-progress', | ||||
|     templateUrl: 'course-progress.html' | ||||
| }) | ||||
| export class CoreCoursesCourseProgressComponent implements OnInit { | ||||
| export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||
|     @Input() course: any; // The course to render.
 | ||||
| 
 | ||||
|     isDownloading: boolean; | ||||
| 
 | ||||
|     protected obsStatus; | ||||
|     protected downloadText; | ||||
|     protected downloadingText; | ||||
|     protected downloadButton = { | ||||
|         isDownload: true, | ||||
|         className: 'core-download-course', | ||||
|         priority: 1000 | ||||
|     prefetchCourseData = { | ||||
|         prefetchCourseIcon: 'spinner' | ||||
|     }; | ||||
|     protected buttons; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, private translate: TranslateService, | ||||
|             private courseFormatDelegate: CoreCourseFormatDelegate) { | ||||
|         this.downloadText = this.translate.instant('core.course.downloadcourse'); | ||||
|         this.downloadingText = this.translate.instant('core.downloading'); | ||||
|     protected isDestroyed = false; | ||||
|     protected courseStatusObserver; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, private translate: TranslateService, private courseHelper: CoreCourseHelperProvider, | ||||
|             private courseFormatDelegate: CoreCourseFormatDelegate, private domUtils: CoreDomUtilsProvider, | ||||
|             private courseProvider: CoreCourseProvider, eventsProvider: CoreEventsProvider, sitesProvider: CoreSitesProvider) { | ||||
|         // Listen for status change in course.
 | ||||
|         this.courseStatusObserver = eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => { | ||||
|             if (data.courseId == this.course.id) { | ||||
|                 this.prefetchCourseData.prefetchCourseIcon = this.courseHelper.getCourseStatusIconFromStatus(data.status); | ||||
|             } | ||||
|         }, sitesProvider.getCurrentSiteId()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being initialized. | ||||
|      */ | ||||
|     ngOnInit() { | ||||
|         // @todo: Handle course prefetch.
 | ||||
|         // Determine course prefetch icon.
 | ||||
|         this.courseHelper.getCourseStatusIcon(this.course.id).then((icon) => { | ||||
|             this.prefetchCourseData.prefetchCourseIcon = icon; | ||||
| 
 | ||||
|             if (icon == 'spinner') { | ||||
|                 // Course is being downloaded. Get the download promise.
 | ||||
|                 const promise = this.courseHelper.getCourseDownloadPromise(this.course.id); | ||||
|                 if (promise) { | ||||
|                     // There is a download promise. If it fails, show an error.
 | ||||
|                     promise.catch((error) => { | ||||
|                         if (!this.isDestroyed) { | ||||
|                             this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                         } | ||||
|                     }); | ||||
|                 } else { | ||||
|                     // No download, this probably means that the app was closed while downloading. Set previous status.
 | ||||
|                     this.courseProvider.setCoursePreviousStatus(this.course.id); | ||||
|                 } | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -64,4 +89,30 @@ export class CoreCoursesCourseProgressComponent implements OnInit { | ||||
|         this.courseFormatDelegate.openCourse(this.navCtrl, course); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch the course. | ||||
|      * | ||||
|      * @param {Event} e Click event. | ||||
|      */ | ||||
|     prefetchCourse(e: Event) { | ||||
|         e.preventDefault(); | ||||
|         e.stopPropagation(); | ||||
| 
 | ||||
|         this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course).catch((error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component destroyed. | ||||
|      */ | ||||
|     ngOnDestroy() { | ||||
|         this.isDestroyed = true; | ||||
| 
 | ||||
|         if (this.courseStatusObserver) { | ||||
|             this.courseStatusObserver.off(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -17,22 +17,22 @@ | ||||
|                 <p *ngIf="course.startdate">{{course.startdate * 1000 | coreFormatDate:"dfdaymonthyear"}} <span *ngIf="course.enddate"> - {{course.enddate * 1000 | coreFormatDate:"dfdaymonthyear"}}</span></p> | ||||
|             </a> | ||||
| 
 | ||||
|             <ion-item text-wrap *ngIf="course.summary"> | ||||
|             <ion-item text-wrap *ngIf="course.summary" detail-none> | ||||
|                 <core-format-text [text]="course.summary" maxHeight="120"></core-format-text> | ||||
|             </ion-item> | ||||
| 
 | ||||
|             <a ion-item text-wrap *ngIf="course.contacts && course.contacts.length" core-user-link [attr.aria-label]="'core.viewprofile' | translate"> | ||||
|             <a ion-item text-wrap *ngIf="course.contacts && course.contacts.length" detail-none> | ||||
|                 <p class="item-heading">{{ 'core.teachers' | translate }}</p> | ||||
|                 <p *ngFor="let contact of course.contacts">{{contact.fullname}}</p> | ||||
|             </a> | ||||
|             <core-file *ngFor="let file of course.overviewfiles" [file]="file" [component]="component" [componentId]="course.id"></core-file> | ||||
|             <div *ngIf="!isEnrolled"> | ||||
|             <div *ngIf="!isEnrolled" detail-none> | ||||
|                 <ion-item text-wrap *ngFor="let instance of selfEnrolInstances"> | ||||
|                     <p class="item-heading">{{ instance.name }}</p> | ||||
|                     <button ion-button block margin-top (click)="selfEnrolClicked(instance.id)">{{ 'core.courses.enrolme' | translate }}</button> | ||||
|                 </ion-item> | ||||
|             </div> | ||||
|             <ion-item text-wrap *ngIf="!isEnrolled && paypalEnabled"> | ||||
|             <ion-item text-wrap *ngIf="!isEnrolled && paypalEnabled" detail-none> | ||||
|                 <p class="item-heading">{{ 'core.courses.paypalaccepted' | translate }}</p> | ||||
|                 <p>{{ 'core.paymentinstant' | translate }}</p> | ||||
|                 <button ion-button block margin-top (click)="paypalEnrol()">{{ 'core.courses.sendpaymentbutton' | translate }}</button> | ||||
| @ -40,12 +40,11 @@ | ||||
|             <ion-item *ngIf="!isEnrolled && !selfEnrolInstances.length && !paypalEnabled"> | ||||
|                 <p>{{ 'core.courses.notenrollable' | translate }}</p> | ||||
|             </ion-item> | ||||
|             <!-- @todo: Prefetch course. | ||||
|             <a class="item item-icon-left" ng-if="handlersShouldBeShown" ng-click="prefetchCourse()"> | ||||
|                 <i ng-if="prefetchCourseIcon != 'spinner'" class="icon {{prefetchCourseIcon}}"></i> | ||||
|                 <ion-spinner ng-if="prefetchCourseIcon == 'spinner'" class="icon"></ion-spinner> | ||||
|             <a ion-item *ngIf="handlersShouldBeShown" (click)="prefetchCourse()" detail-none> | ||||
|                 <ion-icon *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" [name]="prefetchCourseData.prefetchCourseIcon" item-start></ion-icon> | ||||
|                 <ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" item-start></ion-spinner> | ||||
|                 <h2>{{ 'core.course.downloadcourse' | translate }}</h2> | ||||
|             </a> --> | ||||
|             </a> | ||||
|             <a ion-item (click)="openCourse()" [title]="course.fullname" *ngIf="handlersShouldBeShown"> | ||||
|                 <ion-icon name="briefcase" item-start></ion-icon> | ||||
|                 <h2>{{ 'core.course.contents' | translate }}</h2> | ||||
|  | ||||
| @ -22,6 +22,8 @@ import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | ||||
| import { CoreTextUtilsProvider } from '../../../../providers/utils/text'; | ||||
| import { CoreCoursesProvider } from '../../providers/courses'; | ||||
| import { CoreCoursesDelegate } from '../../providers/delegate'; | ||||
| import { CoreCourseProvider } from '../../../course/providers/course'; | ||||
| import { CoreCourseHelperProvider } from '../../../course/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that allows "previewing" a course and enrolling in it if enabled and not enrolled. | ||||
| @ -40,7 +42,9 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { | ||||
|     selfEnrolInstances: any[] = []; | ||||
|     paypalEnabled: boolean; | ||||
|     dataLoaded: boolean; | ||||
|     prefetchCourseIcon: string; | ||||
|     prefetchCourseData = { | ||||
|         prefetchCourseIcon: 'spinner' | ||||
|     }; | ||||
| 
 | ||||
|     protected guestWSAvailable: boolean; | ||||
|     protected isGuestEnabled: boolean = false; | ||||
| @ -55,15 +59,24 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { | ||||
|     protected selfEnrolModal: Modal; | ||||
|     protected pageDestroyed = false; | ||||
|     protected currentInstanceId: number; | ||||
|     protected courseStatusObserver; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, navParams: NavParams, private sitesProvider: CoreSitesProvider, | ||||
|             private domUtils: CoreDomUtilsProvider, private textUtils: CoreTextUtilsProvider, appProvider: CoreAppProvider, | ||||
|             private coursesProvider: CoreCoursesProvider, private platform: Platform, private modalCtrl: ModalController, | ||||
|             private translate: TranslateService, private eventsProvider: CoreEventsProvider, | ||||
|             private coursesDelegate: CoreCoursesDelegate) { | ||||
|             private coursesDelegate: CoreCoursesDelegate, private courseHelper: CoreCourseHelperProvider, | ||||
|             private courseProvider: CoreCourseProvider) { | ||||
|         this.course = navParams.get('course'); | ||||
|         this.isMobile = appProvider.isMobile(); | ||||
|         this.isDesktop = appProvider.isDesktop(); | ||||
| 
 | ||||
|         // Listen for status change in course.
 | ||||
|         this.courseStatusObserver = eventsProvider.on(CoreEventsProvider.COURSE_STATUS_CHANGED, (data) => { | ||||
|             if (data.courseId == this.course.id) { | ||||
|                 this.prefetchCourseData.prefetchCourseIcon = this.courseHelper.getCourseStatusIconFromStatus(data.status); | ||||
|             } | ||||
|         }, sitesProvider.getCurrentSiteId()); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -88,7 +101,26 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { | ||||
|         }); | ||||
| 
 | ||||
|         this.getCourse().finally(() => { | ||||
|             // @todo: Prefetch course.
 | ||||
|             // Determine course prefetch icon.
 | ||||
|             this.courseHelper.getCourseStatusIcon(this.course.id).then((icon) => { | ||||
|                 this.prefetchCourseData.prefetchCourseIcon = icon; | ||||
| 
 | ||||
|                 if (icon == 'spinner') { | ||||
|                     // Course is being downloaded. Get the download promise.
 | ||||
|                     let promise = this.courseHelper.getCourseDownloadPromise(this.course.id); | ||||
|                     if (promise) { | ||||
|                         // There is a download promise. If it fails, show an error.
 | ||||
|                         promise.catch((error) => { | ||||
|                             if (!this.pageDestroyed) { | ||||
|                                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                             } | ||||
|                         }); | ||||
|                     } else { | ||||
|                         // No download, this probably means that the app was closed while downloading. Set previous status.
 | ||||
|                         this.courseProvider.setCoursePreviousStatus(this.course.id); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
| @ -97,6 +129,10 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { | ||||
|      */ | ||||
|     ngOnDestroy() { | ||||
|         this.pageDestroyed = true; | ||||
| 
 | ||||
|         if (this.courseStatusObserver) { | ||||
|             this.courseStatusObserver.off(); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -387,4 +423,16 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { | ||||
|             }); | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch the course. | ||||
|      */ | ||||
|     prefetchCourse() { | ||||
|         this.courseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course, undefined, this.course._handlers) | ||||
|                 .catch((error) => { | ||||
|             if (!this.pageDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|             } | ||||
|         }) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @ -7,6 +7,7 @@ | ||||
|                 <ion-icon name="search"></ion-icon> | ||||
|             </button> | ||||
|             <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]="!courses || courses.length <= 5" [priority]="700" [content]="'core.courses.filtermycourses' | translate" (action)="switchFilter()" [iconAction]="'funnel'"></core-context-menu-item> | ||||
|             </core-context-menu> | ||||
|         </ion-buttons> | ||||
|  | ||||
| @ -18,6 +18,7 @@ import { CoreEventsProvider } from '../../../../providers/events'; | ||||
| import { CoreSitesProvider } from '../../../../providers/sites'; | ||||
| import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | ||||
| import { CoreCoursesProvider } from '../../providers/courses'; | ||||
| import { CoreCourseHelperProvider } from '../../../course/providers/helper'; | ||||
| 
 | ||||
| /** | ||||
|  * Page that displays the list of courses the user is enrolled in. | ||||
| @ -34,14 +35,16 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { | ||||
|     filter = ''; | ||||
|     showFilter = false; | ||||
|     coursesLoaded = false; | ||||
|     prefetchCoursesData: any = {}; | ||||
| 
 | ||||
|     protected prefetchIconInitialized = false; | ||||
|     protected myCoursesObserver; | ||||
|     protected siteUpdatedObserver; | ||||
|     protected isDestroyed = false; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider, | ||||
|             private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider, | ||||
|             private sitesProvider: CoreSitesProvider) {} | ||||
|             private sitesProvider: CoreSitesProvider, private courseHelper: CoreCourseHelperProvider) {} | ||||
| 
 | ||||
|     /** | ||||
|      * View loaded. | ||||
| @ -81,7 +84,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { | ||||
|                 this.filteredCourses = this.courses; | ||||
|                 this.filter = ''; | ||||
| 
 | ||||
|                 // this.initPrefetchCoursesIcon();
 | ||||
|                 this.initPrefetchCoursesIcon(); | ||||
|             }); | ||||
|         }).catch((error) => { | ||||
|             this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true); | ||||
| @ -139,10 +142,60 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch all the courses. | ||||
|      */ | ||||
|     prefetchCourses() { | ||||
|         let initialIcon = this.prefetchCoursesData.icon; | ||||
| 
 | ||||
|         this.prefetchCoursesData.icon = 'spinner'; | ||||
|         this.prefetchCoursesData.badge = ''; | ||||
|         return this.courseHelper.confirmAndPrefetchCourses(this.courses, (progress) => { | ||||
|             this.prefetchCoursesData.badge = progress.count + ' / ' + progress.total; | ||||
|         }).then((downloaded) => { | ||||
|             this.prefetchCoursesData.icon = downloaded ? 'ion-android-refresh' : initialIcon; | ||||
|         }, (error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                 this.prefetchCoursesData.icon = initialIcon; | ||||
|             } | ||||
|         }).finally(() => { | ||||
|             this.prefetchCoursesData.badge = ''; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the prefetch icon for the list of courses. | ||||
|      */ | ||||
|     protected initPrefetchCoursesIcon() { | ||||
|         if (this.prefetchIconInitialized) { | ||||
|             // Already initialized.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.prefetchIconInitialized = true; | ||||
| 
 | ||||
|         if (!this.courses || this.courses.length < 2) { | ||||
|             // Not enough courses.
 | ||||
|             this.prefetchCoursesData.icon = ''; | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.courseHelper.determineCoursesStatus(this.courses).then((status) => { | ||||
|             let icon = this.courseHelper.getCourseStatusIconFromStatus(status); | ||||
|             if (icon == 'spinner') { | ||||
|                 // It seems all courses are being downloaded, show a download button instead.
 | ||||
|                 icon = 'cloud-download'; | ||||
|             } | ||||
|             this.prefetchCoursesData.icon = icon; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Page destroyed. | ||||
|      */ | ||||
|     ngOnDestroy() { | ||||
|         this.isDestroyed = true; | ||||
|         this.myCoursesObserver && this.myCoursesObserver.off(); | ||||
|         this.siteUpdatedObserver && this.siteUpdatedObserver.off(); | ||||
|     } | ||||
|  | ||||
| @ -46,22 +46,30 @@ | ||||
|         <!-- Courses tab. --> | ||||
|         <core-tab [title]="'core.courses.courses' | translate" (ionSelect)="tabChanged('courses')"> | ||||
|             <core-loading [hideUntil]="courses.loaded" class="core-loading-center"> | ||||
|                 <!-- "Time" selector. --> | ||||
|                 <div no-padding class="clearfix" [hidden]="showFilter"> | ||||
|                     <ion-select [title]="'core.show' | translate" [(ngModel)]="courses.selected" float-start (ngModelChange)="selectedChanged()"> | ||||
|                         <ion-option value="inprogress">{{ 'core.courses.inprogress' | translate }}</ion-option> | ||||
|                         <ion-option value="future">{{ 'core.courses.future' | translate }}</ion-option> | ||||
|                         <ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option> | ||||
|                     </ion-select> | ||||
|                     <button [hidden]="!courses[courses.selected] || !courses[courses.selected].length" ion-button icon-only clear color="dark" float-end> | ||||
|                         <ion-icon name="cloud-download"></ion-icon> | ||||
|                     </button> | ||||
|                     <!-- Download all courses. --> | ||||
|                     <div *ngIf="courses[courses.selected] && courses[courses.selected].length > 1"> | ||||
|                         <button *ngIf="prefetchCoursesData[courses.selected].icon && prefetchCoursesData[courses.selected].icon != 'spinner'" ion-button icon-only clear color="dark" float-end (click)="prefetchCourses()"> | ||||
|                             <ion-icon [name]="prefetchCoursesData[courses.selected].icon"></ion-icon> | ||||
|                         </button> | ||||
|                         <ion-spinner *ngIf="!prefetchCoursesData[courses.selected].icon || prefetchCoursesData[courses.selected].icon == 'spinner'" float-end></ion-spinner> | ||||
|                         <span float-end *ngIf="prefetchCoursesData[courses.selected].badge">{{prefetchCoursesData[courses.selected].badge}}</span> | ||||
|                     </div> | ||||
|                 </div> | ||||
|                 <!-- Filter courses. --> | ||||
|                 <div no-padding padding-bottom [hidden]="!showFilter"> | ||||
|                     <ion-item> | ||||
|                         <ion-label><ion-icon name="funnel" class="placeholder-icon"></ion-icon></ion-label> | ||||
|                         <ion-input type="text" name="filter" clearInput [(ngModel)]="courses.filter" (ngModelChange)="filterChanged($event)" [placeholder]="'core.courses.filtermycourses' | translate"></ion-input> | ||||
|                     </ion-item> | ||||
|                 </div> | ||||
|                 <!-- List of courses. --> | ||||
|                 <div> | ||||
|                     <ion-grid no-padding> | ||||
|                         <ion-row no-padding> | ||||
|  | ||||
| @ -12,11 +12,12 @@ | ||||
| // See the License for the specific language governing permissions and
 | ||||
| // limitations under the License.
 | ||||
| 
 | ||||
| import { Component } from '@angular/core'; | ||||
| import { Component, OnDestroy } from '@angular/core'; | ||||
| import { IonicPage, NavController } from 'ionic-angular'; | ||||
| import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | ||||
| import { CoreCoursesProvider } from '../../providers/courses'; | ||||
| import { CoreCoursesMyOverviewProvider } from '../../providers/my-overview'; | ||||
| import { CoreCourseHelperProvider } from '../../../course/providers/helper'; | ||||
| import * as moment from 'moment'; | ||||
| 
 | ||||
| /** | ||||
| @ -27,7 +28,7 @@ import * as moment from 'moment'; | ||||
|     selector: 'page-core-courses-my-overview', | ||||
|     templateUrl: 'my-overview.html', | ||||
| }) | ||||
| export class CoreCoursesMyOverviewPage { | ||||
| export class CoreCoursesMyOverviewPage implements OnDestroy { | ||||
|     tabShown = 'courses'; | ||||
|     timeline = { | ||||
|         sort: 'sortbydates', | ||||
| @ -52,21 +53,24 @@ export class CoreCoursesMyOverviewPage { | ||||
|     searchEnabled: boolean; | ||||
|     filteredCourses: any[]; | ||||
|     tabs = []; | ||||
|     prefetchCoursesData = { | ||||
|         inprogress: {}, | ||||
|         past: {}, | ||||
|         future: {} | ||||
|     }; | ||||
| 
 | ||||
|     protected prefetchIconInitialized = false; | ||||
|     protected myCoursesObserver; | ||||
|     protected siteUpdatedObserver; | ||||
|     protected prefetchIconsInitialized = false; | ||||
|     protected isDestroyed; | ||||
| 
 | ||||
|     constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider, | ||||
|             private domUtils: CoreDomUtilsProvider, private myOverviewProvider: CoreCoursesMyOverviewProvider) {} | ||||
|             private domUtils: CoreDomUtilsProvider, private myOverviewProvider: CoreCoursesMyOverviewProvider, | ||||
|             private courseHelper: CoreCourseHelperProvider) {} | ||||
| 
 | ||||
|     /** | ||||
|      * View loaded. | ||||
|      */ | ||||
|     ionViewDidLoad() { | ||||
|         this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite(); | ||||
| 
 | ||||
|         // @todo: Course download.
 | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
| @ -144,6 +148,8 @@ export class CoreCoursesMyOverviewPage { | ||||
|             this.courses.filter = ''; | ||||
|             this.showFilter = false; | ||||
|             this.filteredCourses = this.courses[this.courses.selected]; | ||||
| 
 | ||||
|             this.initPrefetchCoursesIcons(); | ||||
|         }).catch((error) => { | ||||
|             this.domUtils.showErrorModalDefault(error, 'Error getting my overview data.'); | ||||
|         }); | ||||
| @ -229,6 +235,7 @@ export class CoreCoursesMyOverviewPage { | ||||
|                     } | ||||
|                     break; | ||||
|                 case 'courses': | ||||
|                     this.prefetchIconsInitialized = false; | ||||
|                     return this.fetchMyOverviewCourses(); | ||||
|             } | ||||
|         }).finally(() => { | ||||
| @ -315,4 +322,65 @@ export class CoreCoursesMyOverviewPage { | ||||
|     selectedChanged() { | ||||
|         this.filteredCourses = this.courses[this.courses.selected]; | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Prefetch all the shown courses. | ||||
|      */ | ||||
|     prefetchCourses() { | ||||
|         let selected = this.courses.selected, | ||||
|             selectedData = this.prefetchCoursesData[selected], | ||||
|             initialIcon = selectedData.icon; | ||||
| 
 | ||||
|         selectedData.icon = 'spinner'; | ||||
|         selectedData.badge = ''; | ||||
|         return this.courseHelper.confirmAndPrefetchCourses(this.courses[selected], (progress) => { | ||||
|             selectedData.badge = progress.count + ' / ' + progress.total; | ||||
|         }).then((downloaded) => { | ||||
|             selectedData.icon = downloaded ? 'refresh' : initialIcon; | ||||
|         }, (error) => { | ||||
|             if (!this.isDestroyed) { | ||||
|                 this.domUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true); | ||||
|                 selectedData.icon = initialIcon; | ||||
|             } | ||||
|         }).finally(() => { | ||||
|             selectedData.badge = ''; | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Initialize the prefetch icon for selected courses. | ||||
|      */ | ||||
|     protected initPrefetchCoursesIcons() { | ||||
|         if (this.prefetchIconsInitialized) { | ||||
|             // Already initialized.
 | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         this.prefetchIconsInitialized = true; | ||||
| 
 | ||||
|         Object.keys(this.prefetchCoursesData).forEach((filter) => { | ||||
|             if (!this.courses[filter] || this.courses[filter].length < 2) { | ||||
|                 // Not enough courses.
 | ||||
|                 this.prefetchCoursesData[filter].icon = ''; | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             this.courseHelper.determineCoursesStatus(this.courses[filter]).then((status) => { | ||||
|                 let icon = this.courseHelper.getCourseStatusIconFromStatus(status); | ||||
|                 if (icon == 'spinner') { | ||||
|                     // It seems all courses are being downloaded, show a download button instead.
 | ||||
|                     icon = 'cloud-download'; | ||||
|                 } | ||||
|                 this.prefetchCoursesData[filter].icon = icon; | ||||
|             }); | ||||
| 
 | ||||
|         }); | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Component being destroyed. | ||||
|      */ | ||||
|     ngOnDestroy() { | ||||
|         this.isDestroyed = true; | ||||
|     } | ||||
| } | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user