Skip to content

Commit c44b8ee

Browse files
Mutugiiidogi
andauthored
community: smoother voices paginating (fixes #9223) (#9227)
Co-authored-by: dogi <[email protected]>
1 parent 1a656b2 commit c44b8ee

File tree

4 files changed

+91
-33
lines changed

4 files changed

+91
-33
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "planet",
33
"license": "AGPL-3.0",
4-
"version": "0.20.55",
4+
"version": "0.20.56",
55
"myplanet": {
66
"latest": "v0.35.29",
77
"min": "v0.34.29"

src/app/news/news-list.component.html

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,17 @@
3636
</planet-news-list-item>
3737
</div>
3838
</ng-container>
39-
<div #anchor class="loading-anchor"></div>
40-
<div class="spinner-container" style="text-align: center;">
41-
<mat-spinner *ngIf="isLoadingMore"></mat-spinner>
42-
</div>
39+
<mat-paginator *ngIf="replyViewing._id === 'root' && totalItems > 0"
40+
[length]="totalItems"
41+
[pageSize]="pageSize"
42+
[pageIndex]="pageIndex"
43+
[pageSizeOptions]="pageSizeOptions"
44+
(page)="onPageChange($event)"
45+
showFirstLastButtons>
46+
</mat-paginator>
47+
<ng-container *ngIf="replyViewing._id !== 'root'">
48+
<div #anchor class="loading-anchor"></div>
49+
<div class="spinner-container" style="text-align: center;">
50+
<mat-spinner *ngIf="isLoadingMore"></mat-spinner>
51+
</div>
52+
</ng-container>

src/app/news/news-list.component.scss

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,12 @@ mat-divider {
1515
align-items: center;
1616
padding: 16px;
1717
}
18+
19+
mat-paginator {
20+
margin-top: 16px;
21+
background-color: transparent;
22+
}
23+
24+
.loading-anchor {
25+
height: 1px;
26+
}

src/app/news/news-list.component.ts

Lines changed: 67 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
2828
@Input() useReplyRoutes = false;
2929
@Output() viewChange = new EventEmitter<any>();
3030
@Output() changeLabelsFilter = new EventEmitter<{ label: string, action: 'remove' | 'add' | 'select' }>();
31-
@ViewChild('anchor', { static: true }) anchor: any;
31+
@ViewChild('anchor', { static: false }) anchor: any;
3232
observer: IntersectionObserver;
3333
displayedItems: any[] = [];
3434
replyObject: any = {};
@@ -44,9 +44,13 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
4444
totalReplies = 0;
4545
// Key value store for max number of posts viewed per conversation
4646
pageEnd = { root: 10 };
47-
// store the last opened threads root post id
47+
// store the last opened thread's root post id
4848
lastRootPostId: string;
4949
trackById = trackById;
50+
// Pagination for main posts
51+
pageIndex = 0;
52+
pageSizeOptions = [ 5, 10, 25, 50 ];
53+
totalItems = 0;
5054

5155
constructor(
5256
private dialog: MatDialog,
@@ -88,20 +92,31 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
8892
}
8993

9094
ngAfterViewInit() {
91-
this.observer = new IntersectionObserver(
92-
([ entry ]) => {
93-
if (entry.isIntersecting && this.hasMoreNews && !this.isLoadingMore) {
94-
this.loadMoreItems();
95-
}
96-
},
97-
{ root: null, rootMargin: '0px', threshold: 1.0 }
98-
);
99-
100-
this.observer.observe(this.anchor.nativeElement);
95+
this.setupObserver();
10196
}
10297

10398
ngOnDestroy() {
104-
this.observer.disconnect();
99+
if (this.observer) {
100+
this.observer.disconnect();
101+
}
102+
}
103+
104+
setupObserver() {
105+
if (this.observer) {
106+
this.observer.disconnect();
107+
}
108+
109+
if (this.anchor?.nativeElement) {
110+
this.observer = new IntersectionObserver(
111+
([ entry ]) => {
112+
if (entry.isIntersecting && this.hasMoreNews && !this.isLoadingMore && this.replyViewing._id !== 'root') {
113+
this.loadMoreItems();
114+
}
115+
},
116+
{ root: null, rootMargin: '0px', threshold: 1.0 }
117+
);
118+
this.observer.observe(this.anchor.nativeElement);
119+
}
105120
}
106121

107122
initNews() {
@@ -166,6 +181,10 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
166181
}
167182
}, 0);
168183
}
184+
// Set up observer for replies view after the anchor element is rendered
185+
if (newsId !== 'root') {
186+
setTimeout(() => this.setupObserver(), 0);
187+
}
169188
}
170189

171190
showPreviousReplies() {
@@ -286,26 +305,46 @@ export class NewsListComponent implements OnInit, OnChanges, AfterViewInit, OnDe
286305
}
287306

288307
loadPagedItems(initial = true) {
289-
let pageSize = this.pageSize;
290-
if (initial) {
291-
this.displayedItems = [];
292-
this.nextStartIndex = 0;
293-
// Take maximum so if fewer posts than page size adding a post doesn't add a "Load More" button
294-
pageSize = Math.max(this.pageEnd[this.replyViewing._id] || this.pageSize, this.pageSize);
295-
}
296-
const news = this.getCurrentItems();
297-
const { items, endIndex, hasMore } = this.paginateItems(news, this.nextStartIndex, pageSize);
308+
if (this.replyViewing._id === 'root') {
309+
if (initial) {
310+
this.pageIndex = 0;
311+
}
312+
const news = this.getCurrentItems();
313+
this.totalItems = news.length;
314+
const start = this.pageIndex * this.pageSize;
315+
const { items } = this.paginateItems(news, start, this.pageSize);
316+
this.displayedItems = items;
317+
this.hasMoreNews = false;
318+
this.isLoadingMore = false;
319+
} else {
320+
let pageSize = this.pageSize;
321+
if (initial) {
322+
this.displayedItems = [];
323+
this.nextStartIndex = 0;
324+
// Take maximum so if fewer posts than page size adding a post doesn't add a "Load More" button
325+
pageSize = Math.max(this.pageEnd[this.replyViewing._id] || this.pageSize, this.pageSize);
326+
}
327+
const news = this.getCurrentItems();
328+
const { items, endIndex, hasMore } = this.paginateItems(news, this.nextStartIndex, pageSize);
298329

299-
this.displayedItems = [ ...this.displayedItems, ...items ];
300-
this.pageEnd[this.replyViewing._id] = this.displayedItems.length;
301-
this.nextStartIndex = endIndex;
302-
this.hasMoreNews = hasMore;
303-
this.isLoadingMore = false;
304-
this.totalReplies = news.length;
330+
this.displayedItems = [ ...this.displayedItems, ...items ];
331+
this.pageEnd[this.replyViewing._id] = this.displayedItems.length;
332+
this.nextStartIndex = endIndex;
333+
this.hasMoreNews = hasMore;
334+
this.isLoadingMore = false;
335+
this.totalReplies = news.length;
336+
}
305337
}
306338

307339
loadMoreItems() {
308340
this.isLoadingMore = true;
309341
this.loadPagedItems(false);
310342
}
343+
344+
onPageChange(event: any) {
345+
this.pageIndex = event.pageIndex;
346+
this.pageSize = event.pageSize;
347+
this.loadPagedItems(false);
348+
window.scrollTo({ top: 0, behavior: 'smooth' });
349+
}
311350
}

0 commit comments

Comments
 (0)