MOBILE-2688 courses: Add options menu
parent
62a7820d2c
commit
973bc5fcb3
|
@ -66,6 +66,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
||||||
protected prefetchIconsInitialized = false;
|
protected prefetchIconsInitialized = false;
|
||||||
protected isDestroyed;
|
protected isDestroyed;
|
||||||
protected updateSiteObserver;
|
protected updateSiteObserver;
|
||||||
|
protected coursesObserver;
|
||||||
protected courseIds = [];
|
protected courseIds = [];
|
||||||
protected fetchContentDefaultError = 'Error getting my overview data.';
|
protected fetchContentDefaultError = 'Error getting my overview data.';
|
||||||
|
|
||||||
|
@ -96,6 +97,10 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.coursesObserver = this.eventsProvider.on(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, () => {
|
||||||
|
this.refreshContent();
|
||||||
|
}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
|
||||||
this.currentSite = this.sitesProvider.getCurrentSite();
|
this.currentSite = this.sitesProvider.getCurrentSite();
|
||||||
|
|
||||||
const promises = [];
|
const promises = [];
|
||||||
|
@ -326,6 +331,7 @@ export class AddonBlockMyOverviewComponent extends CoreBlockBaseComponent implem
|
||||||
*/
|
*/
|
||||||
ngOnDestroy(): void {
|
ngOnDestroy(): void {
|
||||||
this.isDestroyed = true;
|
this.isDestroyed = true;
|
||||||
|
this.coursesObserver && this.coursesObserver.off();
|
||||||
this.updateSiteObserver && this.updateSiteObserver.off();
|
this.updateSiteObserver && this.updateSiteObserver.off();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1188,6 +1188,7 @@
|
||||||
"core.courses.errorselfenrol": "An error occurred while self enrolling.",
|
"core.courses.errorselfenrol": "An error occurred while self enrolling.",
|
||||||
"core.courses.filtermycourses": "Filter my courses",
|
"core.courses.filtermycourses": "Filter my courses",
|
||||||
"core.courses.frontpage": "Front page",
|
"core.courses.frontpage": "Front page",
|
||||||
|
"core.courses.hidecourse": "Hide from view",
|
||||||
"core.courses.mycourses": "My courses",
|
"core.courses.mycourses": "My courses",
|
||||||
"core.courses.mymoodle": "Dashboard",
|
"core.courses.mymoodle": "Dashboard",
|
||||||
"core.courses.nocourses": "No course information to show.",
|
"core.courses.nocourses": "No course information to show.",
|
||||||
|
@ -1203,6 +1204,7 @@
|
||||||
"core.courses.searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
"core.courses.searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
||||||
"core.courses.selfenrolment": "Self enrolment",
|
"core.courses.selfenrolment": "Self enrolment",
|
||||||
"core.courses.sendpaymentbutton": "Send payment via PayPal",
|
"core.courses.sendpaymentbutton": "Send payment via PayPal",
|
||||||
|
"core.courses.show": "Show this course",
|
||||||
"core.courses.totalcoursesearchresults": "Total courses: {{$a}}",
|
"core.courses.totalcoursesearchresults": "Total courses: {{$a}}",
|
||||||
"core.currentdevice": "Current device",
|
"core.currentdevice": "Current device",
|
||||||
"core.datastoredoffline": "Data stored in the device because it couldn't be sent. It will be sent automatically later.",
|
"core.datastoredoffline": "Data stored in the device because it couldn't be sent. It will be sent automatically later.",
|
||||||
|
|
|
@ -21,11 +21,13 @@ import { CoreDirectivesModule } from '@directives/directives.module';
|
||||||
import { CorePipesModule } from '@pipes/pipes.module';
|
import { CorePipesModule } from '@pipes/pipes.module';
|
||||||
import { CoreCoursesCourseProgressComponent } from '../components/course-progress/course-progress';
|
import { CoreCoursesCourseProgressComponent } from '../components/course-progress/course-progress';
|
||||||
import { CoreCoursesCourseListItemComponent } from '../components/course-list-item/course-list-item';
|
import { CoreCoursesCourseListItemComponent } from '../components/course-list-item/course-list-item';
|
||||||
|
import { CoreCoursesCourseOptionsMenuComponent } from '../components/course-options-menu/course-options-menu';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
declarations: [
|
declarations: [
|
||||||
CoreCoursesCourseProgressComponent,
|
CoreCoursesCourseProgressComponent,
|
||||||
CoreCoursesCourseListItemComponent
|
CoreCoursesCourseListItemComponent,
|
||||||
|
CoreCoursesCourseOptionsMenuComponent
|
||||||
],
|
],
|
||||||
imports: [
|
imports: [
|
||||||
CommonModule,
|
CommonModule,
|
||||||
|
@ -39,7 +41,11 @@ import { CoreCoursesCourseListItemComponent } from '../components/course-list-it
|
||||||
],
|
],
|
||||||
exports: [
|
exports: [
|
||||||
CoreCoursesCourseProgressComponent,
|
CoreCoursesCourseProgressComponent,
|
||||||
CoreCoursesCourseListItemComponent
|
CoreCoursesCourseListItemComponent,
|
||||||
|
CoreCoursesCourseOptionsMenuComponent
|
||||||
|
],
|
||||||
|
entryComponents: [
|
||||||
|
CoreCoursesCourseOptionsMenuComponent
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
export class CoreCoursesComponentsModule {}
|
export class CoreCoursesComponentsModule {}
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<ion-item text-wrap (click)="action('download')" *ngIf="downloadCourseEnabled">
|
||||||
|
<ion-icon [name]="prefetch.prefetchCourseIcon" item-start></ion-icon>
|
||||||
|
<h2>{{ prefetch.title | translate }}</h2>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item text-wrap (click)="action('hide')" *ngIf="!course.hidden">
|
||||||
|
<core-icon name="fa-eye" item-start></core-icon>
|
||||||
|
<h2>{{ 'core.courses.hidecourse' | translate }}</h2>
|
||||||
|
</ion-item>
|
||||||
|
<ion-item text-wrap (click)="action('show')" *ngIf="course.hidden">
|
||||||
|
<core-icon name="fa-eye-slash" item-start></core-icon>
|
||||||
|
<h2>{{ 'core.courses.show' | translate }}</h2>
|
||||||
|
</ion-item>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
// (C) Copyright 2015 Martin Dougiamas
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
import { Component, OnInit } from '@angular/core';
|
||||||
|
import { NavParams, ViewController } from 'ionic-angular';
|
||||||
|
import { CoreCoursesProvider } from '../../providers/courses';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This component is meant to display a popover with the course options.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'core-courses-course-options-menu',
|
||||||
|
templateUrl: 'core-courses-course-options-menu.html'
|
||||||
|
})
|
||||||
|
export class CoreCoursesCourseOptionsMenuComponent implements OnInit {
|
||||||
|
course: any; // The course.
|
||||||
|
prefetch: any; // The prefecth info.
|
||||||
|
|
||||||
|
downloadCourseEnabled: boolean;
|
||||||
|
|
||||||
|
constructor(navParams: NavParams, private viewCtrl: ViewController, private coursesProvider: CoreCoursesProvider) {
|
||||||
|
this.course = navParams.get('course') || {};
|
||||||
|
this.prefetch = navParams.get('prefetch') || {};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Component being initialized.
|
||||||
|
*/
|
||||||
|
ngOnInit(): void {
|
||||||
|
this.downloadCourseEnabled = !this.coursesProvider.isDownloadCourseDisabledInSite();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do an action over the course.
|
||||||
|
* @param {string} action Action name to take.
|
||||||
|
*/
|
||||||
|
action(action: string): void {
|
||||||
|
this.viewCtrl.dismiss(action);
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,10 +3,10 @@
|
||||||
<img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt=""/>
|
<img *ngIf="course.courseImage" [src]="course.courseImage" core-external-content alt=""/>
|
||||||
<core-icon name="fa-star" *ngIf="course.isfavourite"></core-icon>
|
<core-icon name="fa-star" *ngIf="course.isfavourite"></core-icon>
|
||||||
</div>
|
</div>
|
||||||
<ion-item tappable text-wrap detail-none (click)="openCourse(course)" [title]="course.displayname || course.fullname" class="core-course-link" [class.item-disabled]="course.visible == 0">
|
<ion-item tappable text-wrap detail-none (click)="openCourse(course)" [title]="course.displayname || course.fullname" class="core-course-link" [class.item-disabled]="course.visible == 0" [class.core-course-more-than-title]="(course.summary && course.summary.length) || (course.progress != null && course.progress >= 0)">
|
||||||
<h2><core-format-text [text]="course.displayname || course.fullname"></core-format-text></h2>
|
<h2><core-format-text [text]="course.displayname || course.fullname"></core-format-text></h2>
|
||||||
|
|
||||||
<div class="core-button-spinner" *ngIf="downloadCourseEnabled">
|
<div class="core-button-spinner" *ngIf="downloadCourseEnabled && !courseOptionMenuEnabled">
|
||||||
<!-- 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">
|
||||||
<core-icon [name]="prefetchCourseData.prefetchCourseIcon"></core-icon>
|
<core-icon [name]="prefetchCourseData.prefetchCourseIcon"></core-icon>
|
||||||
|
@ -14,6 +14,16 @@
|
||||||
<!-- Download course spinner. -->
|
<!-- Download course spinner. -->
|
||||||
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'"></ion-spinner>
|
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner'"></ion-spinner>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="core-button-spinner" *ngIf="courseOptionMenuEnabled">
|
||||||
|
<!-- Options menu. -->
|
||||||
|
<button ion-button icon-only clear color="dark" (click)="showCourseOptionsMenu($event)" *ngIf="prefetchCourseData.prefetchCourseIcon != 'spinner' && !showSpinner">
|
||||||
|
<core-icon name="more"></core-icon>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<!-- Download course spinner. -->
|
||||||
|
<ion-spinner *ngIf="prefetchCourseData.prefetchCourseIcon == 'spinner' || showSpinner"></ion-spinner>
|
||||||
|
</div>
|
||||||
</ion-item>
|
</ion-item>
|
||||||
<ion-item text-wrap *ngIf="course.summary && course.summary.length" [class.item-disabled]="course.visible == 0">
|
<ion-item text-wrap *ngIf="course.summary && course.summary.length" [class.item-disabled]="course.visible == 0">
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -56,6 +56,10 @@ ion-app.app-root core-courses-course-progress {
|
||||||
margins: 6px 0;
|
margins: 6px 0;
|
||||||
flex-grow: 1;
|
flex-grow: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.core-course-more-than-title {
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.label {
|
.label {
|
||||||
@include margin(0, 0, 0, null);
|
@include margin(0, 0, 0, null);
|
||||||
|
|
|
@ -13,14 +13,16 @@
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
import { Component, Input, OnInit, OnDestroy, Optional } from '@angular/core';
|
import { Component, Input, OnInit, OnDestroy, Optional } from '@angular/core';
|
||||||
import { NavController } from 'ionic-angular';
|
import { NavController, PopoverController } 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 { CoreUserProvider } from '@core/user/providers/user';
|
||||||
import { CoreCoursesProvider } from '@core/courses/providers/courses';
|
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';
|
||||||
|
import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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.
|
||||||
|
@ -42,7 +44,9 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
prefetchCourseIcon: 'spinner',
|
prefetchCourseIcon: 'spinner',
|
||||||
title: 'core.course.downloadcourse'
|
title: 'core.course.downloadcourse'
|
||||||
};
|
};
|
||||||
|
showSpinner = false;
|
||||||
downloadCourseEnabled: boolean;
|
downloadCourseEnabled: boolean;
|
||||||
|
courseOptionMenuEnabled: boolean;
|
||||||
|
|
||||||
protected isDestroyed = false;
|
protected isDestroyed = false;
|
||||||
protected courseStatusObserver;
|
protected courseStatusObserver;
|
||||||
|
@ -51,7 +55,8 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
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, private eventsProvider: CoreEventsProvider,
|
private courseProvider: CoreCourseProvider, private eventsProvider: CoreEventsProvider,
|
||||||
private sitesProvider: CoreSitesProvider, private coursesProvider: CoreCoursesProvider) { }
|
private sitesProvider: CoreSitesProvider, private coursesProvider: CoreCoursesProvider,
|
||||||
|
private popoverCtrl: PopoverController, private userProvider: CoreUserProvider) { }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component being initialized.
|
* Component being initialized.
|
||||||
|
@ -63,6 +68,8 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
this.initPrefetchCourse();
|
this.initPrefetchCourse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.courseOptionMenuEnabled = typeof this.course.isfavourite != 'undefined';
|
||||||
|
|
||||||
// Refresh the enabled flag if site is updated.
|
// Refresh the enabled flag if site is updated.
|
||||||
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
this.siteUpdatedObserver = this.eventsProvider.on(CoreEventsProvider.SITE_UPDATED, () => {
|
||||||
const wasEnabled = this.downloadCourseEnabled;
|
const wasEnabled = this.downloadCourseEnabled;
|
||||||
|
@ -153,6 +160,58 @@ export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy {
|
||||||
this.prefetchCourseData.title = statusData.title;
|
this.prefetchCourseData.title = statusData.title;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the context menu.
|
||||||
|
*
|
||||||
|
* @param {Event} e Click Event.
|
||||||
|
*/
|
||||||
|
showCourseOptionsMenu(e: Event): void {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
|
||||||
|
const popover = this.popoverCtrl.create(CoreCoursesCourseOptionsMenuComponent, {
|
||||||
|
course: this.course,
|
||||||
|
prefetch: this.prefetchCourseData
|
||||||
|
});
|
||||||
|
popover.onDidDismiss((action) => {
|
||||||
|
if (action) {
|
||||||
|
switch (action) {
|
||||||
|
case 'download':
|
||||||
|
this.prefetchCourse(e);
|
||||||
|
break;
|
||||||
|
case 'hide':
|
||||||
|
this.setCourseHidden(true);
|
||||||
|
break;
|
||||||
|
case 'show':
|
||||||
|
this.setCourseHidden(false);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
popover.present({
|
||||||
|
ev: e
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide/Unhide the course from the course list.
|
||||||
|
*
|
||||||
|
* @param {boolean} hide True to hide and false to show.
|
||||||
|
*/
|
||||||
|
protected setCourseHidden(hide: boolean): void {
|
||||||
|
this.showSpinner = true;
|
||||||
|
|
||||||
|
this.userProvider.updateUserPreference('block_myoverview_hidden_course_' + this.course.id, hide ? 1 : false).then(() => {
|
||||||
|
this.course.hidden = hide;
|
||||||
|
this.eventsProvider.trigger(
|
||||||
|
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {course: this.course}, this.sitesProvider.getCurrentSiteId());
|
||||||
|
}).finally(() => {
|
||||||
|
this.showSpinner = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Component destroyed.
|
* Component destroyed.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
"errorselfenrol": "An error occurred while self enrolling.",
|
"errorselfenrol": "An error occurred while self enrolling.",
|
||||||
"filtermycourses": "Filter my courses",
|
"filtermycourses": "Filter my courses",
|
||||||
"frontpage": "Front page",
|
"frontpage": "Front page",
|
||||||
|
"hidecourse": "Hide from view",
|
||||||
"mycourses": "My courses",
|
"mycourses": "My courses",
|
||||||
"nocourses": "No course information to show.",
|
"nocourses": "No course information to show.",
|
||||||
"nocoursesyet": "No courses in this category",
|
"nocoursesyet": "No courses in this category",
|
||||||
|
@ -28,5 +29,6 @@
|
||||||
"searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
"searchcoursesadvice": "You can use the search courses button to find courses to access as a guest or enrol yourself in courses that allow it.",
|
||||||
"selfenrolment": "Self enrolment",
|
"selfenrolment": "Self enrolment",
|
||||||
"sendpaymentbutton": "Send payment via PayPal",
|
"sendpaymentbutton": "Send payment via PayPal",
|
||||||
|
"show": "Show this course",
|
||||||
"totalcoursesearchresults": "Total courses: {{$a}}"
|
"totalcoursesearchresults": "Total courses: {{$a}}"
|
||||||
}
|
}
|
|
@ -353,7 +353,7 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy {
|
||||||
this.refreshData().finally(() => {
|
this.refreshData().finally(() => {
|
||||||
// My courses have been updated, trigger event.
|
// My courses have been updated, trigger event.
|
||||||
this.eventsProvider.trigger(
|
this.eventsProvider.trigger(
|
||||||
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {}, this.sitesProvider.getCurrentSiteId());
|
CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {course: this.course}, this.sitesProvider.getCurrentSiteId());
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).catch((error) => {
|
}).catch((error) => {
|
||||||
|
|
Loading…
Reference in New Issue