MOBILE-2554 core: Create infinite scroll component

main
Pau Ferrer Ocaña 2018-09-19 09:53:12 +02:00
parent 2b3ebc5452
commit bf2c75c148
20 changed files with 145 additions and 67 deletions

View File

@ -29,12 +29,7 @@
</a>
</ion-list>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="fetchEvents()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(fetchEvents())">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreEvents($event)"></core-infinite-loading>
</core-loading>
</ion-content>
</core-split-view>

View File

@ -179,6 +179,18 @@ export class AddonCalendarListPage implements OnDestroy {
});
}
/**
* Function to load more events.
*
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise<any>} Resolved when done.
*/
loadMoreEvents(infiniteComplete?: any): Promise<any> {
return this.fetchEvents().finally(() => {
infiniteComplete && infiniteComplete();
});
}
/**
* Get filtered events.
*

View File

@ -15,12 +15,7 @@
<ion-content class="has-footer">
<core-loading [hideUntil]="loaded">
<!-- Load previous messages. -->
<div *ngIf="canLoadMore" padding>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="loadPrevious($event)" position="top">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
<button ion-button block (click)="loadPrevious()" color="light">{{'core.loadmore' | translate }}</button>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadPrevious($event)" position="top"></core-infinite-loading>
<ion-list class="addon-messages-discussion-container" [attr.aria-live]="polite">
<ng-container *ngFor="let message of messages; index as index; last as last">
<ion-chip *ngIf="showDate(message, messages[index - 1])" class="addon-messages-date" color="light">

View File

@ -543,10 +543,10 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
/**
* Function to load previous messages.
*
* @param {any} [infiniteScroll] Infinite scroll object.
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise<any>} Resolved when done.
*/
loadPrevious(infiniteScroll: any): Promise<any> {
loadPrevious(infiniteComplete?: any): Promise<any> {
// If there is an ongoing fetch, wait for it to finish.
return this.waitForFetch().finally(() => {
this.pagesLoaded++;
@ -555,7 +555,7 @@ export class AddonMessagesDiscussionPage implements OnDestroy {
this.pagesLoaded--;
this.domUtils.showErrorModalDefault(error, 'addon.messages.errorwhileretrievingmessages', true);
}).finally(() => {
infiniteScroll.complete();
infiniteComplete && infiniteComplete();
});
});
}

View File

@ -88,12 +88,7 @@
</div>
</core-empty-box>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="fetchMoreDiscussions()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(fetchMoreDiscussions())">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="fetchMoreDiscussions($event)"></core-infinite-loading>
</core-loading>
<ion-fab bottom end *ngIf="forum && forum.cancreatediscussions">

View File

@ -305,13 +305,16 @@ export class AddonModForumIndexComponent extends CoreCourseModuleMainActivityCom
/**
* Convenience function to load more forum discussions.
*
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise<any>} Promise resolved when done.
*/
protected fetchMoreDiscussions(): Promise<any> {
fetchMoreDiscussions(infiniteComplete?: any): Promise<any> {
return this.fetchDiscussions(false).catch((message) => {
this.domUtils.showErrorModalDefault(message, 'addon.mod_forum.errorgetforum', true);
this.canLoadMore = false; // Set to false to prevent infinite calls with infinite-loading.
}).finally(() => {
infiniteComplete && infiniteComplete();
});
}

View File

@ -56,12 +56,7 @@
<core-empty-box *ngIf="!entries.length && !offlineEntries.length" icon="list" [message]="'addon.mod_glossary.noentriesfound' | translate"></core-empty-box>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="loadMoreEntries()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(loadMoreEntries())">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreEntries($event)"></core-infinite-loading>
</core-loading>
<ion-fab bottom end *ngIf="canAdd">

View File

@ -289,11 +289,14 @@ export class AddonModGlossaryIndexComponent extends CoreCourseModuleMainActivity
/**
* Convenience function to load more forum discussions.
*
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise<any>} Promise resolved when done.
*/
loadMoreEntries(): Promise<any> {
loadMoreEntries(infiniteComplete?: any): Promise<any> {
return this.fetchEntries(true).catch((error) => {
this.domUtils.showErrorModalDefault(error, 'addon.mod_glossary.errorloadingentries', true);
}).finally(() => {
infiniteComplete && infiniteComplete();
});
}

View File

@ -32,11 +32,6 @@
<addon-notifications-actions [contextUrl]="notification.contexturl" [courseId]="notification.courseid"></addon-notifications-actions>
</ion-card>
<core-empty-box *ngIf="!notifications || notifications.length <= 0" icon="notifications" [message]="'addon.notifications.therearentnotificationsyet' | translate"></core-empty-box>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="loadMoreNotifications()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="loadMoreNotifications($event)">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreNotifications($event)"></core-infinite-loading>
</core-loading>
</ion-content>

View File

@ -204,11 +204,11 @@ export class AddonNotificationsListPage {
/**
* Load more results.
*
* @param {any} infiniteScroll The infinit scroll instance.
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
*/
loadMoreNotifications(infiniteScroll: any): void {
loadMoreNotifications(infiniteComplete?: any): void {
this.fetchNotifications().finally(() => {
infiniteScroll.complete();
infiniteComplete && infiniteComplete();
});
}

View File

@ -49,6 +49,7 @@ import { CoreNavigationBarComponent } from './navigation-bar/navigation-bar';
import { CoreAttachmentsComponent } from './attachments/attachments';
import { CoreIonTabsComponent } from './ion-tabs/ion-tabs';
import { CoreIonTabComponent } from './ion-tabs/ion-tab';
import { CoreInfiniteLoadingComponent } from './infinite-loading/infinite-loading';
@NgModule({
declarations: [
@ -83,7 +84,8 @@ import { CoreIonTabComponent } from './ion-tabs/ion-tab';
CoreNavigationBarComponent,
CoreAttachmentsComponent,
CoreIonTabsComponent,
CoreIonTabComponent
CoreIonTabComponent,
CoreInfiniteLoadingComponent
],
entryComponents: [
CoreContextMenuPopoverComponent,
@ -125,7 +127,8 @@ import { CoreIonTabComponent } from './ion-tabs/ion-tab';
CoreNavigationBarComponent,
CoreAttachmentsComponent,
CoreIonTabsComponent,
CoreIonTabComponent
CoreIonTabComponent,
CoreInfiniteLoadingComponent
]
})
export class CoreComponentsModule {}

View File

@ -0,0 +1,19 @@
<div *ngIf="enabled && !loadingMore && position != 'top'" padding-horizontal>
<button ion-button block (click)="loadMore()" color="light">
{{'core.loadmore' | translate }}
</button>
</div>
<ion-infinite-scroll [enabled]="enabled && !loadingMore" (ionInfinite)="loadMore($event)" [position]="position">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
<div *ngIf="enabled && !loadingMore && position == 'top'" padding-horizontal>
<button ion-button block (click)="loadMore()" color="light">
{{'core.loadmore' | translate }}
</button>
</div>
<div *ngIf="loadingMore" padding text-center>
<ion-spinner></ion-spinner>
</div>

View File

@ -0,0 +1,68 @@
// (C) Copyright 2015 Martin Dougiamas
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component, Input, Output, EventEmitter } from '@angular/core';
import { InfiniteScroll } from 'ionic-angular';
/**
* Component to show a infinite loading trigger and spinner while more data is being loaded.
*
* Usage:
* <core-infinite-loading [action]="loadingAction" [enabled]="dataLoaded"></core-inifinite-loading>
*/
@Component({
selector: 'core-infinite-loading',
templateUrl: 'core-infinite-loading.html',
})
export class CoreInfiniteLoadingComponent {
@Input() enabled: boolean;
@Input() position = 'bottom';
@Output() action: EventEmitter<() => void>; // Will emit an event when triggered.
loadingMore = false; // Hide button and avoid loading more.
protected infiniteScroll: InfiniteScroll;
constructor() {
this.action = new EventEmitter();
}
/**
* Load More items calling the action provided.
*
* @param {InfiniteScroll} [infiniteScroll] Infinite scroll object only if triggered from the scroll.
*/
loadMore(infiniteScroll?: InfiniteScroll): void {
if (this.loadingMore) {
return;
}
if (infiniteScroll) {
this.infiniteScroll = infiniteScroll;
}
this.loadingMore = true;
this.action.emit(this.complete.bind(this));
}
/**
* Complete loading.
*/
complete(): void {
this.loadingMore = false;
this.infiniteScroll && this.infiniteScroll.complete();
this.infiniteScroll = undefined;
}
}

View File

@ -51,12 +51,7 @@
</ng-container>
</core-dynamic-component>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="showMoreActivities()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(showMoreActivities())">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="showMoreActivities($event)"></core-infinite-loading>
</div>
</core-loading>
<ion-buttons padding end class="core-course-section-nav-buttons" *ngIf="displaySectionSelector && sections && sections.length">

View File

@ -373,9 +373,9 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
/**
* Show more activities (only used when showing all the sections at the same time).
*
* @return {Promise<void>} Resolved when done to change infinite loading status.
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
*/
showMoreActivities(): Promise<void> {
showMoreActivities(infiniteComplete?: any): void {
this.canLoadMore = false;
let modulesLoaded = 0,
@ -399,7 +399,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
// Check if any of the following sections have any content.
let thereAreMore = false;
for (i++; i < this.sections.length; i++) {
if (this.sections[i].hasContent && this.sections[i].modules) {
if (this.sections[i].hasContent && this.sections[i].modules && this.sections[i].modules.length > 0) {
thereAreMore = true;
break;
}
@ -407,7 +407,7 @@ export class CoreCourseFormatComponent implements OnInit, OnChanges, OnDestroy {
this.canLoadMore = thereAreMore;
}
return Promise.resolve();
infiniteComplete && infiniteComplete();
}
/**

View File

@ -16,7 +16,6 @@ import { Injectable } from '@angular/core';
import { NavController } from 'ionic-angular';
import { CoreCoursesProvider } from '@core/courses/providers/courses';
import { CoreCourseFormatHandler } from './format-delegate';
import { CoreCourseProvider } from './course';
/**
* Default handler used when the course format doesn't have a specific implementation.

View File

@ -10,12 +10,7 @@
<ion-item-divider color="light">{{ 'core.courses.totalcoursesearchresults' | translate:{$a: total} }}</ion-item-divider>
<core-empty-box *ngIf="total == 0" icon="search" [message]="'core.courses.nosearchresults' | translate"></core-empty-box>
<core-courses-course-list-item *ngFor="let course of courses" [course]="course"></core-courses-course-list-item>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="loadMoreResults()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="loadMoreResults($event)">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreResults($event)"></core-infinite-loading>
</div>
</ion-content>

View File

@ -54,11 +54,11 @@ export class CoreCoursesSearchPage {
/**
* Load more results.
*
* @param {any} infiniteScroll The infinit scroll instance.
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
*/
loadMoreResults(infiniteScroll: any): void {
loadMoreResults(infiniteComplete?: any): void {
this.searchCourses().finally(() => {
infiniteScroll.complete();
infiniteComplete && infiniteComplete();
});
}

View File

@ -16,13 +16,7 @@
<p *ngIf="participant.lastaccess"><strong>{{ 'core.lastaccess' | translate }}: </strong>{{ participant.lastaccess * 1000 | coreFormatDate:"dfmediumdate"}}</p>
</a>
</ion-list>
<div *ngIf="canLoadMore" padding>
<button ion-button block (click)="fetchData()" color="light">{{'core.loadmore' | translate }}</button>
<ion-infinite-scroll [enabled]="canLoadMore" (ionInfinite)="$event.waitFor(fetchData())">
<ion-infinite-scroll-content></ion-infinite-scroll-content>
</ion-infinite-scroll>
</div>
<core-infinite-loading [enabled]="canLoadMore" (action)="loadMoreData($event)"></core-infinite-loading>
</core-loading>
</ion-content>
</core-split-view>

View File

@ -82,6 +82,18 @@ export class CoreUserParticipantsComponent implements OnInit {
});
}
/**
* Function to load more data.
*
* @param {any} [infiniteComplete] Infinite scroll complete function. Only used from core-infinite-loading.
* @return {Promise<any>} Resolved when done.
*/
loadMoreData(infiniteComplete?: any): Promise<any> {
return this.fetchData().finally(() => {
infiniteComplete && infiniteComplete();
});
}
/**
* Refresh data.
*