diff --git a/src/addon/competency/components/course/course.html b/src/addon/competency/components/course/course.html index 04584daae..320ea502c 100644 --- a/src/addon/competency/components/course/course.html +++ b/src/addon/competency/components/course/course.html @@ -29,7 +29,7 @@ - + diff --git a/src/components/empty-box/empty-box.scss b/src/components/empty-box/empty-box.scss index 1e56ae295..6c379ea4c 100644 --- a/src/components/empty-box/empty-box.scss +++ b/src/components/empty-box/empty-box.scss @@ -11,6 +11,7 @@ core-empty-box { margin: 0; padding: 0; clear: both; + pointer-events: none; .core-empty-box-content { color: $black; diff --git a/src/core/course/components/format/format.html b/src/core/course/components/format/format.html index 4c8d1d43a..369c52c63 100644 --- a/src/core/course/components/format/format.html +++ b/src/core/course/components/format/format.html @@ -3,6 +3,9 @@ +
+ +
diff --git a/src/core/course/components/format/format.scss b/src/core/course/components/format/format.scss index 11fd5d99a..284fe6133 100644 --- a/src/core/course/components/format/format.scss +++ b/src/core/course/components/format/format.scss @@ -3,4 +3,23 @@ ion-badge.core-course-download-section-progress { float: left; margin-top: 12px; margin-right: 12px; +} + +core-course-format { + .core-course-thumb { + height: 150px; + width: 100%; + overflow: hidden; + cursor: pointer; + pointer-events: auto; + position: relative; + + img { + position: absolute; + top: 0; + bottom: 0; + margin: auto; + width: 100%; + } + } } \ No newline at end of file diff --git a/src/core/course/components/format/format.ts b/src/core/course/components/format/format.ts index d65a8d674..9774e7b5b 100644 --- a/src/core/course/components/format/format.ts +++ b/src/core/course/components/format/format.ts @@ -252,7 +252,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy { /** * Calculate the status of sections. * - * @param {boolean} refresh [description] + * @param {boolean} refresh If refresh or not. */ protected calculateSectionsStatus(refresh?: boolean): void { this.courseHelper.calculateSectionsStatus(this.sections, this.course.id, refresh).catch(() => { diff --git a/src/core/course/pages/section/section.ts b/src/core/course/pages/section/section.ts index d5fcd1ad9..574165744 100644 --- a/src/core/course/pages/section/section.ts +++ b/src/core/course/pages/section/section.ts @@ -204,6 +204,19 @@ export class CoreCourseSectionPage implements OnDestroy { }); })); + // Get the overview files. + if (this.course.overviewfiles) { + this.course.imageThumb = this.course.overviewfiles[0] && this.course.overviewfiles[0].fileurl; + } else { + promises.push(this.coursesProvider.getCoursesByField('id', this.course.id).then((coursesInfo) => { + if (coursesInfo[0] && coursesInfo[0].overviewfiles && coursesInfo[0].overviewfiles[0]) { + this.course.imageThumb = coursesInfo[0].overviewfiles[0].fileurl; + } else { + this.course.imageThumb = false; + } + })); + } + // Load the course handlers. promises.push(this.courseOptionsDelegate.getHandlersToDisplay(this.injector, this.course, refresh, false) .then((handlers) => { @@ -265,6 +278,7 @@ export class CoreCourseSectionPage implements OnDestroy { promises.push(this.courseProvider.invalidateSections(this.course.id)); promises.push(this.coursesProvider.invalidateUserCourses()); promises.push(this.courseFormatDelegate.invalidateData(this.course, this.sections)); + promises.push(this.coursesProvider.invalidateCoursesByField('id', this.course.id)); if (this.sections) { promises.push(this.prefetchDelegate.invalidateCourseUpdates(this.course.id)); diff --git a/src/core/courses/components/course-progress/course-progress.html b/src/core/courses/components/course-progress/course-progress.html index 73002477a..2f17bc71d 100644 --- a/src/core/courses/components/course-progress/course-progress.html +++ b/src/core/courses/components/course-progress/course-progress.html @@ -1,4 +1,7 @@ +
+ +

diff --git a/src/core/courses/components/course-progress/course-progress.scss b/src/core/courses/components/course-progress/course-progress.scss index 5045e97a7..e4eb027ed 100644 --- a/src/core/courses/components/course-progress/course-progress.scss +++ b/src/core/courses/components/course-progress/course-progress.scss @@ -2,9 +2,32 @@ core-courses-course-progress { ion-card.card { display: flex; flex-direction: column; - justify-content: space-between; + + .core-course-thumb { + height: 150px; + width: 100%; + overflow: hidden; + cursor: pointer; + pointer-events: auto; + position: relative; + + @for $i from 0 to length($core-course-image-background) { + &.core-course-color-#{$i} { + background: nth($core-course-image-background, $i + 1); + } + } + + img { + position: absolute; + top: 0; + bottom: 0; + margin: auto; + } + } .core-course-link { + padding-top: 8px; + padding-bottom: 8px; .item-inner { padding-right: 0; } diff --git a/src/core/courses/pages/course-preview/course-preview.html b/src/core/courses/pages/course-preview/course-preview.html index 450803de9..c5af7affb 100644 --- a/src/core/courses/pages/course-preview/course-preview.html +++ b/src/core/courses/pages/course-preview/course-preview.html @@ -10,6 +10,9 @@ +
+ +

diff --git a/src/core/courses/pages/course-preview/course-preview.scss b/src/core/courses/pages/course-preview/course-preview.scss index 6667a1983..0bb6be28f 100644 --- a/src/core/courses/pages/course-preview/course-preview.scss +++ b/src/core/courses/pages/course-preview/course-preview.scss @@ -1,3 +1,18 @@ page-core-courses-course-preview { + .core-course-thumb { + height: 150px; + width: 100%; + overflow: hidden; + cursor: pointer; + pointer-events: auto; + position: relative; + img { + position: absolute; + top: 0; + bottom: 0; + margin: auto; + width: 100%; + } + } } diff --git a/src/core/courses/pages/course-preview/course-preview.ts b/src/core/courses/pages/course-preview/course-preview.ts index c32b2c093..7679ce57d 100644 --- a/src/core/courses/pages/course-preview/course-preview.ts +++ b/src/core/courses/pages/course-preview/course-preview.ts @@ -96,6 +96,9 @@ export class CoreCoursesCoursePreviewPage implements OnDestroy { this.enrolUrl = this.textUtils.concatenatePaths(currentSiteUrl, 'enrol/index.php?id=' + this.course.id); this.courseUrl = this.textUtils.concatenatePaths(currentSiteUrl, 'course/view.php?id=' + this.course.id); this.paypalReturnUrl = this.textUtils.concatenatePaths(currentSiteUrl, 'enrol/paypal/return.php'); + if (this.course.overviewfiles && this.course.overviewfiles.length > 0) { + this.course.imageThumb = this.course.overviewfiles[0].fileurl; + } // Initialize the self enrol modal. this.selfEnrolModal = this.modalCtrl.create('CoreCoursesSelfEnrolPasswordPage'); diff --git a/src/core/courses/pages/my-courses/my-courses.ts b/src/core/courses/pages/my-courses/my-courses.ts index da0bd3dae..1508d2831 100644 --- a/src/core/courses/pages/my-courses/my-courses.ts +++ b/src/core/courses/pages/my-courses/my-courses.ts @@ -17,6 +17,7 @@ import { IonicPage, NavController } from 'ionic-angular'; import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCoursesProvider } from '../../providers/courses'; import { CoreCourseHelperProvider } from '@core/course/providers/helper'; import { CoreCourseOptionsDelegate } from '@core/course/providers/options-delegate'; @@ -43,11 +44,12 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { protected myCoursesObserver; protected siteUpdatedObserver; protected isDestroyed = false; + protected courseIds = ''; constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider, private domUtils: CoreDomUtilsProvider, private eventsProvider: CoreEventsProvider, private sitesProvider: CoreSitesProvider, private courseHelper: CoreCourseHelperProvider, - private courseOptionsDelegate: CoreCourseOptionsDelegate) { } + private courseOptionsDelegate: CoreCourseOptionsDelegate, private utils: CoreUtilsProvider) { } /** * View loaded. @@ -85,16 +87,33 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { */ protected fetchCourses(): Promise { return this.coursesProvider.getUserCourses().then((courses) => { - - const courseIds = courses.map((course) => { + const promises = [], + courseIds = courses.map((course) => { return course.id; }); - return this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => { + this.courseIds = courseIds.join(','); + + // Load course image of all the courses. + promises.push(this.coursesProvider.getCoursesByField('ids', this.courseIds).then((coursesInfo) => { + coursesInfo = this.utils.arrayToObject(coursesInfo, 'id'); + courses.forEach((course) => { + if (coursesInfo[course.id] && coursesInfo[course.id].overviewfiles && coursesInfo[course.id].overviewfiles[0]) { + course.imageThumb = coursesInfo[course.id].overviewfiles[0].fileurl; + } else { + course.imageThumb = false; + } + }); + })); + + promises.push(this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => { courses.forEach((course) => { course.navOptions = options.navOptions[course.id]; course.admOptions = options.admOptions[course.id]; }); + })); + + return Promise.all(promises).then(() => { this.courses = courses; this.filteredCourses = this.courses; this.filter = ''; @@ -116,6 +135,7 @@ export class CoreCoursesMyCoursesPage implements OnDestroy { promises.push(this.coursesProvider.invalidateUserCourses()); promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions()); + promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds)); Promise.all(promises).finally(() => { diff --git a/src/core/courses/pages/my-overview/my-overview.ts b/src/core/courses/pages/my-overview/my-overview.ts index 956267823..fbc38ec9d 100644 --- a/src/core/courses/pages/my-overview/my-overview.ts +++ b/src/core/courses/pages/my-overview/my-overview.ts @@ -17,6 +17,7 @@ import { IonicPage, NavController } from 'ionic-angular'; import { CoreEventsProvider } from '@providers/events'; import { CoreSitesProvider } from '@providers/sites'; import { CoreDomUtilsProvider } from '@providers/utils/dom'; +import { CoreUtilsProvider } from '@providers/utils/utils'; import { CoreCoursesProvider } from '../../providers/courses'; import { CoreCoursesMyOverviewProvider } from '../../providers/my-overview'; import { CoreCourseHelperProvider } from '@core/course/providers/helper'; @@ -70,12 +71,13 @@ export class CoreCoursesMyOverviewPage implements OnDestroy { protected prefetchIconsInitialized = false; protected isDestroyed; protected updateSiteObserver; + protected courseIds = ''; constructor(private navCtrl: NavController, private coursesProvider: CoreCoursesProvider, private domUtils: CoreDomUtilsProvider, private myOverviewProvider: CoreCoursesMyOverviewProvider, private courseHelper: CoreCourseHelperProvider, private sitesProvider: CoreSitesProvider, private siteHomeProvider: CoreSiteHomeProvider, private courseOptionsDelegate: CoreCourseOptionsDelegate, - private eventsProvider: CoreEventsProvider) { + private eventsProvider: CoreEventsProvider, private utils: CoreUtilsProvider) { } /** @@ -198,17 +200,34 @@ export class CoreCoursesMyOverviewPage implements OnDestroy { */ protected fetchUserCourses(): Promise { return this.coursesProvider.getUserCourses().then((courses) => { - const courseIds = courses.map((course) => { + const promises = [], + courseIds = courses.map((course) => { return course.id; }); // Load course options of the course. - return this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => { + promises.push(this.coursesProvider.getCoursesAdminAndNavOptions(courseIds).then((options) => { courses.forEach((course) => { course.navOptions = options.navOptions[course.id]; course.admOptions = options.admOptions[course.id]; }); + })); + this.courseIds = courseIds.join(','); + + // Load course image of all the courses. + promises.push(this.coursesProvider.getCoursesByField('ids', this.courseIds).then((coursesInfo) => { + coursesInfo = this.utils.arrayToObject(coursesInfo, 'id'); + courses.forEach((course) => { + if (coursesInfo[course.id] && coursesInfo[course.id].overviewfiles && coursesInfo[course.id].overviewfiles[0]) { + course.imageThumb = coursesInfo[course.id].overviewfiles[0].fileurl; + } else { + course.imageThumb = false; + } + }); + })); + + return Promise.all(promises).then(() => { return courses.sort((a, b) => { const compareA = a.fullname.toLowerCase(), compareB = b.fullname.toLowerCase(); @@ -260,6 +279,7 @@ export class CoreCoursesMyOverviewPage implements OnDestroy { promises.push(this.coursesProvider.invalidateUserCourses()); promises.push(this.courseOptionsDelegate.clearAndInvalidateCoursesOptions()); + promises.push(this.coursesProvider.invalidateCoursesByField('ids', this.courseIds)); return Promise.all(promises).finally(() => { switch (this.tabShown) { diff --git a/src/theme/variables.scss b/src/theme/variables.scss index 5c879c9f5..7258d8490 100644 --- a/src/theme/variables.scss +++ b/src/theme/variables.scss @@ -50,6 +50,8 @@ $core-color: $orange; $core-color-light: lighten($core-color, 10%); $core-color-dark: darken($core-color, 10%); +$core-course-image-background: #81ecec, #74b9ff, #a29bfe, #dfe6e9, #00b894, #0984e3, #b2bec3, #fdcb6e, #fd79a8, #6c5ce7; + // Shared Variables // -------------------------------------------------- // To customize the look and feel of this app, you can override