MOBILE-4465 chore: Simplify code on deprecated components
parent
3c53bf2632
commit
0ddb86d6b8
|
@ -12,7 +12,7 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { Component, HostBinding, Input } from '@angular/core';
|
||||
|
||||
/**
|
||||
* Component to display the description of a module.
|
||||
|
@ -47,4 +47,8 @@ export class CoreCourseModuleDescriptionComponent {
|
|||
@Input() contextInstanceId?: number; // The instance ID related to the context.
|
||||
@Input() courseId?: number; // Course ID the text belongs to. It can be used to improve performance with filters.
|
||||
|
||||
@HostBinding('class.deprecated') get isDeprecated(): boolean {
|
||||
return true;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -1,60 +1,3 @@
|
|||
<ion-card [attr.course-color]="course.color ? null : course.colorNumber">
|
||||
<div (click)="openCourse()" class="core-course-thumb" [class.core-course-color-img]="course.courseimage"
|
||||
[style.background-color]="course.color">
|
||||
<img *ngIf="course.courseimage" [src]="course.courseimage" core-external-content alt="" />
|
||||
</div>
|
||||
<ion-item button (click)="openCourse()" [attr.aria-label]="course.displayname || course.fullname" class="core-course-header"
|
||||
[class.core-course-only-title]="!showAll || progress < 0 && completionUserTracked === false" detail="false">
|
||||
<ion-label class="ion-text-wrap core-course-title"
|
||||
[class.core-course-with-buttons]="courseOptionMenuEnabled || (downloadCourseEnabled && showDownload)"
|
||||
[class.core-course-with-spinner]="(downloadCourseEnabled && prefetchCourseData.icon == 'spinner') || showSpinner">
|
||||
<p *ngIf="course.categoryname || (course.displayname && course.shortname && course.fullname != course.displayname)"
|
||||
class="core-course-additional-info">
|
||||
<span class="sr-only">{{ 'core.courses.aria:coursecategory' | translate }}</span>
|
||||
<span *ngIf="course.categoryname" class="core-course-category">
|
||||
<core-format-text [text]="course.categoryname"></core-format-text>
|
||||
</span>
|
||||
<span *ngIf="course.categoryname && course.displayname && course.shortname && course.fullname != course.displayname"
|
||||
class="core-course-category"> | </span>
|
||||
<span *ngIf="course.displayname && course.shortname && course.fullname != course.displayname" class="core-course-shortname">
|
||||
<core-format-text [text]="course.shortname" contextLevel="course" [contextInstanceId]="course.id">
|
||||
</core-format-text>
|
||||
</span>
|
||||
</p>
|
||||
<p class="item-heading">
|
||||
<ion-icon name="fas-star" *ngIf="isFavourite" [attr.aria-label]="'core.courses.favourite' | translate">
|
||||
</ion-icon>
|
||||
<span class="sr-only" *ngIf="isFavourite">{{ 'core.courses.aria:favourite' | translate }}</span>
|
||||
<span class="sr-only">{{ 'core.courses.aria:coursename' | translate }}</span>
|
||||
<core-format-text [text]="course.fullname" contextLevel="course" [contextInstanceId]="course.id"></core-format-text>
|
||||
</p>
|
||||
</ion-label>
|
||||
|
||||
<div class="core-button-spinner" *ngIf="downloadCourseEnabled && !courseOptionMenuEnabled && showDownload" slot="end">
|
||||
<core-download-refresh [status]="prefetchCourseData.status" [enabled]="downloadCourseEnabled"
|
||||
[statusTranslatable]="prefetchCourseData.statusTranslatable" [canTrustDownload]="false"
|
||||
[loading]="prefetchCourseData.loading" (action)="prefetchCourse()"></core-download-refresh>
|
||||
</div>
|
||||
|
||||
<div class="core-button-spinner" *ngIf="courseOptionMenuEnabled" slot="end">
|
||||
<!-- Download course spinner. -->
|
||||
<ion-spinner *ngIf="(downloadCourseEnabled && prefetchCourseData.icon == 'spinner') || showSpinner"
|
||||
[attr.aria-label]="'core.loading' | translate"></ion-spinner>
|
||||
|
||||
<!-- Downloaded icon. -->
|
||||
<ion-icon *ngIf="downloadCourseEnabled && prefetchCourseData.downloadSucceeded && !showSpinner" class="core-icon-downloaded"
|
||||
name="fam-cloud-done" color="success" role="status" [attr.aria-label]="'core.downloaded' | translate"></ion-icon>
|
||||
|
||||
<!-- Options menu. -->
|
||||
<ion-button fill="clear" (click)="showCourseOptionsMenu($event)" *ngIf="!showSpinner"
|
||||
[attr.aria-label]="('core.displayoptions' | translate)">
|
||||
<ion-icon name="ellipsis-vertical" slot="icon-only" aria-hidden="true"></ion-icon>
|
||||
</ion-button>
|
||||
</div>
|
||||
</ion-item>
|
||||
<ion-item *ngIf="showAll && progress >= 0 && completionUserTracked !== false" class="core-course-progress">
|
||||
<ion-label>
|
||||
<core-progress-bar [progress]="progress" a11yText="core.courses.aria:courseprogress"></core-progress-bar>
|
||||
</ion-label>
|
||||
</ion-item>
|
||||
</ion-card>
|
||||
<core-courses-course-list-item [course]="course" class="core-course-progress" [showDownload]="showDownload"
|
||||
[layout]="showAll ? 'card' : 'summarycard'">
|
||||
</core-courses-course-list-item>
|
||||
|
|
|
@ -1,159 +0,0 @@
|
|||
@import "~theme/globals";
|
||||
|
||||
:host {
|
||||
ion-card {
|
||||
--vertical-margin: 12px;
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-self: stretch;
|
||||
height: calc(100% - var(--vertical-margin) - var(--vertical-margin));
|
||||
margin-top: var(--vertical-margin);
|
||||
margin-bottom: var(--vertical-margin);
|
||||
|
||||
@for $i from 0 to length($core-course-image-background) {
|
||||
&[course-color="#{$i}"] .core-course-thumb {
|
||||
background: var(--core-course-color-#{$i});
|
||||
}
|
||||
}
|
||||
|
||||
.core-course-thumb {
|
||||
padding-top: 40%;
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
position: relative;
|
||||
background-position: center;
|
||||
background-size: cover;
|
||||
-webkit-transition: all 50ms ease-in-out;
|
||||
transition: all 50ms ease-in-out;
|
||||
|
||||
&.core-course-color-img {
|
||||
background: var(--ion-item-background);
|
||||
}
|
||||
|
||||
img {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
left: 0;
|
||||
margin: auto;
|
||||
|
||||
// Fill geopaterns
|
||||
&[src$=".svg"] {
|
||||
min-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@if ($core-course-hide-thumb-on-cards) {
|
||||
.core-course-thumb {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@if ($core-course-thumb-on-cards-background) {
|
||||
.core-course-thumb {
|
||||
background: $core-course-thumb-on-cards-background !important;
|
||||
}
|
||||
}
|
||||
|
||||
.core-course-additional-info {
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.core-course-header {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
&.core-course-only-title {
|
||||
&::part(native) {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.core-course-title {
|
||||
margin: 12px 0;
|
||||
flex-grow: 1;
|
||||
|
||||
.item-heading ion-icon {
|
||||
margin-right: 4px;
|
||||
color: var(--core-star-color);
|
||||
}
|
||||
}
|
||||
|
||||
.core-button-spinner {
|
||||
margin: 0;
|
||||
}
|
||||
.core-button-spinner ion-spinner {
|
||||
vertical-align: top; // the better option for most scenarios
|
||||
vertical-align: -webkit-baseline-middle; // the best for those that support it
|
||||
}
|
||||
|
||||
.core-button-spinner .core-icon-downloaded {
|
||||
font-size: 28.8px;
|
||||
margin-top: 8px;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.item-button[icon-only] {
|
||||
min-width: 50px;
|
||||
width: 50px;
|
||||
}
|
||||
}
|
||||
|
||||
@if ($core-course-hide-progress-on-cards) {
|
||||
.core-course-progress {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
z-index: 1;
|
||||
}
|
||||
}
|
||||
|
||||
// Common styles.
|
||||
:host-context(.core-horizontal-scroll) {
|
||||
@include horizontal_scroll_item(80%, 250px, 300px);
|
||||
|
||||
ion-card {
|
||||
.core-course-thumb {
|
||||
padding-top: 30%;
|
||||
}
|
||||
|
||||
.core-course-header {
|
||||
.core-course-title {
|
||||
margin: 7px 0;
|
||||
|
||||
.item-heading ion-icon {
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
&.core-course-with-buttons {
|
||||
max-width: calc(100% - 40px);
|
||||
}
|
||||
}
|
||||
.core-button-spinner {
|
||||
min-height: 40px;
|
||||
min-width: 40px;
|
||||
|
||||
ion-spinner {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
}
|
||||
.item-button[icon-only] {
|
||||
min-width: 40px;
|
||||
width: 40px;
|
||||
padding: 8px;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,21 +12,8 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component, Input, OnInit, OnDestroy, OnChanges } from '@angular/core';
|
||||
import { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events';
|
||||
import { CoreSites } from '@services/sites';
|
||||
import { CoreDomUtils } from '@services/utils/dom';
|
||||
import { CoreCourses, CoreCoursesProvider } from '@features/courses/services/courses';
|
||||
import { CoreCourse, CoreCourseProvider } from '@features/course/services/course';
|
||||
import { CoreCourseHelper, CorePrefetchStatusInfo } from '@features/course/services/course-helper';
|
||||
import { Translate } from '@singletons';
|
||||
import { CoreConstants } from '@/core/constants';
|
||||
import {
|
||||
CoreCourseAnyCourseDataWithExtraInfoAndOptions,
|
||||
CoreEnrolledCourseDataWithExtraInfoAndOptions,
|
||||
} from '../../services/courses-helper';
|
||||
import { CoreCoursesCourseOptionsMenuComponent } from '../course-options-menu/course-options-menu';
|
||||
import { CoreUser } from '@features/user/services/user';
|
||||
import { Component, HostBinding, Input } from '@angular/core';
|
||||
import { CoreCourseListItem } from '@features/courses/services/courses';
|
||||
|
||||
/**
|
||||
* This component is meant to display a course for a list of courses with progress.
|
||||
|
@ -41,296 +28,15 @@ import { CoreUser } from '@features/user/services/user';
|
|||
@Component({
|
||||
selector: 'core-courses-course-progress',
|
||||
templateUrl: 'core-courses-course-progress.html',
|
||||
styleUrls: ['course-progress.scss'],
|
||||
})
|
||||
export class CoreCoursesCourseProgressComponent implements OnInit, OnDestroy, OnChanges {
|
||||
export class CoreCoursesCourseProgressComponent {
|
||||
|
||||
// The course to render.
|
||||
@Input() course!: CoreCourseAnyCourseDataWithExtraInfoAndOptions;
|
||||
@Input() course!: CoreCourseListItem; // The course to render.
|
||||
@Input() showAll = false; // If true, will show all actions, options, star and progress.
|
||||
@Input() showDownload = true; // If true, will show download button. Only works if the options menu is not shown.
|
||||
|
||||
prefetchCourseData: CorePrefetchStatusInfo = {
|
||||
icon: '',
|
||||
statusTranslatable: 'core.loading',
|
||||
status: '',
|
||||
loading: true,
|
||||
@HostBinding('class.deprecated') get isDeprecated(): boolean {
|
||||
return true;
|
||||
};
|
||||
|
||||
showSpinner = false;
|
||||
downloadCourseEnabled = false;
|
||||
courseOptionMenuEnabled = false;
|
||||
isFavourite = false;
|
||||
progress = -1;
|
||||
completionUserTracked: boolean | undefined = false;
|
||||
|
||||
protected courseStatus = CoreConstants.NOT_DOWNLOADED;
|
||||
protected isDestroyed = false;
|
||||
protected courseStatusObserver?: CoreEventObserver;
|
||||
protected siteUpdatedObserver?: CoreEventObserver;
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnInit(): void {
|
||||
|
||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||
|
||||
if (this.downloadCourseEnabled) {
|
||||
this.initPrefetchCourse();
|
||||
}
|
||||
|
||||
// This field is only available from 3.6 onwards.
|
||||
this.courseOptionMenuEnabled = this.showAll && 'isfavourite' in this.course &&
|
||||
this.course.isfavourite !== undefined;
|
||||
|
||||
// Refresh the enabled flag if site is updated.
|
||||
this.siteUpdatedObserver = CoreEvents.on(CoreEvents.SITE_UPDATED, () => {
|
||||
const wasEnabled = this.downloadCourseEnabled;
|
||||
|
||||
this.downloadCourseEnabled = !CoreCourses.isDownloadCourseDisabledInSite();
|
||||
|
||||
if (!wasEnabled && this.downloadCourseEnabled) {
|
||||
// Download course is enabled now, initialize it.
|
||||
this.initPrefetchCourse();
|
||||
}
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
ngOnChanges(): void {
|
||||
this.isFavourite = 'isfavourite' in this.course && !!this.course.isfavourite;
|
||||
this.progress = 'progress' in this.course ? this.course.progress || -1 : -1;
|
||||
this.completionUserTracked = 'completionusertracked' in this.course && this.course.completionusertracked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize prefetch course.
|
||||
*/
|
||||
async initPrefetchCourse(): Promise<void> {
|
||||
if (this.courseStatusObserver !== undefined) {
|
||||
// Already initialized.
|
||||
return;
|
||||
}
|
||||
|
||||
// Listen for status change in course.
|
||||
this.courseStatusObserver = CoreEvents.on(CoreEvents.COURSE_STATUS_CHANGED, (data: CoreEventCourseStatusChanged) => {
|
||||
if (data.courseId == this.course.id || data.courseId == CoreCourseProvider.ALL_COURSES_CLEARED) {
|
||||
this.updateCourseStatus(data.status);
|
||||
}
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
|
||||
// Determine course prefetch icon.
|
||||
const status = await CoreCourse.getCourseStatus(this.course.id);
|
||||
|
||||
this.updateCourseStatus(status);
|
||||
|
||||
if (this.prefetchCourseData.loading) {
|
||||
// Course is being downloaded. Get the download promise.
|
||||
const promise = CoreCourseHelper.getCourseDownloadPromise(this.course.id);
|
||||
if (promise) {
|
||||
// There is a download promise. If it fails, show an error.
|
||||
promise.catch((error) => {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
// No download, this probably means that the app was closed while downloading. Set previous status.
|
||||
CoreCourse.setCoursePreviousStatus(this.course.id);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Open a course.
|
||||
*/
|
||||
openCourse(): void {
|
||||
CoreCourseHelper.openCourse(this.course);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prefetch the course.
|
||||
*
|
||||
* @param e Click event.
|
||||
*/
|
||||
async prefetchCourse(e?: Event): Promise<void> {
|
||||
e?.preventDefault();
|
||||
e?.stopPropagation();
|
||||
|
||||
try {
|
||||
await CoreCourseHelper.confirmAndPrefetchCourse(this.prefetchCourseData, this.course);
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'core.course.errordownloadingcourse', true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the course.
|
||||
*/
|
||||
async deleteCourse(): Promise<void> {
|
||||
try {
|
||||
await CoreDomUtils.showDeleteConfirm(
|
||||
'addon.storagemanager.confirmdeletedatafrom',
|
||||
{ name: this.course.displayname || this.course.fullname },
|
||||
);
|
||||
} catch (error) {
|
||||
if (!CoreDomUtils.isCanceledError(error)) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const modal = await CoreDomUtils.showModalLoading();
|
||||
|
||||
try {
|
||||
await CoreCourseHelper.deleteCourseFiles(this.course.id);
|
||||
} catch (error) {
|
||||
CoreDomUtils.showErrorModalDefault(error, Translate.instant('core.errordeletefile'));
|
||||
} finally {
|
||||
modal.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the course status icon and title.
|
||||
*
|
||||
* @param status Status to show.
|
||||
*/
|
||||
protected updateCourseStatus(status: string): void {
|
||||
const statusData = CoreCourseHelper.getCoursePrefetchStatusInfo(status);
|
||||
|
||||
this.courseStatus = status;
|
||||
this.prefetchCourseData.status = statusData.status;
|
||||
this.prefetchCourseData.icon = statusData.icon;
|
||||
this.prefetchCourseData.statusTranslatable = statusData.statusTranslatable;
|
||||
this.prefetchCourseData.loading = statusData.loading;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show the context menu.
|
||||
*
|
||||
* @param e Click Event.
|
||||
*/
|
||||
async showCourseOptionsMenu(e: Event): Promise<void> {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
const popoverData = await CoreDomUtils.openPopover<string>({
|
||||
component: CoreCoursesCourseOptionsMenuComponent,
|
||||
componentProps: {
|
||||
course: this.course,
|
||||
prefetch: this.prefetchCourseData,
|
||||
},
|
||||
event: e,
|
||||
});
|
||||
|
||||
switch (popoverData) {
|
||||
case 'download':
|
||||
if (!this.prefetchCourseData.loading) {
|
||||
this.prefetchCourse(e);
|
||||
}
|
||||
break;
|
||||
case 'delete':
|
||||
if (this.courseStatus == CoreConstants.DOWNLOADED || this.courseStatus == CoreConstants.OUTDATED) {
|
||||
this.deleteCourse();
|
||||
}
|
||||
break;
|
||||
case 'hide':
|
||||
this.setCourseHidden(true);
|
||||
break;
|
||||
case 'show':
|
||||
this.setCourseHidden(false);
|
||||
break;
|
||||
case 'favourite':
|
||||
this.setCourseFavourite(true);
|
||||
break;
|
||||
case 'unfavourite':
|
||||
this.setCourseFavourite(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide/Unhide the course from the course list.
|
||||
*
|
||||
* @param hide True to hide and false to show.
|
||||
*/
|
||||
protected async setCourseHidden(hide: boolean): Promise<void> {
|
||||
this.showSpinner = true;
|
||||
|
||||
// We should use null to unset the preference.
|
||||
try {
|
||||
await CoreUser.updateUserPreference(
|
||||
'block_myoverview_hidden_course_' + this.course.id,
|
||||
hide ? '1' : undefined,
|
||||
);
|
||||
|
||||
(<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).hidden = hide;
|
||||
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
|
||||
courseId: this.course.id,
|
||||
course: this.course,
|
||||
action: CoreCoursesProvider.ACTION_STATE_CHANGED,
|
||||
state: CoreCoursesProvider.STATE_HIDDEN,
|
||||
value: hide,
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error changing course visibility.');
|
||||
}
|
||||
} finally {
|
||||
this.showSpinner = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Favourite/Unfavourite the course from the course list.
|
||||
*
|
||||
* @param favourite True to favourite and false to unfavourite.
|
||||
*/
|
||||
protected async setCourseFavourite(favourite: boolean): Promise<void> {
|
||||
this.showSpinner = true;
|
||||
|
||||
try {
|
||||
await CoreCourses.setFavouriteCourse(this.course.id, favourite);
|
||||
|
||||
(<CoreEnrolledCourseDataWithExtraInfoAndOptions> this.course).isfavourite = favourite;
|
||||
this.isFavourite = favourite;
|
||||
CoreEvents.trigger(CoreCoursesProvider.EVENT_MY_COURSES_UPDATED, {
|
||||
courseId: this.course.id,
|
||||
course: this.course,
|
||||
action: CoreCoursesProvider.ACTION_STATE_CHANGED,
|
||||
state: CoreCoursesProvider.STATE_FAVOURITE,
|
||||
value: favourite,
|
||||
}, CoreSites.getCurrentSiteId());
|
||||
|
||||
} catch (error) {
|
||||
if (!this.isDestroyed) {
|
||||
CoreDomUtils.showErrorModalDefault(error, 'Error changing course favourite attribute.');
|
||||
}
|
||||
} finally {
|
||||
this.showSpinner = false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Component destroyed.
|
||||
*/
|
||||
ngOnDestroy(): void {
|
||||
this.isDestroyed = true;
|
||||
|
||||
this.siteUpdatedObserver?.off();
|
||||
this.courseStatusObserver?.off();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue