Skip to content

Commit

Permalink
MOBILE-4653 loading: Add placeholder types for loading
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyserver committed Jan 30, 2025
1 parent ba81d76 commit 443e391
Show file tree
Hide file tree
Showing 34 changed files with 126 additions and 44 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h2>{{ 'addon.block_activitymodules.pluginname' | translate }}</h2>
</ion-label>
</ion-item-divider>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px" [placeholderLimit]="8">
<ion-item class="ion-text-wrap" *ngFor="let entry of entries" [detail]="true" button (click)="gotoCoureListModType(entry)">
<core-mod-icon slot="start" [modicon]="entry.icon" [modname]="entry.iconModName" [showAlt]="false" [colorize]="false"
[isBranded]="entry.branded" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ <h2>{{ 'addon.block_myoverview.pluginname' | translate }}</h2>
</div>
</div>
</ion-item-divider>
<core-loading [hideUntil]="loaded">

<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="120px">
<ion-row class="ion-hide-md-up addon-block-myoverview-filter" *ngIf="hasCourses">
<ion-col>
<!-- Filter courses. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,4 +52,8 @@
@include margin(null, 12px, null, null);
}
}

core-loading {
--loading-placeholder-wrap: wrap;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ <h2>{{ 'addon.block_recentlyaccessedcourses.pluginname' | translate }}</h2>
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId" />
</div>
</ion-item-divider>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="280px" placeholderHeight="134px" [placeholderLimit]="4">
<core-empty-box *ngIf="courses.length === 0" image="assets/img/icons/courses.svg"
[message]="'addon.block_recentlyaccessedcourses.nocourses' | translate" />
<!-- List of courses. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ <h2>{{ 'addon.block_recentlyaccesseditems.pluginname' | translate }}</h2>
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId" />
</div>
</ion-item-divider>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="280px" placeholderHeight="66px" [placeholderLimit]="4">
<div [id]="scrollElementId" [hidden]="!items || items.length === 0" class="core-horizontal-scroll"
(scroll)="scrollControls.updateScrollPosition()">
<div *ngIf="items" (onResize)="scrollControls.updateScrollPosition()" class="flex-row">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,4 @@
.core-course-module-handler {
--inner-border-width: 0px;
}
core-loading {
--loading-inline-min-height: 102px;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h2>{{ 'addon.block_sitemainmenu.pluginname' | translate }}</h2>
</ion-label>
</ion-item-divider>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px" [placeholderLimit]="8">
<ion-list *ngIf="mainMenuBlock" class="core-course-module-list-wrapper list-item-limited-width">
<ion-item class="ion-text-wrap" *ngIf="mainMenuBlock.summary">
<ion-label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ <h2>{{ 'addon.block_starredcourses.pluginname' | translate }}</h2>
<core-horizontal-scroll-controls #scrollControls [aria-controls]="scrollElementId" />
</div>
</ion-item-divider>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="280px" placeholderHeight="134px" [placeholderLimit]="4">
<core-empty-box *ngIf="courses.length === 0" image="assets/img/icons/courses.svg"
[message]="'addon.block_starredcourses.nocourses' | translate" />
<!-- List of courses. -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<h2>{{ 'addon.block_timeline.pluginname' | translate }}</h2>
</ion-label>
</ion-item-divider>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="120px" [placeholderLimit]="1">
<ion-row class="ion-hide-md-up addon-block-timeline-filter" *ngIf="(search$ | async) !== null">
<ion-col>
<!-- Filter courses. -->
Expand Down
2 changes: 1 addition & 1 deletion src/addons/messages/pages/discussion/discussion.html
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ <h1>
</core-navbar-buttons>
</ion-header>
<ion-content (ionScroll)="scrollFunction()">
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="36px">
<!-- Load previous messages. -->
<core-infinite-loading [enabled]="canLoadMore" (action)="loadPrevious($event)" position="top" [error]="loadMoreError" />

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ <h1>{{ 'addon.messages.messages' | translate }}</h1>
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>

<core-loading [hideUntil]="loaded" [message]="loadingMessage">
<core-loading [hideUntil]="loaded" [message]="loadingMessage" placeholderType="grid" placeholderWidth="100%"
placeholderHeight="48px">
<ion-list>
<ion-item class="ion-text-wrap" (click)="gotoContacts()" [detail]="true" button>
<ion-icon name="fas-address-book" slot="start" aria-hidden="true" />
Expand Down
2 changes: 1 addition & 1 deletion src/addons/notifications/pages/list/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ <h1>{{ 'addon.notifications.notifications' | translate }}</h1>
<ion-refresher slot="fixed" [disabled]="!notifications.loaded" (ionRefresh)="refreshNotifications($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>
<core-loading [hideUntil]="notifications.loaded">
<core-loading [hideUntil]="notifications.loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px">
<ion-card class="core-warning-card core-card-with-buttons" *ngIf="!hasNotificationsPermission && !permissionWarningHidden">
<ion-item class="ion-text-wrap">
<ion-icon name="fas-circle-info" slot="start" aria-hidden="true" />
Expand Down
2 changes: 1 addition & 1 deletion src/addons/notifications/pages/settings/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ <h1>{{ 'addon.notifications.notifications' | translate }}</h1>
<ion-refresher slot="fixed" [disabled]="!preferencesLoaded" (ionRefresh)="refreshPreferences($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>
<core-loading [hideUntil]="preferencesLoaded">
<core-loading [hideUntil]="preferencesLoaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px">
@if (warningMessage()) {
<ion-card class="core-warning-card ion-margin-top">
<ion-item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ <h1>{{ 'addon.storagemanager.managedownloads' | translate }}</h1>
</ion-toolbar>
</ion-header>
<ion-content class="limited-width">
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="84px">
<div class="ion-padding-horizontal ion-text-wrap" *ngIf="spaceUsage">
<h2>{{ 'addon.storagemanager.alldata' | translate }}</h2>
</div>
Expand Down
14 changes: 12 additions & 2 deletions src/core/components/loading/core-loading.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
<div class="core-loading-container" *ngIf="!hideUntil" role="status" @coreShowHideAnimation>
<ng-content *ngIf="loaded" @coreShowHideAnimation />
@if (!hideUntil) {
<div class="core-loading-container" role="status" @coreShowHideAnimation [attr.aria-label]="message">
@if (!placeholderType) {
<ion-spinner aria-hidden="true" />
<p class="core-loading-message" *ngIf="message" role="status">{{message}}</p>
} @else {
<div class="{{placeholderType}} list-item-limited-width placeholder">
<div *ngFor="let _ of [].constructor(placeholderLimit)" class="placeholder-element"
[ngStyle]="{'width': placeholderWidth, 'height': placeholderHeight}">
</div>
</div>
}
</div>
<ng-content *ngIf="loaded" @coreShowHideAnimation />
}
50 changes: 47 additions & 3 deletions src/core/components/loading/loading.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

@mixin inline() {
&:not(.core-loading-loaded) {
min-height: var(--internal-loading-inline-min-height);
min-height: calc(var(--internal-loading-inline-min-height) + 32px);
width: 100%;
position: relative;
}
Expand All @@ -13,7 +13,7 @@
height: auto;

.core-loading-message {
@include margin(0, 0, 0, 10px);
@include margin(0px, 0px, 0px, 16px);
}
}
}
Expand All @@ -29,6 +29,9 @@
--loading-display: flex;
--loading-display-message: block;
--contents-display: block;
--loading-placeholder-direction: row;
--loading-placeholder-justify: center;
--loading-placeholder-wrap: wrap;

@include core-transition(all, 200ms);
display: var(--contents-display);
Expand Down Expand Up @@ -63,14 +66,50 @@
flex-direction: column;

.core-loading-message {
@include margin(10px, 0, 0, 0);
@include margin(16px, 0, 0, 0);
display: var(--loading-display-message);
}

ion-spinner {
--color: var(--loading-spinner);
color: var(--color);
}

.placeholder {
position: absolute;
@include position(0, 0, 0, 0);
height: 100%;
width: 100%;
display: flex;
flex-direction: var(--loading-placeholder-direction);
padding: 16px;
gap: 16px;
flex-wrap: var(--loading-placeholder-wrap);
justify-content: var(--loading-placeholder-justify);
align-items: center;
overflow: hidden;

.placeholder-element {
width: 100px;
height: 100px;
background: linear-gradient(90deg, #e0e0e0 25%, #f0f0f0 50%, #e0e0e0 75%);
background-size: 200% 100%;
animation: core-loading 5s infinite ease-in-out;
border-radius: var(--mdl-shape-borderRadius-lg);
flex-shrink: 0;
}

&.rounded {
padding: 4px;
gap: 12px;

.placeholder-element {
width: 48px;
height: 48px;
border-radius: 100%;
}
}
}
}

&.core-loading-inline {
Expand All @@ -84,3 +123,8 @@
// Implicit Inline.
@include inline();
}

@keyframes core-loading {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
31 changes: 25 additions & 6 deletions src/core/components/loading/loading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

import { Component, Input, OnInit, OnChanges, SimpleChange, ElementRef, AfterViewInit, OnDestroy } from '@angular/core';
import { Component, Input, OnInit, OnChanges, SimpleChange, ElementRef, AfterViewInit, OnDestroy, HostBinding } from '@angular/core';

import { CoreUtils } from '@singletons/utils';
import { CoreAnimations } from '@components/animations';
Expand Down Expand Up @@ -55,6 +55,10 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
@Input({ transform: toBoolean }) hideUntil = false; // Determine when should the contents be shown.
@Input() message?: string; // Message to show while loading.
@Input({ transform: toBoolean }) fullscreen = true; // Use the whole screen.
@Input() placeholderType?: string;
@Input() placeholderWidth?: string;
@Input() placeholderHeight?: string;
@Input() placeholderLimit = 20;

uniqueId: string;
loaded = false;
Expand All @@ -64,6 +68,26 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
protected onReadyPromise = new CorePromisedValue<void>();
protected mutationObserver: MutationObserver;

@HostBinding('class.core-loading-inline')
get inlineClass(): boolean {
return !this.fullscreen;
}

@HostBinding('attr.aria-busy')
get ariaBusy(): string {
return this.loaded ? 'false' : 'true';
}

@HostBinding('style.--loading-inline-min-height')
get minHeith(): string | undefined {
return this.placeholderHeight;
}

@HostBinding('class.core-loading-loaded')
get loadedClass(): boolean {
return this.loaded;
}

constructor(element: ElementRef) {
this.element = element.nativeElement;
CoreDirectivesRegistry.register(this.element, this);
Expand Down Expand Up @@ -102,7 +126,6 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
// Default loading message.
this.message = Translate.instant('core.loading');
}
this.element.classList.toggle('core-loading-inline', !this.fullscreen);
}

/**
Expand Down Expand Up @@ -132,12 +155,8 @@ export class CoreLoadingComponent implements OnInit, OnChanges, AfterViewInit, A
* Change loaded state.
*
* @param loaded True to load, false otherwise.
* @returns Promise resolved when done.
*/
async changeState(loaded: boolean): Promise<void> {
this.element.classList.toggle('core-loading-loaded', loaded);
this.element.setAttribute('aria-busy', loaded ? 'false' : 'true');

if (this.loaded === loaded) {
return;
}
Expand Down
4 changes: 3 additions & 1 deletion src/core/features/block/components/block/block.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
}

::ng-deep core-loading {
--loading-inline-min-height: 44px;
--loading-inline-min-height: 60px;
--loading-placeholder-justify: flex-start;
--loading-placeholder-wrap: nowrap;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ <h2>
</h2>
</ion-label>
</ion-item-divider>
<core-loading [hideUntil]="loaded" [fullscreen]="false">
<core-loading [hideUntil]="loaded" [fullscreen]="false" placeholderType="grid" placeholderWidth="100%" placeholderHeight="120px"
[placeholderLimit]="1">
<ion-item *ngIf="block.contents?.content" class="ion-text-wrap core-block-content">
<ion-label>
<core-format-text [text]="block.contents?.content" contextLevel="block" [contextInstanceId]="block.instanceid"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
<ion-refresher slot="fixed" [disabled]="!loaded" (ionRefresh)="doRefresh($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="120px">
<ion-list *ngIf="blocks.length > 0">
<ng-container *ngFor="let block of blocks">
<core-block *ngIf="block.visible" [block]="block" [contextLevel]="contextLevel" [instanceId]="instanceId" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</core-navbar-buttons>
<core-dynamic-component [component]="courseFormatComponent" [data]="data">
<!-- Default course format. -->
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px">

<!-- Single section. -->
<div *ngIf="selectedSection && selectedSection.id !== allSectionsId" class="list-item-limited-width">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ <h1 id="core-course-section-selector-label">{{ 'core.course.courseindex' | trans
</ion-toolbar>
</ion-header>
<ion-content>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px">
<ion-list *ngIf="loaded" id="core-course-section-selector" role="listbox" aria-labelledby="core-course-section-selector-label">
<ng-container *ngFor="let section of sectionsToRender">
<ion-item *ngIf="allSectionId === section.id" class="divider core-course-index-all"
Expand Down
2 changes: 1 addition & 1 deletion src/core/features/course/pages/contents/contents.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>

<core-loading [hideUntil]="dataLoaded && !updatingData">
<core-loading [hideUntil]="dataLoaded && !updatingData" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px">
<core-course-format [course]="course" [sections]="sections" [initialSectionId]="sectionId" [initialSectionNumber]="sectionNumber"
[initialBlockInstanceId]="blockInstanceId" [moduleId]="moduleId" class="core-course-format-{{course.format}}"
*ngIf="dataLoaded && sections" [isGuest]="isGuest" />
Expand Down
2 changes: 1 addition & 1 deletion src/core/features/courses/pages/categories/categories.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ <h1>
<ion-refresher slot="fixed" [disabled]="!categoriesLoaded" (ionRefresh)="refreshCategories($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>
<core-loading [hideUntil]="categoriesLoaded">
<core-loading [hideUntil]="categoriesLoaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="108px">
<ion-list class="list-item-limited-width">
<ion-item *ngIf="currentCategory" class="ion-text-wrap">
<ion-icon name="fas-folder" slot="start" [attr.aria-label]="'core.category' | translate" />
Expand Down
2 changes: 1 addition & 1 deletion src/core/features/courses/pages/dashboard/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>

<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="96px">
<ion-list class="list-item-limited-width" *ngIf="hasMainBlocks">
<ng-container *ngFor="let block of blocks">
<core-block *ngIf="block.visible" [block]="block" contextLevel="user" [instanceId]="userId" />
Expand Down
2 changes: 1 addition & 1 deletion src/core/features/courses/pages/list/list.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ <h1 *ngIf="showOnlyEnrolled">{{ 'core.courses.mycourses' | translate }}</h1>
[placeholder]="'core.courses.search' | translate" [searchLabel]="'core.courses.search' | translate" [autoFocus]="searchMode"
searchArea="CoreCoursesSearch" [lengthCheck]="1" />

<core-loading [hideUntil]="loaded" [message]="loadingMessage">
<core-loading [hideUntil]="loaded" [message]="loadingMessage" placeholderType="grid" placeholderWidth="100%" placeholderHeight="108px">
<ng-container *ngIf="searchMode && searchTotal > 0">
<ion-item-divider>
<ion-label>
Expand Down
2 changes: 1 addition & 1 deletion src/core/features/grades/pages/course/course.html
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ <h1>{{ title }}</h1>
<ion-refresher slot="fixed" [disabled]="!columns || !rows" (ionRefresh)="refreshGrades($event.target)">
<ion-refresher-content pullingText="{{ 'core.pulltorefresh' | translate }}" />
</ion-refresher>
<core-loading [hideUntil]="loaded">
<core-loading [hideUntil]="loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="36px">
<core-empty-box *ngIf="!rows.length" icon="fas-chart-bar" [message]="'core.grades.nogradesreturned' | translate" />
<div *ngIf="rows.length" class="core-grades-container">
<table class="core-table core-grades-table" [class.summary]="showSummary">
Expand Down
Loading

0 comments on commit 443e391

Please sign in to comment.