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).
 |                     // 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"> |     <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> |         <h2 float-start><core-format-text [text]="course.fullname"></core-format-text></h2> | ||||||
|         <!-- Download course. --> |         <!-- Download course. --> | ||||||
|         <!--<button [hidden]="!downloadButton.isDownload" ion-button icon-only clear color="dark" float-end> |         <button *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" ion-button icon-only clear color="dark" float-end (click)="prefetchCourse($event)"> | ||||||
|             <ion-icon name="cloud-download"></ion-icon> |             <ion-icon [name]="prefetchCourseData.prefetchCourseIcon"></ion-icon> | ||||||
|         </button>--> |         </button> | ||||||
|         <!-- Download course spinner. --> |         <!-- 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> |     </a> | ||||||
|     <ion-item text-wrap *ngIf="course.summary && course.summary.length"> |     <ion-item text-wrap *ngIf="course.summary && course.summary.length"> | ||||||
|         <p> |         <p> | ||||||
|  | |||||||
| @ -12,10 +12,15 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // 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 { NavController } from 'ionic-angular'; | ||||||
| import { TranslateService } from '@ngx-translate/core'; | 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 { 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. |  * 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', |     selector: 'core-courses-course-progress', | ||||||
|     templateUrl: 'course-progress.html' |     templateUrl: 'course-progress.html' | ||||||
| }) | }) | ||||||
| export class CoreCoursesCourseProgressComponent implements OnInit { | export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy { | ||||||
|     @Input() course: any; // The course to render.
 |     @Input() course: any; // The course to render.
 | ||||||
| 
 | 
 | ||||||
|     isDownloading: boolean; |     isDownloading: boolean; | ||||||
| 
 |     prefetchCourseData = { | ||||||
|     protected obsStatus; |         prefetchCourseIcon: 'spinner' | ||||||
|     protected downloadText; |  | ||||||
|     protected downloadingText; |  | ||||||
|     protected downloadButton = { |  | ||||||
|         isDownload: true, |  | ||||||
|         className: 'core-download-course', |  | ||||||
|         priority: 1000 |  | ||||||
|     }; |     }; | ||||||
|     protected buttons; |  | ||||||
| 
 | 
 | ||||||
|     constructor(private navCtrl: NavController, private translate: TranslateService, |     protected isDestroyed = false; | ||||||
|             private courseFormatDelegate: CoreCourseFormatDelegate) { |     protected courseStatusObserver; | ||||||
|         this.downloadText = this.translate.instant('core.course.downloadcourse'); | 
 | ||||||
|         this.downloadingText = this.translate.instant('core.downloading'); |     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. |      * Component being initialized. | ||||||
|      */ |      */ | ||||||
|     ngOnInit() { |     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); |         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> |                 <p *ngIf="course.startdate">{{course.startdate * 1000 | coreFormatDate:"dfdaymonthyear"}} <span *ngIf="course.enddate"> - {{course.enddate * 1000 | coreFormatDate:"dfdaymonthyear"}}</span></p> | ||||||
|             </a> |             </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> |                 <core-format-text [text]="course.summary" maxHeight="120"></core-format-text> | ||||||
|             </ion-item> |             </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 class="item-heading">{{ 'core.teachers' | translate }}</p> | ||||||
|                 <p *ngFor="let contact of course.contacts">{{contact.fullname}}</p> |                 <p *ngFor="let contact of course.contacts">{{contact.fullname}}</p> | ||||||
|             </a> |             </a> | ||||||
|             <core-file *ngFor="let file of course.overviewfiles" [file]="file" [component]="component" [componentId]="course.id"></core-file> |             <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"> |                 <ion-item text-wrap *ngFor="let instance of selfEnrolInstances"> | ||||||
|                     <p class="item-heading">{{ instance.name }}</p> |                     <p class="item-heading">{{ instance.name }}</p> | ||||||
|                     <button ion-button block margin-top (click)="selfEnrolClicked(instance.id)">{{ 'core.courses.enrolme' | translate }}</button> |                     <button ion-button block margin-top (click)="selfEnrolClicked(instance.id)">{{ 'core.courses.enrolme' | translate }}</button> | ||||||
|                 </ion-item> |                 </ion-item> | ||||||
|             </div> |             </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 class="item-heading">{{ 'core.courses.paypalaccepted' | translate }}</p> | ||||||
|                 <p>{{ 'core.paymentinstant' | translate }}</p> |                 <p>{{ 'core.paymentinstant' | translate }}</p> | ||||||
|                 <button ion-button block margin-top (click)="paypalEnrol()">{{ 'core.courses.sendpaymentbutton' | translate }}</button> |                 <button ion-button block margin-top (click)="paypalEnrol()">{{ 'core.courses.sendpaymentbutton' | translate }}</button> | ||||||
| @ -40,12 +40,11 @@ | |||||||
|             <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> | ||||||
|             <!-- @todo: Prefetch course. |             <a ion-item *ngIf="handlersShouldBeShown" (click)="prefetchCourse()" detail-none> | ||||||
|             <a class="item item-icon-left" ng-if="handlersShouldBeShown" ng-click="prefetchCourse()"> |                 <ion-icon *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner'" [name]="prefetchCourseData.prefetchCourseIcon" item-start></ion-icon> | ||||||
|                 <i ng-if="prefetchCourseIcon != 'spinner'" class="icon {{prefetchCourseIcon}}"></i> |                 <ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'" item-start></ion-spinner> | ||||||
|                 <ion-spinner ng-if="prefetchCourseIcon == 'spinner'" class="icon"></ion-spinner> |  | ||||||
|                 <h2>{{ 'core.course.downloadcourse' | translate }}</h2> |                 <h2>{{ 'core.course.downloadcourse' | translate }}</h2> | ||||||
|             </a> --> |             </a> | ||||||
|             <a ion-item (click)="openCourse()" [title]="course.fullname" *ngIf="handlersShouldBeShown"> |             <a ion-item (click)="openCourse()" [title]="course.fullname" *ngIf="handlersShouldBeShown"> | ||||||
|                 <ion-icon name="briefcase" item-start></ion-icon> |                 <ion-icon name="briefcase" item-start></ion-icon> | ||||||
|                 <h2>{{ 'core.course.contents' | translate }}</h2> |                 <h2>{{ 'core.course.contents' | translate }}</h2> | ||||||
|  | |||||||
| @ -22,6 +22,8 @@ import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | |||||||
| import { CoreTextUtilsProvider } from '../../../../providers/utils/text'; | import { CoreTextUtilsProvider } from '../../../../providers/utils/text'; | ||||||
| import { CoreCoursesProvider } from '../../providers/courses'; | import { CoreCoursesProvider } from '../../providers/courses'; | ||||||
| import { CoreCoursesDelegate } from '../../providers/delegate'; | 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. |  * 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[] = []; |     selfEnrolInstances: any[] = []; | ||||||
|     paypalEnabled: boolean; |     paypalEnabled: boolean; | ||||||
|     dataLoaded: boolean; |     dataLoaded: boolean; | ||||||
|     prefetchCourseIcon: string; |     prefetchCourseData = { | ||||||
|  |         prefetchCourseIcon: 'spinner' | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     protected guestWSAvailable: boolean; |     protected guestWSAvailable: boolean; | ||||||
|     protected isGuestEnabled: boolean = false; |     protected isGuestEnabled: boolean = false; | ||||||
| @ -55,15 +59,24 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { | |||||||
|     protected selfEnrolModal: Modal; |     protected selfEnrolModal: Modal; | ||||||
|     protected pageDestroyed = false; |     protected pageDestroyed = false; | ||||||
|     protected currentInstanceId: number; |     protected currentInstanceId: number; | ||||||
|  |     protected courseStatusObserver; | ||||||
| 
 | 
 | ||||||
|     constructor(private navCtrl: NavController, navParams: NavParams, private sitesProvider: CoreSitesProvider, |     constructor(private navCtrl: NavController, navParams: NavParams, private sitesProvider: CoreSitesProvider, | ||||||
|             private domUtils: CoreDomUtilsProvider, private textUtils: CoreTextUtilsProvider, appProvider: CoreAppProvider, |             private domUtils: CoreDomUtilsProvider, private textUtils: CoreTextUtilsProvider, appProvider: CoreAppProvider, | ||||||
|             private coursesProvider: CoreCoursesProvider, private platform: Platform, private modalCtrl: ModalController, |             private coursesProvider: CoreCoursesProvider, private platform: Platform, private modalCtrl: ModalController, | ||||||
|             private translate: TranslateService, private eventsProvider: CoreEventsProvider, |             private translate: TranslateService, private eventsProvider: CoreEventsProvider, | ||||||
|             private coursesDelegate: CoreCoursesDelegate) { |             private coursesDelegate: CoreCoursesDelegate, private courseHelper: CoreCourseHelperProvider, | ||||||
|  |             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(); | ||||||
|  | 
 | ||||||
|  |         // 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(() => { |         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() { |     ngOnDestroy() { | ||||||
|         this.pageDestroyed = true; |         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> |                 <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]="!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> | ||||||
|  | |||||||
| @ -18,6 +18,7 @@ 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'; | ||||||
|  | import { CoreCourseHelperProvider } from '../../../course/providers/helper'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Page that displays the list of courses the user is enrolled in. |  * Page that displays the list of courses the user is enrolled in. | ||||||
| @ -34,14 +35,16 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { | |||||||
|     filter = ''; |     filter = ''; | ||||||
|     showFilter = false; |     showFilter = false; | ||||||
|     coursesLoaded = false; |     coursesLoaded = false; | ||||||
|  |     prefetchCoursesData: any = {}; | ||||||
| 
 | 
 | ||||||
|     protected prefetchIconInitialized = false; |     protected prefetchIconInitialized = false; | ||||||
|     protected myCoursesObserver; |     protected myCoursesObserver; | ||||||
|     protected siteUpdatedObserver; |     protected siteUpdatedObserver; | ||||||
|  |     protected isDestroyed = false; | ||||||
| 
 | 
 | ||||||
|     constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider, |     constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider, | ||||||
|             private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider, |             private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider, | ||||||
|             private sitesProvider: CoreSitesProvider) {} |             private sitesProvider: CoreSitesProvider, private courseHelper: CoreCourseHelperProvider) {} | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * View loaded. |      * View loaded. | ||||||
| @ -81,7 +84,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { | |||||||
|                 this.filteredCourses = this.courses; |                 this.filteredCourses = this.courses; | ||||||
|                 this.filter = ''; |                 this.filter = ''; | ||||||
| 
 | 
 | ||||||
|                 // this.initPrefetchCoursesIcon();
 |                 this.initPrefetchCoursesIcon(); | ||||||
|             }); |             }); | ||||||
|         }).catch((error) => { |         }).catch((error) => { | ||||||
|             this.domUtils.showErrorModalDefault(error, 'core.courses.errorloadcourses', true); |             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. |      * Page destroyed. | ||||||
|      */ |      */ | ||||||
|     ngOnDestroy() { |     ngOnDestroy() { | ||||||
|  |         this.isDestroyed = true; | ||||||
|         this.myCoursesObserver && this.myCoursesObserver.off(); |         this.myCoursesObserver && this.myCoursesObserver.off(); | ||||||
|         this.siteUpdatedObserver && this.siteUpdatedObserver.off(); |         this.siteUpdatedObserver && this.siteUpdatedObserver.off(); | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -46,22 +46,30 @@ | |||||||
|         <!-- Courses tab. --> |         <!-- Courses tab. --> | ||||||
|         <core-tab [title]="'core.courses.courses' | translate" (ionSelect)="tabChanged('courses')"> |         <core-tab [title]="'core.courses.courses' | translate" (ionSelect)="tabChanged('courses')"> | ||||||
|             <core-loading [hideUntil]="courses.loaded" class="core-loading-center"> |             <core-loading [hideUntil]="courses.loaded" class="core-loading-center"> | ||||||
|  |                 <!-- "Time" selector. --> | ||||||
|                 <div no-padding class="clearfix" [hidden]="showFilter"> |                 <div no-padding class="clearfix" [hidden]="showFilter"> | ||||||
|                     <ion-select [title]="'core.show' | translate" [(ngModel)]="courses.selected" float-start (ngModelChange)="selectedChanged()"> |                     <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="inprogress">{{ 'core.courses.inprogress' | translate }}</ion-option> | ||||||
|                         <ion-option value="future">{{ 'core.courses.future' | translate }}</ion-option> |                         <ion-option value="future">{{ 'core.courses.future' | translate }}</ion-option> | ||||||
|                         <ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option> |                         <ion-option value="past">{{ 'core.courses.past' | translate }}</ion-option> | ||||||
|                     </ion-select> |                     </ion-select> | ||||||
|                     <button [hidden]="!courses[courses.selected] || !courses[courses.selected].length" ion-button icon-only clear color="dark" float-end> |                     <!-- Download all courses. --> | ||||||
|                         <ion-icon name="cloud-download"></ion-icon> |                     <div *ngIf="courses[courses.selected] && courses[courses.selected].length > 1"> | ||||||
|                     </button> |                         <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> |                 </div> | ||||||
|  |                 <!-- Filter courses. --> | ||||||
|                 <div no-padding padding-bottom [hidden]="!showFilter"> |                 <div no-padding padding-bottom [hidden]="!showFilter"> | ||||||
|                     <ion-item> |                     <ion-item> | ||||||
|                         <ion-label><ion-icon name="funnel" class="placeholder-icon"></ion-icon></ion-label> |                         <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-input type="text" name="filter" clearInput [(ngModel)]="courses.filter" (ngModelChange)="filterChanged($event)" [placeholder]="'core.courses.filtermycourses' | translate"></ion-input> | ||||||
|                     </ion-item> |                     </ion-item> | ||||||
|                 </div> |                 </div> | ||||||
|  |                 <!-- List of courses. --> | ||||||
|                 <div> |                 <div> | ||||||
|                     <ion-grid no-padding> |                     <ion-grid no-padding> | ||||||
|                         <ion-row no-padding> |                         <ion-row no-padding> | ||||||
|  | |||||||
| @ -12,11 +12,12 @@ | |||||||
| // See the License for the specific language governing permissions and
 | // See the License for the specific language governing permissions and
 | ||||||
| // limitations under the License.
 | // limitations under the License.
 | ||||||
| 
 | 
 | ||||||
| import { Component } from '@angular/core'; | import { Component, OnDestroy } from '@angular/core'; | ||||||
| import { IonicPage, NavController } from 'ionic-angular'; | import { IonicPage, NavController } from 'ionic-angular'; | ||||||
| import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | import { CoreDomUtilsProvider } from '../../../../providers/utils/dom'; | ||||||
| import { CoreCoursesProvider } from '../../providers/courses'; | import { CoreCoursesProvider } from '../../providers/courses'; | ||||||
| import { CoreCoursesMyOverviewProvider } from '../../providers/my-overview'; | import { CoreCoursesMyOverviewProvider } from '../../providers/my-overview'; | ||||||
|  | import { CoreCourseHelperProvider } from '../../../course/providers/helper'; | ||||||
| import * as moment from 'moment'; | import * as moment from 'moment'; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
| @ -27,7 +28,7 @@ import * as moment from 'moment'; | |||||||
|     selector: 'page-core-courses-my-overview', |     selector: 'page-core-courses-my-overview', | ||||||
|     templateUrl: 'my-overview.html', |     templateUrl: 'my-overview.html', | ||||||
| }) | }) | ||||||
| export class CoreCoursesMyOverviewPage { | export class CoreCoursesMyOverviewPage implements OnDestroy { | ||||||
|     tabShown = 'courses'; |     tabShown = 'courses'; | ||||||
|     timeline = { |     timeline = { | ||||||
|         sort: 'sortbydates', |         sort: 'sortbydates', | ||||||
| @ -52,21 +53,24 @@ export class CoreCoursesMyOverviewPage { | |||||||
|     searchEnabled: boolean; |     searchEnabled: boolean; | ||||||
|     filteredCourses: any[]; |     filteredCourses: any[]; | ||||||
|     tabs = []; |     tabs = []; | ||||||
|  |     prefetchCoursesData = { | ||||||
|  |         inprogress: {}, | ||||||
|  |         past: {}, | ||||||
|  |         future: {} | ||||||
|  |     }; | ||||||
| 
 | 
 | ||||||
|     protected prefetchIconInitialized = false; |     protected prefetchIconsInitialized = false; | ||||||
|     protected myCoursesObserver; |     protected isDestroyed; | ||||||
|     protected siteUpdatedObserver; |  | ||||||
| 
 | 
 | ||||||
|     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) {} | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
|      * View loaded. |      * View loaded. | ||||||
|      */ |      */ | ||||||
|     ionViewDidLoad() { |     ionViewDidLoad() { | ||||||
|         this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite(); |         this.searchEnabled = !this.coursesProvider.isSearchCoursesDisabledInSite(); | ||||||
| 
 |  | ||||||
|         // @todo: Course download.
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /** |     /** | ||||||
| @ -144,6 +148,8 @@ export class CoreCoursesMyOverviewPage { | |||||||
|             this.courses.filter = ''; |             this.courses.filter = ''; | ||||||
|             this.showFilter = false; |             this.showFilter = false; | ||||||
|             this.filteredCourses = this.courses[this.courses.selected]; |             this.filteredCourses = this.courses[this.courses.selected]; | ||||||
|  | 
 | ||||||
|  |             this.initPrefetchCoursesIcons(); | ||||||
|         }).catch((error) => { |         }).catch((error) => { | ||||||
|             this.domUtils.showErrorModalDefault(error, 'Error getting my overview data.'); |             this.domUtils.showErrorModalDefault(error, 'Error getting my overview data.'); | ||||||
|         }); |         }); | ||||||
| @ -229,6 +235,7 @@ export class CoreCoursesMyOverviewPage { | |||||||
|                     } |                     } | ||||||
|                     break; |                     break; | ||||||
|                 case 'courses': |                 case 'courses': | ||||||
|  |                     this.prefetchIconsInitialized = false; | ||||||
|                     return this.fetchMyOverviewCourses(); |                     return this.fetchMyOverviewCourses(); | ||||||
|             } |             } | ||||||
|         }).finally(() => { |         }).finally(() => { | ||||||
| @ -315,4 +322,65 @@ export class CoreCoursesMyOverviewPage { | |||||||
|     selectedChanged() { |     selectedChanged() { | ||||||
|         this.filteredCourses = this.courses[this.courses.selected]; |         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