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 160b90f commit 6732e4d
Show file tree
Hide file tree
Showing 24 changed files with 116 additions and 34 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
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: 8px;
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';

Check failure on line 15 in src/core/components/loading/loading.ts

View workflow job for this annotation

GitHub Actions / test

This line has a length of 133. Maximum allowed is 132

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/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
3 changes: 1 addition & 2 deletions src/core/features/mainmenu/pages/menu/menu.html
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
<ion-tabs #mainTabs [hidden]="!showTabs" [class]="'placement-' + tabsPlacement"
[class.tabshidden]="!isMainScreen && tabsPlacement === 'bottom'" (ionTabsDidChange)="tabChanged($event)">
<ion-tab-bar slot="bottom" class="mainmenu-tabs" [@menuVisibilityAnimation]="visibility">
<ion-spinner *ngIf="!loaded" [attr.aria-label]="'core.loading' | translate" />

<core-loading [hideUntil]="loaded" placeholderType="rounded" [placeholderLimit]="8" />
<core-user-menu-button *ngIf="loaded && tabsPlacement === 'side'" [alwaysShow]="true" />

<ion-tab-button *ngFor="let tab of tabs" (keydown)="tabAction.keyDown(tab.page, $event)" (keyup)="tabAction.keyUp(tab.page, $event)"
Expand Down
6 changes: 6 additions & 0 deletions src/core/features/mainmenu/pages/menu/menu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ ion-tab-button {
}

ion-tabs.placement-bottom {

ion-tab-button {
border-top: 4px solid transparent;
border-bottom: 4px solid transparent;
Expand Down Expand Up @@ -134,6 +135,11 @@ ion-tabs.placement-bottom {
ion-tabs.placement-side {
flex-direction: row;

core-loading {
--loading-placeholder-direction: column;
--loading-placeholder-justify: flex-start;
}

ion-tab-bar {
order: -1;
width: var(--menutabbar-size);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<core-search-box [disabled]="searchInProgress" [spellcheck]="false" [lengthCheck]="1" autocorrect="off"
searchArea="CoreUserParticipants" (onSubmit)="search($event)" (onClear)="clearSearch()" />

<core-loading [hideUntil]="participants.loaded">
<core-loading [hideUntil]="participants.loaded" placeholderType="grid" placeholderWidth="100%" placeholderHeight="48px">
<core-empty-box *ngIf="participants.empty && !searchInProgress && !searchQuery" icon="far-user"
[message]="'core.user.noparticipants' | translate" />

Expand Down

0 comments on commit 6732e4d

Please sign in to comment.