improving thumbnail generation. adding thumbnails to map

This commit is contained in:
Braun Patrik 2017-03-20 21:37:23 +01:00
parent 483af01c99
commit 385dcd7c4d
14 changed files with 270 additions and 96 deletions

View File

@ -73,10 +73,10 @@ export class ThumbnailGeneratorMWs {
private static addThInfoToPhotos(photos: Array<PhotoDTO>) { private static addThInfoToPhotos(photos: Array<PhotoDTO>) {
let thumbnailFolder = ProjectPath.ThumbnailFolder; let thumbnailFolder = ProjectPath.ThumbnailFolder;
for (let j = 0; j < Config.Client.thumbnailSizes.length; j++) { for (let i = 0; i < photos.length; i++) {
let size = Config.Client.thumbnailSizes[j]; let fullImagePath = path.join(ProjectPath.ImageFolder, photos[i].directory.path, photos[i].directory.name, photos[i].name);
for (let i = 0; i < photos.length; i++) { for (let j = 0; j < Config.Client.thumbnailSizes.length; j++) {
let fullImagePath = path.join(ProjectPath.ImageFolder, photos[i].directory.path, photos[i].directory.name, photos[i].name); let size = Config.Client.thumbnailSizes[j];
let thPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, size)); let thPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, size));
if (fs.existsSync(thPath) === true) { if (fs.existsSync(thPath) === true) {
if (typeof photos[i].readyThumbnails == "undefined") { if (typeof photos[i].readyThumbnails == "undefined") {
@ -85,6 +85,11 @@ export class ThumbnailGeneratorMWs {
photos[i].readyThumbnails.push(size); photos[i].readyThumbnails.push(size);
} }
} }
let iconPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, Config.Client.iconSize));
if (fs.existsSync(iconPath) === true) {
photos[i].readyIcon = true;
}
} }
} }
@ -129,13 +134,13 @@ export class ThumbnailGeneratorMWs {
//load parameters //load parameters
let imagePath = req.resultPipe; let imagePath = req.resultPipe;
let size: number = 30; let size: number = Config.Client.iconSize;
ThumbnailGeneratorMWs.generateImage(imagePath, size, true, req, res, next); ThumbnailGeneratorMWs.generateImage(imagePath, size, true, req, res, next);
} }
private static generateImage(imagePath, size, makeSquare, req: Request, res: Response, next: NextFunction) { private static generateImage(imagePath: string, size: number, makeSquare: boolean, req: Request, res: Response, next: NextFunction) {
//generate thumbnail path //generate thumbnail path
let thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size)); let thPath = path.join(ProjectPath.ThumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(imagePath, size));

View File

@ -39,6 +39,7 @@ export class GalleryManager implements IGalleryManager {
dir.photos[i].metadata.positionData = <any>JSON.parse(<any>dir.photos[i].metadata.positionData); dir.photos[i].metadata.positionData = <any>JSON.parse(<any>dir.photos[i].metadata.positionData);
dir.photos[i].metadata.size = <any>JSON.parse(<any>dir.photos[i].metadata.size); dir.photos[i].metadata.size = <any>JSON.parse(<any>dir.photos[i].metadata.size);
dir.photos[i].readyThumbnails = []; dir.photos[i].readyThumbnails = [];
dir.photos[i].readyIcon = false;
} }
} }

View File

@ -26,6 +26,8 @@ export class PhotoEntity implements PhotoDTO {
readyThumbnails: Array<number> = []; readyThumbnails: Array<number> = [];
readyIcon: boolean = false;
} }

View File

@ -14,34 +14,36 @@ interface DataBaseConfig {
} }
interface ServerConfig { interface ServerConfig {
port:number; port: number;
imagesFolder:string; imagesFolder: string;
thumbnailFolder:string; thumbnailFolder: string;
database: DataBaseConfig; database: DataBaseConfig;
} }
interface SearchConfig { interface SearchConfig {
searchEnabled:boolean searchEnabled: boolean
instantSearchEnabled:boolean instantSearchEnabled: boolean
autocompleteEnabled:boolean autocompleteEnabled: boolean
} }
interface ClientConfig { interface ClientConfig {
thumbnailSizes:Array<number>; iconSize: number;
Search:SearchConfig; thumbnailSizes: Array<number>;
concurrentThumbnailGenerations:number; Search: SearchConfig;
enableCache:boolean; concurrentThumbnailGenerations: number;
enableOnScrollRendering:boolean; enableCache: boolean;
enableOnScrollThumbnailPrioritising:boolean; enableOnScrollRendering: boolean;
authenticationRequired:boolean; enableOnScrollThumbnailPrioritising: boolean;
authenticationRequired: boolean;
googleApiKey: string; googleApiKey: string;
} }
export class ConfigClass { export class ConfigClass {
public Server:ServerConfig = null; public Server: ServerConfig = null;
public Client:ClientConfig = { public Client: ClientConfig = {
thumbnailSizes: [200, 400, 600], thumbnailSizes: [200, 400, 600],
iconSize: 30,
Search: { Search: {
searchEnabled: true, searchEnabled: true,
instantSearchEnabled: true, instantSearchEnabled: true,
@ -55,7 +57,7 @@ export class ConfigClass {
googleApiKey: "" googleApiKey: ""
}; };
public setDatabaseType(type:DatabaseType) { public setDatabaseType(type: DatabaseType) {
this.Server.database.type = type; this.Server.database.type = type;
if (type === DatabaseType.memory) { if (type === DatabaseType.memory) {
this.Client.Search.searchEnabled = false; this.Client.Search.searchEnabled = false;

View File

@ -6,6 +6,7 @@ export interface PhotoDTO {
directory: DirectoryDTO; directory: DirectoryDTO;
metadata: PhotoMetadata; metadata: PhotoMetadata;
readyThumbnails: Array<number>; readyThumbnails: Array<number>;
readyIcon: boolean;
} }
export interface PhotoMetadata { export interface PhotoMetadata {

View File

@ -8,7 +8,7 @@ import {appRoutes} from "./app.routing";
import {UserService} from "./model/network/user.service"; import {UserService} from "./model/network/user.service";
import {GalleryService} from "./gallery/gallery.service"; import {GalleryService} from "./gallery/gallery.service";
import {NetworkService} from "./model/network/network.service"; import {NetworkService} from "./model/network/network.service";
import {ThumbnailLoaderService} from "./gallery/grid/thumnailLoader.service"; import {ThumbnailLoaderService} from "./gallery/thumnailLoader.service";
import {GalleryCacheService} from "./gallery/cache.gallery.service"; import {GalleryCacheService} from "./gallery/cache.gallery.service";
import {FullScreenService} from "./gallery/fullscreen.service"; import {FullScreenService} from "./gallery/fullscreen.service";
import {AuthenticationService} from "./model/network/authentication.service"; import {AuthenticationService} from "./model/network/authentication.service";
@ -29,7 +29,7 @@ import {StringifyRole} from "./pipes/StringifyRolePipe";
import {Config} from "./config/Config"; import {Config} from "./config/Config";
import {GalleryMapComponent} from "./gallery/map/map.gallery.component"; import {GalleryMapComponent} from "./gallery/map/map.gallery.component";
import {GalleryMapLightboxComponent} from "./gallery/map/lightbox/lightbox.map.gallery.component"; import {GalleryMapLightboxComponent} from "./gallery/map/lightbox/lightbox.map.gallery.component";
import {ThumbnailManagerService} from "./gallery/grid/thumnailManager.service"; import {ThumbnailManagerService} from "./gallery/thumnailManager.service";
@NgModule({ @NgModule({
imports: [ imports: [

View File

@ -0,0 +1,42 @@
import {PhotoDTO} from "../../../common/entities/PhotoDTO";
import {Utils} from "../../../common/Utils";
export class IconPhoto {
protected replacementSizeCache: number|boolean = false;
constructor(public photo: PhotoDTO) {
}
iconLoaded() {
this.photo.readyIcon = true;
}
isIconAvailable() {
return this.photo.readyIcon;
}
getIconPath() {
return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "icon");
}
getPhotoPath() {
return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name);
}
equals(other: PhotoDTO | IconPhoto): boolean {
//is gridphoto
if (other instanceof IconPhoto) {
return this.photo.directory.path === other.photo.directory.path && this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name
}
//is photo
if (other.directory) {
return this.photo.directory.path === other.directory.path && this.photo.directory.name === other.directory.name && this.photo.name === other.name
}
return false;
}
}

View File

@ -1,12 +1,12 @@
import {PhotoDTO} from "../../../common/entities/PhotoDTO"; import {PhotoDTO} from "../../../common/entities/PhotoDTO";
import {Utils} from "../../../common/Utils"; import {Utils} from "../../../common/Utils";
import {Config} from "../config/Config"; import {Config} from "../config/Config";
export class Photo { import {IconPhoto} from "./IconPhoto";
export class Photo extends IconPhoto {
protected replacementSizeCache: boolean|number = false;
constructor(public photo: PhotoDTO, public renderWidth: number, public renderHeight: number) {
constructor(photo: PhotoDTO, public renderWidth: number, public renderHeight: number) {
super(photo);
} }
@ -22,7 +22,7 @@ export class Photo {
return Utils.findClosest(renderSize, Config.Client.thumbnailSizes); return Utils.findClosest(renderSize, Config.Client.thumbnailSizes);
} }
getReplacementThumbnailSize() { getReplacementThumbnailSize(): number {
if (this.replacementSizeCache === false) { if (this.replacementSizeCache === false) {
this.replacementSizeCache = null; this.replacementSizeCache = null;
@ -37,7 +37,7 @@ export class Photo {
} }
} }
} }
return this.replacementSizeCache; return <number>this.replacementSizeCache;
} }
isReplacementThumbnailAvailable() { isReplacementThumbnailAvailable() {
@ -59,22 +59,5 @@ export class Photo {
return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString()); return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name, "thumbnail", size.toString());
} }
getPhotoPath() {
return Utils.concatUrls("/api/gallery/content/", this.photo.directory.path, this.photo.directory.name, this.photo.name);
}
equals(other: any) {
//is gridphoto
if (other.photo) {
return this.photo.directory.path === other.photo.directory.path && this.photo.directory.name === other.photo.directory.name && this.photo.name === other.photo.name
}
//is photo
if (other.directory) {
return this.photo.directory.path === other.directory.path && this.photo.directory.name === other.directory.name && this.photo.name === other.name
}
return false;
}
} }

View File

@ -3,7 +3,7 @@ import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
import {RouterLink} from "@angular/router"; import {RouterLink} from "@angular/router";
import {Utils} from "../../../../common/Utils"; import {Utils} from "../../../../common/Utils";
import {Photo} from "../Photo"; import {Photo} from "../Photo";
import {Thumbnail, ThumbnailManagerService} from "../grid/thumnailManager.service"; import {Thumbnail, ThumbnailManagerService} from "../thumnailManager.service";
@Component({ @Component({
selector: 'gallery-directory', selector: 'gallery-directory',

View File

@ -4,7 +4,7 @@ import {GridPhoto} from "../GridPhoto";
import {SearchTypes} from "../../../../../common/entities/AutoCompleteItem"; import {SearchTypes} from "../../../../../common/entities/AutoCompleteItem";
import {RouterLink} from "@angular/router"; import {RouterLink} from "@angular/router";
import {Config} from "../../../config/Config"; import {Config} from "../../../config/Config";
import {Thumbnail, ThumbnailManagerService} from "../thumnailManager.service"; import {Thumbnail, ThumbnailManagerService} from "../../thumnailManager.service";
@Component({ @Component({
selector: 'gallery-grid-photo', selector: 'gallery-grid-photo',

View File

@ -2,8 +2,9 @@ import {Component, Input, OnChanges, ElementRef, ViewChild} from "@angular/core"
import {PhotoDTO} from "../../../../../common/entities/PhotoDTO"; import {PhotoDTO} from "../../../../../common/entities/PhotoDTO";
import {Dimension} from "../../../model/IRenderable"; import {Dimension} from "../../../model/IRenderable";
import {FullScreenService} from "../../fullscreen.service"; import {FullScreenService} from "../../fullscreen.service";
import {Utils} from "../../../../../common/Utils";
import {SebmGoogleMap} from "angular2-google-maps/core"; import {SebmGoogleMap} from "angular2-google-maps/core";
import {ThumbnailManagerService, IconThumbnail} from "../../thumnailManager.service";
import {IconPhoto} from "../../IconPhoto";
@Component({ @Component({
selector: 'gallery-map-lightbox', selector: 'gallery-map-lightbox',
@ -18,7 +19,7 @@ export class GalleryMapLightboxComponent implements OnChanges {
public mapDimension: Dimension = <Dimension>{top: 0, left: 0, width: 0, height: 0}; public mapDimension: Dimension = <Dimension>{top: 0, left: 0, width: 0, height: 0};
private visible = false; private visible = false;
private opacity = 1.0; private opacity = 1.0;
mapPhotos: Array<{latitude: number, longitude: number, iconUrl}> = []; mapPhotos: Array<{latitude: number, longitude: number, iconUrl?: string, thumbnail: IconThumbnail}> = [];
mapCenter = {latitude: 0, longitude: 0}; mapCenter = {latitude: 0, longitude: 0};
@ViewChild("root") elementRef: ElementRef; @ViewChild("root") elementRef: ElementRef;
@ -26,7 +27,7 @@ export class GalleryMapLightboxComponent implements OnChanges {
@ViewChild(SebmGoogleMap) map: SebmGoogleMap; @ViewChild(SebmGoogleMap) map: SebmGoogleMap;
constructor(private fullScreenService: FullScreenService) { constructor(private fullScreenService: FullScreenService, private thumbnailService: ThumbnailManagerService) {
} }
@ -81,21 +82,33 @@ export class GalleryMapLightboxComponent implements OnChanges {
this.opacity = 0.0; this.opacity = 0.0;
setTimeout(() => { setTimeout(() => {
this.visible = false; this.visible = false;
this.mapPhotos = []; this.hideImages();
}, 500); }, 500);
} }
showImages() { showImages() {
this.hideImages();
this.mapPhotos = this.photos.filter(p => { this.mapPhotos = this.photos.filter(p => {
return p.metadata && p.metadata.positionData && p.metadata.positionData.GPSData; return p.metadata && p.metadata.positionData && p.metadata.positionData.GPSData;
}).map(p => { }).map(p => {
return { let th = this.thumbnailService.getIcon(new IconPhoto(p));
let obj: {latitude: number, longitude: number, iconUrl?: string, thumbnail: IconThumbnail} = {
latitude: p.metadata.positionData.GPSData.latitude, latitude: p.metadata.positionData.GPSData.latitude,
longitude: p.metadata.positionData.GPSData.longitude, longitude: p.metadata.positionData.GPSData.longitude,
iconUrl: Utils.concatUrls("/api/gallery/content/", p.directory.path, p.directory.name, p.name, "icon") thumbnail: th
}; };
if (th.Available == true) {
obj.iconUrl = th.Src;
} else {
th.OnLoad = () => {
obj.iconUrl = th.Src;
};
}
return obj;
}); });
if (this.mapPhotos.length > 0) { if (this.mapPhotos.length > 0) {
@ -103,6 +116,11 @@ export class GalleryMapLightboxComponent implements OnChanges {
} }
} }
hideImages() {
this.mapPhotos.forEach(mp => mp.thumbnail.destroy());
this.mapPhotos = [];
}
private getBodyScrollTop(): number { private getBodyScrollTop(): number {
return window.scrollY; return window.scrollY;

View File

@ -1,6 +1,5 @@
import {Component, OnChanges, Input, ViewChild, ElementRef} from "@angular/core"; import {Component, OnChanges, Input, ViewChild, ElementRef} from "@angular/core";
import {PhotoDTO} from "../../../../common/entities/PhotoDTO"; import {PhotoDTO} from "../../../../common/entities/PhotoDTO";
import {Utils} from "../../../../common/Utils";
import {IRenderable, Dimension} from "../../model/IRenderable"; import {IRenderable, Dimension} from "../../model/IRenderable";
import {GalleryMapLightboxComponent} from "./lightbox/lightbox.map.gallery.component"; import {GalleryMapLightboxComponent} from "./lightbox/lightbox.map.gallery.component";
@Component({ @Component({
@ -13,7 +12,7 @@ export class GalleryMapComponent implements OnChanges, IRenderable {
@Input() photos: Array<PhotoDTO>; @Input() photos: Array<PhotoDTO>;
@ViewChild(GalleryMapLightboxComponent) mapLightbox: GalleryMapLightboxComponent; @ViewChild(GalleryMapLightboxComponent) mapLightbox: GalleryMapLightboxComponent;
mapPhotos: Array<{latitude: number, longitude: number, iconUrl}> = []; mapPhotos: Array<{latitude: number, longitude: number}> = [];
mapCenter = {latitude: 0, longitude: 0}; mapCenter = {latitude: 0, longitude: 0};
@ViewChild("map") map: ElementRef; @ViewChild("map") map: ElementRef;
@ -24,8 +23,7 @@ export class GalleryMapComponent implements OnChanges, IRenderable {
}).map(p => { }).map(p => {
return { return {
latitude: p.metadata.positionData.GPSData.latitude, latitude: p.metadata.positionData.GPSData.latitude,
longitude: p.metadata.positionData.GPSData.longitude, longitude: p.metadata.positionData.GPSData.longitude
iconUrl: Utils.concatUrls("/api/gallery/content/", p.directory.path, p.directory.name, p.name, "icon")
}; };
}); });

View File

@ -1,7 +1,9 @@
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {Config} from "../../config/Config"; import {Config} from "../config/Config";
import {GalleryCacheService} from "../cache.gallery.service"; import {GalleryCacheService} from "./cache.gallery.service";
import {Photo} from "../Photo"; import {Photo} from "./Photo";
import {IconPhoto} from "./IconPhoto";
import {PhotoDTO} from "../../../common/entities/PhotoDTO";
export enum ThumbnailLoadingPriority{ export enum ThumbnailLoadingPriority{
high, medium, low high, medium, low
@ -36,12 +38,46 @@ export class ThumbnailLoaderService {
} }
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;
}
}
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 { loadImage(photo: Photo, priority: ThumbnailLoadingPriority, listener: ThumbnailLoadingListener): ThumbnailTaskEntity {
let tmp: ThumbnailTask = null; let tmp: ThumbnailTask = null;
//is image already qued? //is image already qued?
for (let i = 0; i < this.que.length; i++) { for (let i = 0; i < this.que.length; i++) {
if (this.que[i].photo.getThumbnailPath() == photo.getThumbnailPath()) { if (this.que[i].path == photo.getThumbnailPath()) {
tmp = this.que[i]; tmp = this.que[i];
break; break;
} }
@ -58,9 +94,13 @@ export class ThumbnailLoaderService {
} else {//create new task } else {//create new task
this.que.push({ this.que.push({
photo: photo, photo: photo.photo,
inProgress: false, inProgress: false,
taskEntities: [thumbnailTaskEntity] taskEntities: [thumbnailTaskEntity],
onLoaded: () => {
photo.thumbnailLoaded();
},
path: photo.getThumbnailPath()
}); });
} }
setImmediate(this.run); setImmediate(this.run);
@ -129,8 +169,8 @@ export class ThumbnailLoaderService {
let curImg = new Image(); let curImg = new Image();
curImg.onload = () => { curImg.onload = () => {
task.photo.thumbnailLoaded(); task.onLoaded();
this.galleryChacheService.photoUpdated(task.photo.photo); this.galleryChacheService.photoUpdated(task.photo);
task.taskEntities.forEach((te: ThumbnailTaskEntity) => te.listener.onLoad()); task.taskEntities.forEach((te: ThumbnailTaskEntity) => te.listener.onLoad());
this.taskReady(task); this.taskReady(task);
@ -146,7 +186,7 @@ export class ThumbnailLoaderService {
this.run(); this.run();
}; };
curImg.src = task.photo.getThumbnailPath(); curImg.src = task.path;
}; };
} }
@ -164,8 +204,10 @@ export interface ThumbnailTaskEntity {
} }
interface ThumbnailTask { interface ThumbnailTask {
photo: Photo; photo: PhotoDTO;
inProgress: boolean; inProgress: boolean;
taskEntities: Array<ThumbnailTaskEntity>; taskEntities: Array<ThumbnailTaskEntity>;
path: string;
onLoaded: Function;
} }

View File

@ -1,6 +1,7 @@
import {Injectable} from "@angular/core"; import {Injectable} from "@angular/core";
import {Photo} from "../Photo";
import {ThumbnailLoaderService, ThumbnailLoadingListener, ThumbnailTaskEntity} from "./thumnailLoader.service"; import {ThumbnailLoaderService, ThumbnailLoadingListener, ThumbnailTaskEntity} from "./thumnailLoader.service";
import {Photo} from "./Photo";
import {IconPhoto} from "./IconPhoto";
export enum ThumbnailLoadingPriority{ export enum ThumbnailLoadingPriority{
high, medium, low high, medium, low
@ -16,21 +17,117 @@ export class ThumbnailManagerService {
public getThumbnail(photo: Photo) { public getThumbnail(photo: Photo) {
return new Thumbnail(photo, this.thumbnailLoader); return new Thumbnail(photo, this.thumbnailLoader);
} }
public getIcon(photo: IconPhoto) {
return new IconThumbnail(photo, this.thumbnailLoader);
}
} }
export class Thumbnail { export abstract class ThumbnailBase {
private available: boolean = false; protected available: boolean = false;
private src: string = null; protected src: string = null;
private loading: boolean = false; protected loading: boolean = false;
private thumbnailTask: ThumbnailTaskEntity; protected onLoad: Function = null;
protected thumbnailTask: ThumbnailTaskEntity;
constructor(private photo: Photo, private thumbnailService: ThumbnailLoaderService) { constructor(protected thumbnailService: ThumbnailLoaderService) {
}
abstract set Visible(visible: boolean);
set OnLoad(onLoad: Function) {
this.onLoad = onLoad;
}
get Available() {
return this.available;
}
get Src() {
return this.src;
}
get Loading() {
return this.loading;
}
destroy() {
if (this.thumbnailTask != null) {
this.thumbnailService.removeTask(this.thumbnailTask);
this.thumbnailTask = null;
}
}
}
export class IconThumbnail extends ThumbnailBase {
constructor(private photo: IconPhoto, thumbnailService: ThumbnailLoaderService) {
super(thumbnailService);
this.src = "";
if (this.photo.isIconAvailable()) {
this.src = this.photo.getIconPath();
this.available = true;
if (this.onLoad) this.onLoad();
}
if (!this.photo.isIconAvailable()) {
setImmediate(() => {
let listener: ThumbnailLoadingListener = {
onStartedLoading: () => { //onLoadStarted
this.loading = true;
},
onLoad: () => {//onLoaded
this.src = this.photo.getIconPath();
if (this.onLoad) this.onLoad();
this.available = true;
this.loading = false;
this.thumbnailTask = null;
},
onError: (error) => {//onError
this.thumbnailTask = null;
//TODO: handle error
//TODO: not an error if its from cache
console.error("something bad happened");
console.error(error);
}
};
this.thumbnailTask = this.thumbnailService.loadIcon(this.photo, ThumbnailLoadingPriority.high, listener);
});
}
}
set Visible(visible: boolean) {
if (!this.thumbnailTask) return;
if (visible === true) {
this.thumbnailTask.priority = ThumbnailLoadingPriority.high;
} else {
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
}
}
}
export class Thumbnail extends ThumbnailBase {
constructor(private photo: Photo, thumbnailService: ThumbnailLoaderService) {
super(thumbnailService);
if (this.photo.isThumbnailAvailable()) { if (this.photo.isThumbnailAvailable()) {
this.src = this.photo.getThumbnailPath(); this.src = this.photo.getThumbnailPath();
this.available = true; this.available = true;
if (this.onLoad) this.onLoad();
} else if (this.photo.isReplacementThumbnailAvailable()) { } else if (this.photo.isReplacementThumbnailAvailable()) {
this.src = this.photo.getReplacementThumbnailPath(); this.src = this.photo.getReplacementThumbnailPath();
this.available = true; this.available = true;
@ -45,6 +142,7 @@ export class Thumbnail {
}, },
onLoad: () => {//onLoaded onLoad: () => {//onLoaded
this.src = this.photo.getThumbnailPath(); this.src = this.photo.getThumbnailPath();
if (this.onLoad) this.onLoad();
this.available = true; this.available = true;
this.loading = false; this.loading = false;
this.thumbnailTask = null; this.thumbnailTask = null;
@ -70,6 +168,7 @@ export class Thumbnail {
} }
set Visible(visible: boolean) { set Visible(visible: boolean) {
if (!this.thumbnailTask) return;
if (visible === true) { if (visible === true) {
if (this.photo.isReplacementThumbnailAvailable()) { if (this.photo.isReplacementThumbnailAvailable()) {
this.thumbnailTask.priority = ThumbnailLoadingPriority.medium; this.thumbnailTask.priority = ThumbnailLoadingPriority.medium;
@ -86,24 +185,5 @@ export class Thumbnail {
} }
get Available() {
return this.available;
}
get Src() {
return this.src;
}
get Loading() {
return this.loading;
}
destroy() {
if (this.thumbnailTask != null) {
this.thumbnailService.removeTask(this.thumbnailTask);
this.thumbnailTask = null;
}
}
} }