MOBILE-4465 chore: Simplify code on deprecated components

main
Pau Ferrer Ocaña 2023-11-20 10:13:15 +01:00
parent 3c53bf2632
commit 0ddb86d6b8
4 changed files with 14 additions and 520 deletions

View File

@ -12,7 +12,7 @@
// 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 } from '@angular/core'; import { Component, HostBinding, Input } from '@angular/core';
/** /**
* Component to display the description of a module. * 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() 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. @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;
};
} }

View File

@ -1,60 +1,3 @@
<ion-card [attr.course-color]="course.color ? null : course.colorNumber"> <core-courses-course-list-item [course]="course" class="core-course-progress" [showDownload]="showDownload"
<div (click)="openCourse()" class="core-course-thumb" [class.core-course-color-img]="course.courseimage" [layout]="showAll ? 'card' : 'summarycard'">
[style.background-color]="course.color"> </core-courses-course-list-item>
<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>

View File

@ -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;
}
}
}
}

View File

@ -12,21 +12,8 @@
// 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, OnDestroy, OnChanges } from '@angular/core'; import { Component, HostBinding, Input } from '@angular/core';
import { CoreEventCourseStatusChanged, CoreEventObserver, CoreEvents } from '@singletons/events'; import { CoreCourseListItem } from '@features/courses/services/courses';
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';
/** /**
* 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.
@ -41,296 +28,15 @@ import { CoreUser } from '@features/user/services/user';
@Component({ @Component({
selector: 'core-courses-course-progress', selector: 'core-courses-course-progress',
templateUrl: 'core-courses-course-progress.html', 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!: CoreCourseListItem; // The course to render.
@Input() course!: CoreCourseAnyCourseDataWithExtraInfoAndOptions;
@Input() showAll = false; // If true, will show all actions, options, star and progress. @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. @Input() showDownload = true; // If true, will show download button. Only works if the options menu is not shown.
prefetchCourseData: CorePrefetchStatusInfo = { @HostBinding('class.deprecated') get isDeprecated(): boolean {
icon: '', return true;
statusTranslatable: 'core.loading',
status: '',
loading: 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();
}
} }