2016-06-17 06:05:31 +08:00
|
|
|
import {Injectable} from "@angular/core";
|
2017-03-21 04:37:23 +08:00
|
|
|
import {GalleryCacheService} from "./cache.gallery.service";
|
|
|
|
import {Photo} from "./Photo";
|
|
|
|
import {IconPhoto} from "./IconPhoto";
|
|
|
|
import {PhotoDTO} from "../../../common/entities/PhotoDTO";
|
2017-06-04 21:25:08 +08:00
|
|
|
import {Config} from "../../../common/config/public/Config";
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2016-06-25 05:44:05 +08:00
|
|
|
export enum ThumbnailLoadingPriority{
|
2017-06-11 04:32:56 +08:00
|
|
|
high, medium, low
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
|
|
|
|
2016-06-17 06:05:31 +08:00
|
|
|
@Injectable()
|
|
|
|
export class ThumbnailLoaderService {
|
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
que: Array<ThumbnailTask> = [];
|
|
|
|
runningRequests: number = 0;
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
constructor(private galleryChacheService: GalleryCacheService) {
|
|
|
|
}
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
removeTasks() {
|
|
|
|
this.que = [];
|
|
|
|
}
|
2016-06-24 04:25:16 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
removeTask(taskEntry: ThumbnailTaskEntity) {
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
for (let i = 0; i < this.que.length; i++) {
|
|
|
|
let index = this.que[i].taskEntities.indexOf(taskEntry);
|
|
|
|
if (index == -1) {
|
|
|
|
this.que[i].taskEntities.splice(index, 1);
|
|
|
|
if (this.que[i].taskEntities.length == 0) {
|
|
|
|
this.que.splice(i, 1);
|
2016-06-25 05:44:05 +08:00
|
|
|
|
|
|
|
}
|
2017-06-11 04:32:56 +08:00
|
|
|
return;
|
|
|
|
}
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
}
|
2017-03-21 04:37:23 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
loadIcon(photo: IconPhoto, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
|
|
|
let tmp: ThumbnailTask = null;
|
|
|
|
//is image already qued?
|
|
|
|
for (let i = 0; i < this.que.length; i++) {
|
|
|
|
if (this.que[i].path == photo.getIconPath()) {
|
|
|
|
tmp = this.que[i];
|
|
|
|
break;
|
|
|
|
}
|
2017-03-21 04:37:23 +08:00
|
|
|
}
|
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
let thumbnailTaskEntity = {priority: priority, listener: listener};
|
|
|
|
//add to previous
|
|
|
|
if (tmp != null) {
|
|
|
|
tmp.taskEntities.push(thumbnailTaskEntity);
|
|
|
|
if (tmp.inProgress == true) {
|
|
|
|
listener.onStartedLoading();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} else {//create new task
|
|
|
|
this.que.push(<ThumbnailTask>{
|
|
|
|
photo: photo.photo,
|
|
|
|
inProgress: false,
|
|
|
|
taskEntities: [thumbnailTaskEntity],
|
|
|
|
onLoaded: () => {
|
|
|
|
photo.iconLoaded();
|
|
|
|
},
|
|
|
|
path: photo.getIconPath()
|
|
|
|
});
|
|
|
|
}
|
|
|
|
setImmediate(this.run);
|
|
|
|
return thumbnailTaskEntity;
|
|
|
|
}
|
|
|
|
|
|
|
|
loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
|
|
|
|
|
|
|
|
let tmp: ThumbnailTask = null;
|
|
|
|
//is image already qued?
|
|
|
|
for (let i = 0; i < this.que.length; i++) {
|
|
|
|
if (this.que[i].path == photo.getThumbnailPath()) {
|
|
|
|
tmp = this.que[i];
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
let thumbnailTaskEntity = {priority: priority, listener: listener};
|
|
|
|
//add to previous
|
|
|
|
if (tmp != null) {
|
|
|
|
tmp.taskEntities.push(thumbnailTaskEntity);
|
|
|
|
if (tmp.inProgress == true) {
|
|
|
|
listener.onStartedLoading();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
} else {//create new task
|
|
|
|
this.que.push({
|
|
|
|
photo: photo.photo,
|
|
|
|
inProgress: false,
|
|
|
|
taskEntities: [thumbnailTaskEntity],
|
|
|
|
onLoaded: () => {
|
|
|
|
photo.thumbnailLoaded();
|
|
|
|
},
|
|
|
|
path: photo.getThumbnailPath()
|
|
|
|
});
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
2017-06-11 04:32:56 +08:00
|
|
|
setImmediate(this.run);
|
|
|
|
return thumbnailTaskEntity;
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
}
|
2016-06-25 05:44:05 +08:00
|
|
|
|
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
private getNextTask(): ThumbnailTask {
|
|
|
|
if (this.que.length === 0) {
|
|
|
|
return null;
|
|
|
|
}
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
for (let i = 0; i < this.que.length; i++) {
|
|
|
|
for (let j = 0; j < this.que[i].taskEntities.length; j++) {
|
|
|
|
if (this.que[i].inProgress == false && this.que[i].taskEntities[j].priority === ThumbnailLoadingPriority.high) {
|
|
|
|
return this.que[i];
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
2017-06-11 04:32:56 +08:00
|
|
|
}
|
|
|
|
}
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
for (let i = 0; i < this.que.length; i++) {
|
|
|
|
for (let j = 0; j < this.que[i].taskEntities.length; j++) {
|
|
|
|
if (this.que[i].inProgress == false && this.que[i].taskEntities[j].priority === ThumbnailLoadingPriority.medium) {
|
|
|
|
return this.que[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-01-23 03:30:23 +08:00
|
|
|
|
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
for (let i = 0; i < this.que.length; i++) {
|
|
|
|
if (this.que[i].inProgress == false) {
|
|
|
|
return this.que[i];
|
|
|
|
}
|
2017-01-23 03:30:23 +08:00
|
|
|
|
2016-06-17 06:05:31 +08:00
|
|
|
}
|
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
private taskReady(task: ThumbnailTask) {
|
|
|
|
let i = this.que.indexOf(task);
|
|
|
|
if (i == -1) {
|
|
|
|
if (task.taskEntities.length !== 0) {
|
|
|
|
console.error("ThumbnailLoader: can't find task to remove");
|
|
|
|
}
|
|
|
|
return;
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
2017-06-11 04:32:56 +08:00
|
|
|
this.que.splice(i, 1);
|
|
|
|
}
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
run = () => {
|
|
|
|
if (this.que.length === 0 || this.runningRequests >= Config.Client.concurrentThumbnailGenerations) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let task = this.getNextTask();
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
if (task === null) {
|
|
|
|
return;
|
|
|
|
}
|
2016-06-25 05:44:05 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
this.runningRequests++;
|
|
|
|
task.taskEntities.forEach(te => te.listener.onStartedLoading());
|
|
|
|
task.inProgress = true;
|
2016-06-24 04:25:16 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
let curImg = new Image();
|
|
|
|
curImg.onload = () => {
|
|
|
|
task.onLoaded();
|
|
|
|
this.galleryChacheService.photoUpdated(task.photo);
|
|
|
|
task.taskEntities.forEach((te: ThumbnailTaskEntity) => te.listener.onLoad());
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
this.taskReady(task);
|
|
|
|
this.runningRequests--;
|
|
|
|
this.run();
|
|
|
|
};
|
2016-06-24 04:25:16 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
curImg.onerror = (error) => {
|
|
|
|
task.taskEntities.forEach((te: ThumbnailTaskEntity) => te.listener.onError(error));
|
2017-01-23 03:30:23 +08:00
|
|
|
|
2017-06-11 04:32:56 +08:00
|
|
|
this.taskReady(task);
|
|
|
|
this.runningRequests--;
|
|
|
|
this.run();
|
2016-06-25 05:44:05 +08:00
|
|
|
};
|
2017-06-11 04:32:56 +08:00
|
|
|
|
|
|
|
curImg.src = task.path;
|
|
|
|
};
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
|
|
|
|
2016-06-17 06:05:31 +08:00
|
|
|
|
2016-06-25 05:44:05 +08:00
|
|
|
export interface ThumbnailLoadingListener {
|
2017-06-11 04:32:56 +08:00
|
|
|
onStartedLoading: () => void;
|
|
|
|
onLoad: () => void;
|
|
|
|
onError: (error: any) => void;
|
2016-06-25 05:44:05 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export interface ThumbnailTaskEntity {
|
2017-06-11 04:32:56 +08:00
|
|
|
priority: ThumbnailLoadingPriority;
|
|
|
|
listener: ThumbnailLoadingListener;
|
2016-06-17 06:05:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
interface ThumbnailTask {
|
2017-06-11 04:32:56 +08:00
|
|
|
photo: PhotoDTO;
|
|
|
|
inProgress: boolean;
|
|
|
|
taskEntities: Array<ThumbnailTaskEntity>;
|
|
|
|
path: string;
|
|
|
|
onLoaded: Function;
|
2016-06-17 06:05:31 +08:00
|
|
|
}
|
2017-03-21 04:37:23 +08:00
|
|
|
|