1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-23 01:27:14 +02:00

Fixing media merging #706

This commit is contained in:
Patrik J. Braun 2023-09-01 22:54:31 +02:00
parent 7b7afc01f0
commit 442a9ab690
2 changed files with 111 additions and 118 deletions

View File

@ -74,7 +74,7 @@ describe('GalleryGridComponent', () => {
component.mediaGroups = [{name: 'equal 1', media: [phs[0], phs[1]]}]; component.mediaGroups = [{name: 'equal 1', media: [phs[0], phs[1]]}];
component.mediaToRender = [{name: 'equal 1', media: [gPhs[0], gPhs[1]]}]; component.mediaToRender = [{name: 'equal 1', media: [gPhs[0], gPhs[1]]}];
component.mergeNewPhotos(); component.mergeNewPhotos();
expect(component.mediaToRender).toEqual([{name: 'equal 1', media: [gPhs[0], gPhs[1]]}]); expect(component.mediaToRender).toEqual([{name: 'equal 1', media: [gPhs[0],gPhs[1]]}]);
/*-----------------------*/ /*-----------------------*/
component.mediaGroups = [{name: 'empty render', media: [phs[0], phs[1]]}]; component.mediaGroups = [{name: 'empty render', media: [phs[0], phs[1]]}];
component.mediaToRender = []; component.mediaToRender = [];
@ -109,7 +109,7 @@ describe('GalleryGridComponent', () => {
component.mediaGroups = [{name: 'removed 2nd 2', media: [phs[0], phs[1]]}, {name: '2', media: [phs[2], phs[5]]}]; component.mediaGroups = [{name: 'removed 2nd 2', media: [phs[0], phs[1]]}, {name: '2', media: [phs[2], phs[5]]}];
component.mediaToRender = [{name: 'removed 2nd 2', media: [gPhs[0], gPhs[1]]}, {name: '2', media: [gPhs[2], gPhs[5], gPhs[3], gPhs[4]]}]; component.mediaToRender = [{name: 'removed 2nd 2', media: [gPhs[0], gPhs[1]]}, {name: '2', media: [gPhs[2], gPhs[5], gPhs[3], gPhs[4]]}];
component.mergeNewPhotos(); component.mergeNewPhotos();
expect(component.mediaToRender).toEqual([{name: 'removed 2nd 2', media: [gPhs[0], gPhs[1]]}, {name: '2', media: [gPhs[2]]}]); expect(component.mediaToRender).toEqual([{name: 'removed 2nd 2', media: [gPhs[0], gPhs[1]]}, {name: '2', media: [gPhs[2], gPhs[5]]}]);
/*-----------------------*/ /*-----------------------*/
component.mediaGroups = [{name: 'removed from 1st', media: [phs[0]]},{name: '2', media: [phs[2],phs[3],phs[4]]}]; component.mediaGroups = [{name: 'removed from 1st', media: [phs[0]]},{name: '2', media: [phs[2],phs[3],phs[4]]}];
component.mediaToRender = [{name: 'removed from 1st', media: [gPhs[0], gPhs[1]]},{name: '2', media: [gPhs[2], gPhs[3], gPhs[4]]}]; component.mediaToRender = [{name: 'removed from 1st', media: [gPhs[0], gPhs[1]]},{name: '2', media: [gPhs[2], gPhs[3], gPhs[4]]}];
@ -129,12 +129,20 @@ describe('GalleryGridComponent', () => {
component.mediaGroups = [{name: 'merged', media: [phs[0], phs[1],phs[2],phs[3]]}]; component.mediaGroups = [{name: 'merged', media: [phs[0], phs[1],phs[2],phs[3]]}];
component.mediaToRender = [{name: 'merged dif name', media: [gPhs[0], gPhs[1]]},{name: '2', media: [gPhs[2], gPhs[3]]}]; component.mediaToRender = [{name: 'merged dif name', media: [gPhs[0], gPhs[1]]},{name: '2', media: [gPhs[2], gPhs[3]]}];
component.mergeNewPhotos(); component.mergeNewPhotos();
expect(component.mediaToRender).toEqual([{name: 'merged', media: [gPhs[0], gPhs[1]]}]); expect(component.mediaToRender).toEqual([{name: 'merged', media: [gPhs[0]]}]);
/*-----------------------*/ /*-----------------------*/
component.mediaGroups = [{name: '3', media: [phs[0], phs[1],phs[2],phs[3]]}]; component.mediaGroups = [{name: '3', media: [phs[0], phs[1],phs[2],phs[3]]}];
component.mediaToRender = [{name: '1', media: [gPhs[0], gPhs[1],gPhs[3], gPhs[2]]}]; component.mediaToRender = [{name: '1', media: [gPhs[0], gPhs[1],gPhs[3], gPhs[2]]}];
component.mergeNewPhotos(); component.mergeNewPhotos();
expect(component.mediaToRender).toEqual([{name: '3', media: [gPhs[0], gPhs[1]]}]); expect(component.mediaToRender).toEqual([{name: '3', media: [gPhs[0], gPhs[1]]}]);
/*-----------------------*/
gPhs[1].rowId = 3;
gPhs[3].rowId = 3;
gPhs[2].rowId = 3;
component.mediaGroups = [{name: '3', media: [phs[0], phs[1],phs[2],phs[3]]}];
component.mediaToRender = [{name: '1', media: [gPhs[0], gPhs[1],gPhs[3], gPhs[2]]}];
component.mergeNewPhotos();
expect(component.mediaToRender).toEqual([{name: '3', media: [gPhs[0]]}]);
}); });
}); });

View File

@ -34,7 +34,7 @@ import {GroupByTypes} from '../../../../../common/entities/SortingMethods';
styleUrls: ['./grid.gallery.component.css'], styleUrls: ['./grid.gallery.component.css'],
}) })
export class GalleryGridComponent export class GalleryGridComponent
implements OnInit, OnChanges, AfterViewInit, OnDestroy { implements OnInit, OnChanges, AfterViewInit, OnDestroy {
@ViewChild('gridContainer', {static: false}) gridContainer: ElementRef; @ViewChild('gridContainer', {static: false}) gridContainer: ElementRef;
@ViewChildren(GalleryPhotoComponent) @ViewChildren(GalleryPhotoComponent)
gridPhotoQL: QueryList<GalleryPhotoComponent>; gridPhotoQL: QueryList<GalleryPhotoComponent>;
@ -61,13 +61,13 @@ export class GalleryGridComponent
public readonly GroupByTypes = GroupByTypes; public readonly GroupByTypes = GroupByTypes;
constructor( constructor(
private overlayService: OverlayService, private overlayService: OverlayService,
private changeDetector: ChangeDetectorRef, private changeDetector: ChangeDetectorRef,
public queryService: QueryService, public queryService: QueryService,
private router: Router, private router: Router,
public galleryService: ContentService, public galleryService: ContentService,
public sortingService: GallerySortingService, public sortingService: GallerySortingService,
private route: ActivatedRoute private route: ActivatedRoute
) { ) {
} }
@ -87,19 +87,19 @@ export class GalleryGridComponent
ngOnInit(): void { ngOnInit(): void {
this.subscriptions.route = this.route.queryParams.subscribe( this.subscriptions.route = this.route.queryParams.subscribe(
(params: Params): void => { (params: Params): void => {
if ( if (
params[QueryParams.gallery.photo] && params[QueryParams.gallery.photo] &&
params[QueryParams.gallery.photo] !== '' params[QueryParams.gallery.photo] !== ''
) { ) {
this.delayedRenderUpToPhoto = params[QueryParams.gallery.photo]; this.delayedRenderUpToPhoto = params[QueryParams.gallery.photo];
if (!this.mediaGroups?.length) { if (!this.mediaGroups?.length) {
return; return;
}
this.renderUpToMedia(params[QueryParams.gallery.photo]);
} }
this.renderUpToMedia(params[QueryParams.gallery.photo]);
} }
}
); );
} }
@ -150,7 +150,7 @@ export class GalleryGridComponent
if (Config.Gallery.enableOnScrollThumbnailPrioritising === true) { if (Config.Gallery.enableOnScrollThumbnailPrioritising === true) {
this.gridPhotoQL.changes.subscribe((): void => { this.gridPhotoQL.changes.subscribe((): void => {
this.scrollListenerPhotos = this.gridPhotoQL.filter( this.scrollListenerPhotos = this.gridPhotoQL.filter(
(pc): boolean => pc.ScrollListener (pc): boolean => pc.ScrollListener
); );
}); });
} }
@ -176,104 +176,89 @@ export class GalleryGridComponent
this.clearRenderedPhotos(); this.clearRenderedPhotos();
return; return;
} }
// const minGI = Math.min(this.mediaGroups.length, this.mediaToRender.length) - 1;
// const minMI = Math.min(this.mediaGroups[minGI].media.length, this.mediaToRender[minGI].media.length) - 1;
// merge new data with old one // merge new data with old one
const firstDeleteIndex = { const firstDeleteIndex = {
groups: 0, groups: 0,
media: 0 media: 0
}; };
const lastOkIndex = {
groups: 0,
media: 0
};
let diffFound = false; let diffFound = false;
let i = 0;
let j = 0;
for (let i = 0; i < this.mediaGroups.length && i < this.mediaToRender.length; ++i) { for (; i < this.mediaGroups.length && i < this.mediaToRender.length; ++i) {
if (diffFound) {
if (diffFound) {
break; break;
} }
this.mediaToRender[i].name = this.mediaGroups[i].name; // update name if only this changed this.mediaToRender[i].name = this.mediaGroups[i].name; // update name if only this changed
let lastRowId = null; let lastRowId = null;
for (let j = 0; j < this.mediaGroups[i].media.length && j < this.mediaToRender[i].media.length; ++j) { j = 0;
for (; j < this.mediaGroups[i].media.length && j < this.mediaToRender[i].media.length; ++j) {
const media = this.mediaGroups[i].media[j]; const media = this.mediaGroups[i].media[j];
const gridMedia = this.mediaToRender[i].media[j]; const gridMedia = this.mediaToRender[i].media[j];
// If a media changed the whole row has to be removed // If a media changed the whole row has to be removed
if (gridMedia.rowId !== lastRowId) { if (gridMedia.rowId !== lastRowId) {
firstDeleteIndex.groups = i; firstDeleteIndex.groups = i;
firstDeleteIndex.media = j; firstDeleteIndex.media = j;
lastRowId = gridMedia.rowId; lastRowId = gridMedia.rowId;
} }
// we go no further. Found the first bad media
if (gridMedia.equals(media) === false) { if (gridMedia.equals(media) === false) {
diffFound = true; diffFound = true;
break; break;
} }
// save the last media that was checked and was ok
lastOkIndex.groups = i;
lastOkIndex.media = j;
} }
if (this.mediaGroups[i].media.length != this.mediaToRender[i].media.length) {
// delete last row if the length of the two are not equal break;
if (!diffFound && this.mediaGroups[i].media.length > this.mediaToRender[i].media.length) {
firstDeleteIndex.groups = i;
firstDeleteIndex.media = this.mediaToRender[i].media.length;
diffFound = true;
}
if (!diffFound && this.mediaGroups[i].media.length < this.mediaToRender[i].media.length) {
const endIndex = Math.min(this.mediaToRender[i].media.length, this.mediaGroups[i].media.length) - 1;
lastRowId = this.mediaToRender[i].media[endIndex].rowId;
// make sure we delete if there is no 2 rows
diffFound = true;
firstDeleteIndex.groups = i;
firstDeleteIndex.media = endIndex + 1;
// finding the last but one row
for (let j = endIndex; j >= 0; --j) {
const gridMedia = this.mediaToRender[i].media[j];
if (gridMedia.rowId !== lastRowId) {
firstDeleteIndex.groups = i;
firstDeleteIndex.media = j + 1;
break;
}
}
} }
} }
if (!diffFound && this.mediaGroups.length < this.mediaToRender.length) {
diffFound = true; // if all check passed, nothing to delete from the last group
firstDeleteIndex.groups = this.mediaGroups.length - 1; if (!diffFound &&
firstDeleteIndex.media = 0; lastOkIndex.media == this.mediaGroups[lastOkIndex.groups].media.length - 1) {
firstDeleteIndex.groups = lastOkIndex.groups;
firstDeleteIndex.media = lastOkIndex.media + 1;
} }
// if all the same if (firstDeleteIndex.media < 0 && firstDeleteIndex.groups < 0) {
if (diffFound) { this.clearRenderedPhotos();
if (firstDeleteIndex.media < 0 && firstDeleteIndex.groups < 0) { return;
this.clearRenderedPhotos();
return;
}
// only delete the whole group if all media is different
if (firstDeleteIndex.media === 0) {
this.mediaToRender.splice(firstDeleteIndex.groups);
return;
}
this.mediaToRender.splice(firstDeleteIndex.groups + 1);
const media = this.mediaToRender[firstDeleteIndex.groups].media;
media.splice(firstDeleteIndex.media);
} }
// only delete the whole group if all media is different
if (firstDeleteIndex.media === 0) {
this.mediaToRender.splice(firstDeleteIndex.groups);
return;
}
this.mediaToRender.splice(firstDeleteIndex.groups + 1);
const media = this.mediaToRender[firstDeleteIndex.groups].media;
media.splice(firstDeleteIndex.media);
} }
public renderARow(): number { public renderARow(): number {
if ( if (
!this.isMoreToRender() || !this.isMoreToRender() ||
this.containerWidth === 0 this.containerWidth === 0
) { ) {
return null; return null;
} }
// step group // step group
if (this.mediaToRender.length == 0 || if (this.mediaToRender.length == 0 ||
this.mediaToRender[this.mediaToRender.length - 1].media.length >= this.mediaToRender[this.mediaToRender.length - 1].media.length >=
this.mediaGroups[this.mediaToRender.length - 1].media.length) { this.mediaGroups[this.mediaToRender.length - 1].media.length) {
this.mediaToRender.push({name: this.mediaGroups[this.mediaToRender.length].name, media: []}); this.mediaToRender.push({name: this.mediaGroups[this.mediaToRender.length].name, media: []});
} }
@ -281,10 +266,10 @@ export class GalleryGridComponent
const minRowHeight = this.screenHeight / this.MAX_ROW_COUNT; const minRowHeight = this.screenHeight / this.MAX_ROW_COUNT;
const photoRowBuilder = new GridRowBuilder( const photoRowBuilder = new GridRowBuilder(
this.mediaGroups[this.mediaToRender.length - 1].media, this.mediaGroups[this.mediaToRender.length - 1].media,
this.mediaToRender[this.mediaToRender.length - 1].media.length, this.mediaToRender[this.mediaToRender.length - 1].media.length,
this.IMAGE_MARGIN, this.IMAGE_MARGIN,
this.containerWidth - this.overlayService.getPhantomScrollbarWidth() this.containerWidth - this.overlayService.getPhantomScrollbarWidth()
); );
photoRowBuilder.addPhotos(this.TARGET_COL_COUNT); photoRowBuilder.addPhotos(this.TARGET_COL_COUNT);
@ -297,13 +282,13 @@ export class GalleryGridComponent
const noFullRow = photoRowBuilder.calcRowHeight() > maxRowHeight; const noFullRow = photoRowBuilder.calcRowHeight() > maxRowHeight;
// if the row is not full, make it average sized // if the row is not full, make it average sized
const rowHeight = noFullRow ? (minRowHeight + maxRowHeight) / 2 : const rowHeight = noFullRow ? (minRowHeight + maxRowHeight) / 2 :
Math.min(photoRowBuilder.calcRowHeight(), maxRowHeight); Math.min(photoRowBuilder.calcRowHeight(), maxRowHeight);
const imageHeight = rowHeight - this.IMAGE_MARGIN * 2; const imageHeight = rowHeight - this.IMAGE_MARGIN * 2;
photoRowBuilder.getPhotoRow().forEach((media): void => { photoRowBuilder.getPhotoRow().forEach((media): void => {
const imageWidth = imageHeight * MediaDTOUtils.calcAspectRatio(media); const imageWidth = imageHeight * MediaDTOUtils.calcAspectRatio(media);
this.mediaToRender[this.mediaToRender.length - 1].media.push( this.mediaToRender[this.mediaToRender.length - 1].media.push(
new GridMedia(media, imageWidth, imageHeight, this.mediaToRender[this.mediaToRender.length - 1].media.length) new GridMedia(media, imageWidth, imageHeight, this.mediaToRender[this.mediaToRender.length - 1].media.length)
); );
}); });
@ -314,23 +299,23 @@ export class GalleryGridComponent
@HostListener('window:scroll') @HostListener('window:scroll')
onScroll(): void { onScroll(): void {
if ( if (
!this.onScrollFired && !this.onScrollFired &&
this.mediaGroups && this.mediaGroups &&
// should we trigger this at all? // should we trigger this at all?
(this.isMoreToRender() || (this.isMoreToRender() ||
this.scrollListenerPhotos.length > 0) this.scrollListenerPhotos.length > 0)
) { ) {
window.requestAnimationFrame((): void => { window.requestAnimationFrame((): void => {
this.renderPhotos(); this.renderPhotos();
if (Config.Gallery.enableOnScrollThumbnailPrioritising === true) { if (Config.Gallery.enableOnScrollThumbnailPrioritising === true) {
this.scrollListenerPhotos.forEach( this.scrollListenerPhotos.forEach(
(pc: GalleryPhotoComponent): void => { (pc: GalleryPhotoComponent): void => {
pc.onScroll(); pc.onScroll();
} }
); );
this.scrollListenerPhotos = this.scrollListenerPhotos.filter( this.scrollListenerPhotos = this.scrollListenerPhotos.filter(
(pc): boolean => pc.ScrollListener (pc): boolean => pc.ScrollListener
); );
} }
@ -352,7 +337,7 @@ export class GalleryGridComponent
let mediaIndex = -1; let mediaIndex = -1;
for (let i = 0; i < this.mediaGroups.length; ++i) { for (let i = 0; i < this.mediaGroups.length; ++i) {
mediaIndex = this.mediaGroups[i].media.findIndex( mediaIndex = this.mediaGroups[i].media.findIndex(
(p): boolean => this.queryService.getMediaStringId(p) === mediaStringId (p): boolean => this.queryService.getMediaStringId(p) === mediaStringId
); );
if (mediaIndex !== -1) { if (mediaIndex !== -1) {
groupIndex = i; groupIndex = i;
@ -368,11 +353,11 @@ export class GalleryGridComponent
// so not required to render more, but the scrollbar does not trigger more photos to render // so not required to render more, but the scrollbar does not trigger more photos to render
// (on lightbox navigation) // (on lightbox navigation)
while ( while (
(this.mediaToRender.length - 1 < groupIndex && (this.mediaToRender.length - 1 < groupIndex &&
this.mediaToRender[this.mediaToRender.length - 1].media.length < mediaIndex) && this.mediaToRender[this.mediaToRender.length - 1].media.length < mediaIndex) &&
this.renderARow() !== null this.renderARow() !== null
// eslint-disable-next-line no-empty // eslint-disable-next-line no-empty
) { ) {
} }
} }
@ -390,13 +375,13 @@ export class GalleryGridComponent
private shouldRenderMore(offset = 0): boolean { private shouldRenderMore(offset = 0): boolean {
const bottomOffset = this.getMaxRowHeight() * 2; const bottomOffset = this.getMaxRowHeight() * 2;
return ( return (
Config.Gallery.enableOnScrollRendering === false || Config.Gallery.enableOnScrollRendering === false ||
PageHelper.ScrollY >= PageHelper.ScrollY >=
document.body.clientHeight + document.body.clientHeight +
offset - offset -
window.innerHeight - window.innerHeight -
bottomOffset || bottomOffset ||
(document.body.clientHeight + offset) * 0.85 < window.innerHeight (document.body.clientHeight + offset) * 0.85 < window.innerHeight
); );
} }
@ -405,9 +390,9 @@ export class GalleryGridComponent
return; return;
} }
if ( if (
this.containerWidth === 0 || this.containerWidth === 0 ||
!this.isMoreToRender() || !this.isMoreToRender() ||
!this.shouldRenderMore() !this.shouldRenderMore()
) { ) {
return; return;
} }
@ -415,10 +400,10 @@ export class GalleryGridComponent
let renderedContentHeight = 0; let renderedContentHeight = 0;
while ( while (
this.isMoreToRender() && this.isMoreToRender() &&
(this.shouldRenderMore(renderedContentHeight) === true || (this.shouldRenderMore(renderedContentHeight) === true ||
this.getNumberOfRenderedMedia() < numberOfPhotos) this.getNumberOfRenderedMedia() < numberOfPhotos)
) { ) {
const ret = this.renderARow(); const ret = this.renderARow();
if (ret === null) { if (ret === null) {
throw new Error('Grid media rendering failed'); throw new Error('Grid media rendering failed');
@ -429,7 +414,7 @@ export class GalleryGridComponent
private isMoreToRender() { private isMoreToRender() {
return this.mediaToRender.length < this.mediaGroups.length || return this.mediaToRender.length < this.mediaGroups.length ||
(this.mediaToRender[this.mediaToRender.length - 1]?.media.length || 0) < this.mediaGroups[this.mediaToRender.length - 1]?.media.length; (this.mediaToRender[this.mediaToRender.length - 1]?.media.length || 0) < this.mediaGroups[this.mediaToRender.length - 1]?.media.length;
} }
getNumberOfRenderedMedia() { getNumberOfRenderedMedia() {
@ -445,9 +430,9 @@ export class GalleryGridComponent
PageHelper.showScrollY(); PageHelper.showScrollY();
// if the width changed a bit or the height changed a lot // if the width changed a bit or the height changed a lot
if ( if (
this.containerWidth !== this.gridContainer.nativeElement.parentElement.clientWidth || this.containerWidth !== this.gridContainer.nativeElement.parentElement.clientWidth ||
this.screenHeight < window.innerHeight * 0.75 || this.screenHeight < window.innerHeight * 0.75 ||
this.screenHeight > window.innerHeight * 1.25 this.screenHeight > window.innerHeight * 1.25
) { ) {
this.screenHeight = window.innerHeight; this.screenHeight = window.innerHeight;
this.containerWidth = this.gridContainer.nativeElement.parentElement.clientWidth; this.containerWidth = this.gridContainer.nativeElement.parentElement.clientWidth;