2019-01-19 07:18:20 +08:00
|
|
|
import {Component, HostListener, OnDestroy} from '@angular/core';
|
2019-01-18 07:26:20 +08:00
|
|
|
import {DuplicateService} from './duplicates.service';
|
|
|
|
import {Utils} from '../../../common/Utils';
|
|
|
|
import {QueryService} from '../model/query.service';
|
2019-01-19 07:18:20 +08:00
|
|
|
import {DuplicatesDTO} from '../../../common/entities/DuplicatesDTO';
|
|
|
|
import {DirectoryDTO} from '../../../common/entities/DirectoryDTO';
|
|
|
|
import {Subscription} from 'rxjs';
|
|
|
|
import {Config} from '../../../common/config/public/Config';
|
|
|
|
import {PageHelper} from '../model/page.helper';
|
|
|
|
|
|
|
|
interface GroupedDuplicate {
|
|
|
|
name: string;
|
|
|
|
duplicates: DuplicatesDTO[];
|
|
|
|
}
|
2019-01-18 07:26:20 +08:00
|
|
|
|
|
|
|
@Component({
|
|
|
|
selector: 'app-duplicate',
|
|
|
|
templateUrl: './duplicates.component.html',
|
|
|
|
styleUrls: ['./duplicates.component.css']
|
|
|
|
})
|
2019-01-19 07:18:20 +08:00
|
|
|
export class DuplicateComponent implements OnDestroy {
|
|
|
|
|
|
|
|
directoryGroups: GroupedDuplicate[] = null;
|
|
|
|
renderedDirGroups: GroupedDuplicate[] = null;
|
|
|
|
renderedIndex = {
|
|
|
|
group: -1,
|
|
|
|
pairs: 0
|
|
|
|
};
|
|
|
|
subscription: Subscription;
|
|
|
|
renderTimer: number = null;
|
2019-01-20 00:31:36 +08:00
|
|
|
duplicateCount = {
|
|
|
|
pairs: 0,
|
|
|
|
photos: 0
|
|
|
|
};
|
2019-01-19 07:18:20 +08:00
|
|
|
|
2019-01-18 07:26:20 +08:00
|
|
|
constructor(public _duplicateService: DuplicateService,
|
|
|
|
public queryService: QueryService) {
|
|
|
|
this._duplicateService.getDuplicates().catch(console.error);
|
2019-01-19 07:18:20 +08:00
|
|
|
this.subscription = this._duplicateService.duplicates.subscribe((duplicates: DuplicatesDTO[]) => {
|
|
|
|
this.directoryGroups = [];
|
|
|
|
this.renderedIndex = {group: -1, pairs: 0};
|
|
|
|
this.renderedDirGroups = [];
|
2019-01-20 00:31:36 +08:00
|
|
|
this.duplicateCount = {
|
|
|
|
pairs: 0,
|
|
|
|
photos: 0
|
|
|
|
};
|
2019-01-19 07:18:20 +08:00
|
|
|
if (duplicates === null) {
|
|
|
|
return;
|
|
|
|
}
|
2019-01-20 00:31:36 +08:00
|
|
|
this.duplicateCount.photos = duplicates.reduce((prev: number, curr) => prev + curr.media.length, 0);
|
|
|
|
this.duplicateCount.pairs = duplicates.length;
|
|
|
|
|
2019-01-19 07:18:20 +08:00
|
|
|
const getMostFrequentDir = (dupls: DuplicatesDTO[]) => {
|
|
|
|
if (dupls.length === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
const dirFrequency: { [key: number]: { count: number, dir: DirectoryDTO } } = {};
|
|
|
|
dupls.forEach(d => d.media.forEach(m => {
|
|
|
|
dirFrequency[m.directory.id] = dirFrequency[m.directory.id] || {dir: m.directory, count: 0};
|
|
|
|
dirFrequency[m.directory.id].count++;
|
|
|
|
}));
|
|
|
|
let max: { count: number, dir: DirectoryDTO } = {count: -1, dir: null};
|
|
|
|
for (const freq of Object.values(dirFrequency)) {
|
|
|
|
if (max.count <= freq.count) {
|
|
|
|
max = freq;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return max.dir;
|
|
|
|
};
|
|
|
|
|
|
|
|
while (duplicates.length > 0) {
|
|
|
|
const dir = getMostFrequentDir(duplicates);
|
|
|
|
const group = duplicates.filter(d => d.media.find(m => m.directory.id === dir.id));
|
|
|
|
duplicates = duplicates.filter(d => !d.media.find(m => m.directory.id === dir.id));
|
|
|
|
this.directoryGroups.push({name: this.getDirectoryPath(dir) + ' (' + group.length + ')', duplicates: group});
|
|
|
|
}
|
|
|
|
this.renderMore();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
ngOnDestroy(): void {
|
|
|
|
if (this.subscription) {
|
|
|
|
this.subscription.unsubscribe();
|
|
|
|
this.subscription = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
getDirectoryPath(directory: DirectoryDTO) {
|
|
|
|
return Utils.concatUrls(directory.path, directory.name);
|
|
|
|
}
|
|
|
|
|
|
|
|
renderMore = () => {
|
|
|
|
if (this.renderTimer !== null) {
|
|
|
|
clearTimeout(this.renderTimer);
|
|
|
|
this.renderTimer = null;
|
|
|
|
}
|
|
|
|
|
2019-02-27 01:19:34 +08:00
|
|
|
if (this.directoryGroups.length === 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2019-01-19 07:18:20 +08:00
|
|
|
if (this.renderedIndex.group === this.directoryGroups.length - 1 &&
|
|
|
|
this.renderedIndex.pairs >=
|
|
|
|
this.directoryGroups[this.renderedIndex.group].duplicates.length) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (this.shouldRenderMore()) {
|
|
|
|
if (this.renderedDirGroups.length === 0 ||
|
|
|
|
this.renderedIndex.pairs >=
|
|
|
|
this.directoryGroups[this.renderedIndex.group].duplicates.length) {
|
|
|
|
this.renderedDirGroups.push({
|
|
|
|
name: this.directoryGroups[++this.renderedIndex.group].name,
|
|
|
|
duplicates: []
|
|
|
|
});
|
|
|
|
this.renderedIndex.pairs = 0;
|
|
|
|
}
|
|
|
|
this.renderedDirGroups[this.renderedDirGroups.length - 1].duplicates
|
|
|
|
.push(this.directoryGroups[this.renderedIndex.group].duplicates[this.renderedIndex.pairs++]);
|
|
|
|
|
|
|
|
this.renderTimer = window.setTimeout(this.renderMore, 0);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
@HostListener('window:scroll')
|
|
|
|
onScroll() {
|
|
|
|
this.renderMore();
|
2019-01-18 07:26:20 +08:00
|
|
|
}
|
|
|
|
|
2019-01-19 07:18:20 +08:00
|
|
|
private shouldRenderMore(): boolean {
|
|
|
|
return Config.Client.Other.enableOnScrollRendering === false ||
|
|
|
|
PageHelper.ScrollY >= PageHelper.MaxScrollY * 0.7
|
|
|
|
|| (document.body.clientHeight) * 0.85 < window.innerHeight;
|
2019-01-18 07:26:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|