import {Injectable} from '@angular/core'; import {NetworkService} from '../model/network/network.service'; import {ContentWrapper} from '../../../common/entities/ConentWrapper'; import {DirectoryDTO} from '../../../common/entities/DirectoryDTO'; import {SearchTypes} from '../../../common/entities/AutoCompleteItem'; import {GalleryCacheService} from './cache.gallery.service'; import {BehaviorSubject} from 'rxjs'; import {SharingDTO} from '../../../common/entities/SharingDTO'; import {Config} from '../../../common/config/public/Config'; import {ShareService} from './share.service'; import {NavigationService} from '../model/navigation.service'; import {SortingMethods} from '../../../common/entities/SortingMethods'; import {QueryParams} from '../../../common/QueryParams'; @Injectable() export class GalleryService { public content: BehaviorSubject; public sorting: BehaviorSubject; private lastDirectory: DirectoryDTO; private searchId: any; private ongoingSearch: { text: string, type: SearchTypes } = null; private ongoingInstantSearch: { text: string, type: SearchTypes } = null; private runInstantSearchFor: string; constructor(private networkService: NetworkService, private galleryCacheService: GalleryCacheService, private _shareService: ShareService, private navigationService: NavigationService) { this.content = new BehaviorSubject(new ContentWrapper()); this.sorting = new BehaviorSubject(Config.Client.Other.defaultPhotoSortingMethod); } lastRequest: { directory: string } = { directory: null }; setSorting(sorting: SortingMethods): void { this.sorting.next(sorting); if (this.content.value.directory) { if (sorting !== Config.Client.Other.defaultPhotoSortingMethod) { this.galleryCacheService.setSorting(this.content.value.directory, sorting); } else { this.galleryCacheService.removeSorting(this.content.value.directory); } } } setContent(content: ContentWrapper): void { this.content.next(content); if (content.directory) { const sort = this.galleryCacheService.getSorting(content.directory); if (sort !== null) { this.sorting.next(sort); } else { this.sorting.next(Config.Client.Other.defaultPhotoSortingMethod); } } } public async loadDirectory(directoryName: string): Promise { const content = new ContentWrapper(); content.directory = this.galleryCacheService.getDirectory(directoryName); content.searchResult = null; this.setContent(content); this.lastRequest.directory = directoryName; const params: { [key: string]: any } = {}; if (Config.Client.Sharing.enabled === true) { if (this._shareService.isSharing()) { params[QueryParams.gallery.sharingKey_short] = this._shareService.getSharingKey(); } } if (content.directory && content.directory.lastModified && content.directory.lastScanned && !content.directory.isPartial) { params[QueryParams.gallery.knownLastModified] = content.directory.lastModified; params[QueryParams.gallery.knownLastScanned] = content.directory.lastScanned; } try { const cw = await this.networkService.getJson('/gallery/content/' + directoryName, params); if (!cw || cw.notModified === true) { return; } this.galleryCacheService.setDirectory(cw.directory); // save it before adding references if (this.lastRequest.directory !== directoryName) { return; } DirectoryDTO.addReferences(cw.directory); this.lastDirectory = cw.directory; this.setContent(cw); } catch (e) { console.error(e); this.navigationService.toGallery().catch(console.error); } } public async search(text: string, type?: SearchTypes): Promise { if (this.searchId != null) { clearTimeout(this.searchId); } if (text === null || text === '' || text.trim() === '.') { return null; } this.ongoingSearch = {text: text, type: type}; this.setContent(new ContentWrapper()); const cw = new ContentWrapper(); cw.searchResult = this.galleryCacheService.getSearch(text, type); if (cw.searchResult == null) { if (this.runInstantSearchFor === text && !type) { await this.instantSearch(text, type); return; } const params: { type?: SearchTypes } = {}; if (typeof type !== 'undefined' && type !== null) { params['type'] = type; } cw.searchResult = (await this.networkService.getJson('/search/' + text, params)).searchResult; if (this.ongoingSearch && (this.ongoingSearch.text !== text || this.ongoingSearch.type !== type)) { return; } this.galleryCacheService.setSearch(text, type, cw.searchResult); } this.setContent(cw); } public async instantSearch(text: string, type?: SearchTypes): Promise { if (text === null || text === '' || text.trim() === '.') { const content = new ContentWrapper(this.lastDirectory); this.setContent(content); if (this.searchId != null) { clearTimeout(this.searchId); } if (!this.lastDirectory) { this.loadDirectory('/').catch(console.error); } return null; } if (this.searchId != null) { clearTimeout(this.searchId); } this.runInstantSearchFor = null; this.ongoingInstantSearch = {text: text, type: type}; const cw = new ContentWrapper(); cw.directory = null; cw.searchResult = this.galleryCacheService.getSearch(text); if (cw.searchResult == null) { // If result is not search cache, try to load more this.searchId = setTimeout(() => { this.search(text, type).catch(console.error); this.searchId = null; }, Config.Client.Search.InstantSearchTimeout); cw.searchResult = this.galleryCacheService.getInstantSearch(text); if (cw.searchResult == null) { cw.searchResult = (await this.networkService.getJson('/instant-search/' + text)).searchResult; if (this.ongoingInstantSearch && (this.ongoingInstantSearch.text !== text || this.ongoingInstantSearch.type !== type)) { return; } this.galleryCacheService.setInstantSearch(text, cw.searchResult); } } this.setContent(cw); // if instant search do not have a result, do not do a search if (cw.searchResult.media.length === 0 && cw.searchResult.directories.length === 0) { if (this.searchId != null) { clearTimeout(this.searchId); } } return cw; } public async getSharing(sharingKey: string): Promise { return this.networkService.getJson('/share/' + sharingKey); } isSearchResult(): boolean { return !!this.content.value.searchResult; } runInstantSearch(searchText: string) { this.runInstantSearchFor = searchText; } }