From 115ba52984eb96433b3aa165aea2877913e0e7a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pau=20Ferrer=20Oca=C3=B1a?= Date: Thu, 10 Mar 2022 11:25:05 +0100 Subject: [PATCH] MOBILE-3814 course: Style course summary page --- .../pages/course-summary/course-summary.html | 111 ++++++++++-------- .../pages/course-summary/course-summary.scss | 89 ++++++++++++-- .../pages/course-summary/course-summary.ts | 84 +++++++------ 3 files changed, 192 insertions(+), 92 deletions(-) diff --git a/src/core/features/course/pages/course-summary/course-summary.html b/src/core/features/course/pages/course-summary/course-summary.html index 625e360ae..2b699e288 100644 --- a/src/core/features/course/pages/course-summary/course-summary.html +++ b/src/core/features/course/pages/course-summary/course-summary.html @@ -1,12 +1,9 @@ - + -

- {{'core.course.coursesummary' | translate}} -

@@ -15,27 +12,29 @@
- + -
- +
+ +
- - +
+

-

+

{{ 'core.courses.aria:coursename' | translate }} -

+ {{ 'core.courses.aria:coursecategory' | translate }} @@ -43,7 +42,14 @@ - +
+ + + +
+ +
@@ -51,26 +57,22 @@

- {{ 'core.course.startdate' | translate }}: {{ course.startdate * 1000 | - coreFormatDate:'strftimedatefullshort' }} + {{ 'core.course.startdate' | translate }}
+ {{ course.startdate * 1000 | coreFormatDate:'strftimedaydatetime' }}

- {{ 'core.course.enddate' | translate }}: {{ course.enddate * 1000 | - coreFormatDate:'strftimedatefullshort' }} + {{ 'core.course.enddate' | translate }}
+ {{ course.enddate * 1000 | coreFormatDate:'strftimedaydatetime' }}

- - -

- {{'core.summary' | translate}} + {{'core.course.coursesummary' | translate}}

@@ -78,19 +80,28 @@
- + + -

{{ 'core.teachers' | translate }}

-
-
- - - - -

{{contact.fullname}}

+

+ {{ 'core.teachers' | translate }} +

+ + + + + +

{{contact.fullname}}

+
+
+
@@ -102,23 +113,31 @@ - : + : + - +
- +
+ + + + {{item.data.title | translate }} + + + - +

{{ instance.name }}

@@ -135,22 +154,16 @@
- - -

{{ 'core.courses.notenrollable' | translate }}

-
+
+ + + + + {{ 'core.courses.notenrollable' | translate }} - - - - {{item.data.title | translate }} - - - - + {{ 'core.course' | translate }} diff --git a/src/core/features/course/pages/course-summary/course-summary.scss b/src/core/features/course/pages/course-summary/course-summary.scss index 0386bcac6..477f4a454 100644 --- a/src/core/features/course/pages/course-summary/course-summary.scss +++ b/src/core/features/course/pages/course-summary/course-summary.scss @@ -1,28 +1,99 @@ @import '~theme/globals.scss'; :host { - .core-course-thumb { - overflow: hidden; - text-align: center; - max-height: 35vh; - z-index: -1; - overflow: hidden; - border-bottom: 1px solid var(--stroke); + --thumb-height: 180px; + + ion-content { + position: absolute; } + .core-course-thumb { + background: var(--course-color, white); + overflow: hidden; + text-align: center; + height: var(--thumb-height); + position: fixed; + z-index: -1; + width: 100%; - .core-customfieldvalue core-format-text { - display: inline; + @for $i from 0 to length($core-course-image-background) { + &.course-color-#{$i} { + --course-color: var(--core-course-color-#{$i}); + --course-color-tint: var(--core-course-color-#{$i}-tint); + } + } + + img { + width: 100%; + height: 100%; + object-fit: cover; + } + + ion-icon.course-icon { + padding: 24px; + font-size: calc(var(--thumb-height) - 48px); + color: var(--course-color-tint); + } + } + + .course-container { + position: relative; + top: calc(var(--thumb-height) - var(--big-radius)); + } + + .course-name { + border-radius: var(--big-radius) var(--big-radius) 0 0; + box-shadow: var(--drop-shadow-top); + ion-label { + margin-bottom: 0px; + } + } + + h1 { + font-size: 20px; + } + + .core-course-category { + margin-left: 0; + margin-right: 0; } .core-course-dates { background: var(--light); border-radius: var(--small-radius); padding: 8px; + width: 100%; + + p { + margin-bottom: 8px; + } + + p:last-child { + margin-bottom: 0px; + } ion-icon { @include margin-horizontal(null, 8px); } } + + .core-customfield { + margin-bottom: 8px; + + &.core-customfield_textarea { + display: flex; + flex-direction: column; + margin-bottom: 12px; + } + + .core-customfieldname { + @include margin-horizontal(null, 4px); + font-weight: bold; + display: inline; + } + .core-customfieldvalue { + display: inline; + } + } } diff --git a/src/core/features/course/pages/course-summary/course-summary.ts b/src/core/features/course/pages/course-summary/course-summary.ts index 547e9a6cb..82e096ecf 100644 --- a/src/core/features/course/pages/course-summary/course-summary.ts +++ b/src/core/features/course/pages/course-summary/course-summary.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import { Component, OnDestroy, OnInit, Input } from '@angular/core'; +import { Component, OnDestroy, OnInit, Input, ViewChild, ElementRef } from '@angular/core'; import { IonRefresher } from '@ionic/angular'; import { CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreSites } from '@services/sites'; @@ -35,8 +35,9 @@ import { ModalController, NgZone, Platform, Translate } from '@singletons'; import { CoreCoursesSelfEnrolPasswordComponent } from '../../../courses/components/self-enrol-password/self-enrol-password'; import { CoreNavigator } from '@services/navigator'; import { CoreUtils } from '@services/utils/utils'; -import { CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper'; +import { CoreCoursesHelper, CoreCourseWithImageAndColor } from '@features/courses/services/courses-helper'; import { Subscription } from 'rxjs'; +import { CoreColors } from '@singletons/colors'; /** * Page that shows the summary of a course including buttons to enrol and other available options. @@ -51,23 +52,23 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { @Input() course?: CoreCourseSummaryData; @Input() courseId = 0; + @ViewChild('courseThumb') courseThumb?: ElementRef; + isEnrolled = false; canAccessCourse = true; selfEnrolInstances: CoreCourseEnrolmentMethod[] = []; paypalEnabled = false; dataLoaded = false; isModal = false; + contactsExpanded = false; courseUrl = ''; - courseImageUrl?: string; progress?: number; courseMenuHandlers: CoreCourseOptionsMenuHandlerToDisplay[] = []; - protected isGuestEnabled = false; protected useGuestAccess = false; protected guestInstanceId?: number; - protected enrolmentMethods: CoreCourseEnrolmentMethod[] = []; protected waitStart = 0; protected enrolUrl = ''; protected pageDestroyed = false; @@ -127,25 +128,14 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { * password is required for guest access. */ protected async canAccessAsGuest(): Promise { - if (!this.isGuestEnabled) { - throw Error('Guest access is not enabled.'); + if (this.guestInstanceId === undefined) { + return false; } - // Search instance ID of guest enrolment method. - const method = this.enrolmentMethods.find((method) => method.type == 'guest'); - this.guestInstanceId = method?.id; + const info = await CoreCourses.getCourseGuestEnrolmentInfo(this.guestInstanceId); - if (this.guestInstanceId) { - const info = await CoreCourses.getCourseGuestEnrolmentInfo(this.guestInstanceId); - if (!info.status) { - // Not active, reject. - throw Error('Guest access is not enabled.'); - } - - return info.passwordrequired; - } - - throw Error('Guest enrollment method not found.'); + // Guest access with password is not supported by the app. + return !!info.status && !info.passwordrequired; } /** @@ -158,13 +148,14 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { this.selfEnrolInstances = []; try { - this.enrolmentMethods = await CoreCourses.getCourseEnrolmentMethods(this.courseId); + const enrolmentMethods = await CoreCourses.getCourseEnrolmentMethods(this.courseId); + this.guestInstanceId = undefined; - this.enrolmentMethods.forEach((method) => { + enrolmentMethods.forEach((method) => { if (method.type === 'self') { this.selfEnrolInstances.push(method); } else if (method.type === 'guest') { - this.isGuestEnabled = true; + this.guestInstanceId = method.id; } else if (method.type === 'paypal') { this.paypalEnabled = true; } @@ -189,16 +180,8 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { this.useGuestAccess = false; } catch { // The user is not an admin/manager. Check if we can provide guest access to the course. - try { - this.canAccessCourse = !(await this.canAccessAsGuest()); - this.useGuestAccess = this.canAccessCourse; - } catch { - this.canAccessCourse = false; - } - } - - if (this.course && 'overviewfiles' in this.course && this.course.overviewfiles?.length) { - this.courseImageUrl = this.course.overviewfiles[0].fileurl; + this.canAccessCourse = await this.canAccessAsGuest(); + this.useGuestAccess = this.canAccessCourse; } try { @@ -219,6 +202,8 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { // Ignore errors. } + await this.setCourseColor(); + if (!this.course || !('progress' in this.course) || typeof this.course.progress !== 'number' || @@ -433,6 +418,37 @@ export class CoreCourseSummaryPage implements OnInit, OnDestroy { CoreNavigator.navigateToSitePath(item.data.page, { params }); } + /** + * Set course color. + */ + protected async setCourseColor(): Promise { + if (!this.course) { + return; + } + + await CoreCoursesHelper.loadCourseColorAndImage(this.course); + + if (!this.courseThumb) { + return; + } + + if (this.course.color) { + this.courseThumb.nativeElement.style.setProperty('--course-color', this.course.color); + + const tint = CoreColors.lighter(this.course.color, 50); + this.courseThumb.nativeElement.style.setProperty('--course-color-tint', tint); + } else if(this.course.colorNumber !== undefined) { + this.courseThumb.nativeElement.classList.add('course-color-' + this.course.colorNumber); + } + } + + /** + * Toggle list of contacts. + */ + toggleContacts(): void { + this.contactsExpanded = !this.contactsExpanded; + } + /** * Close the modal. */