mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-01-24 05:17:16 +02:00
Merge remote-tracking branch 'origin/master'
# Conflicts: # demo/images/index.md
This commit is contained in:
commit
383de854dd
@ -90,6 +90,26 @@ export class Utils {
|
||||
return true;
|
||||
}
|
||||
|
||||
static toIsoString(d: number | Date) {
|
||||
if (!(d instanceof Date)) {
|
||||
d = new Date(d);
|
||||
}
|
||||
return d.getUTCFullYear() + '-' + d.getUTCMonth() + '-' + d.getUTCDate();
|
||||
}
|
||||
|
||||
|
||||
static makeUTCMidnight(d: number | Date) {
|
||||
if (!(d instanceof Date)) {
|
||||
d = new Date(d);
|
||||
}
|
||||
d.setUTCHours(0);
|
||||
d.setUTCMinutes(0);
|
||||
d.setUTCSeconds(0);
|
||||
d.setUTCMilliseconds(0);
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static renderDataSize(size: number): string {
|
||||
const postFixes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
||||
let index = 0;
|
||||
|
@ -183,6 +183,7 @@ import {ParseIntPipe} from './pipes/ParseIntPipe';
|
||||
import {
|
||||
SortingMethodSettingsEntryComponent
|
||||
} from './ui/settings/template/settings-entry/sorting-method/sorting-method.settings-entry.component';
|
||||
import {ContentLoaderService} from './ui/gallery/contentLoader.service';
|
||||
|
||||
@Injectable()
|
||||
export class MyHammerConfig extends HammerGestureConfig {
|
||||
@ -344,6 +345,7 @@ Marker.prototype.options.icon = MarkerFactory.defIcon;
|
||||
AlbumsService,
|
||||
GalleryCacheService,
|
||||
ContentService,
|
||||
ContentLoaderService,
|
||||
FilterService,
|
||||
GallerySortingService,
|
||||
MapService,
|
||||
|
@ -3,19 +3,17 @@ import { ShareService } from '../ui/gallery/share.service';
|
||||
import {MediaDTO} from '../../../common/entities/MediaDTO';
|
||||
import {QueryParams} from '../../../common/QueryParams';
|
||||
import {Utils} from '../../../common/Utils';
|
||||
import { ContentService } from '../ui/gallery/content.service';
|
||||
import {Config} from '../../../common/config/public/Config';
|
||||
import {
|
||||
ParentDirectoryDTO,
|
||||
SubDirectoryDTO,
|
||||
} from '../../../common/entities/DirectoryDTO';
|
||||
import {ParentDirectoryDTO, SubDirectoryDTO,} from '../../../common/entities/DirectoryDTO';
|
||||
import {ContentLoaderService} from '../ui/gallery/contentLoader.service';
|
||||
|
||||
@Injectable()
|
||||
export class QueryService {
|
||||
constructor(
|
||||
private shareService: ShareService,
|
||||
private galleryService: ContentService
|
||||
) {}
|
||||
private galleryService: ContentLoaderService
|
||||
) {
|
||||
}
|
||||
|
||||
getMediaStringId(media: MediaDTO): string {
|
||||
if (this.galleryService.isSearchResult()) {
|
||||
|
@ -1,4 +1,21 @@
|
||||
.btn-blog-details {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
border: 0;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.btn-blog-details:hover {
|
||||
background-image: linear-gradient(transparent, rgba(var(--bs-body-color-rgb), 0.5));
|
||||
}
|
||||
|
||||
.blog {
|
||||
opacity: 0.8;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.blog:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
|
@ -1,16 +1,25 @@
|
||||
<div class="blog">
|
||||
<ng-container *ngIf="mkObservable | async as markdowns">
|
||||
<div class="blog" *ngIf="markdowns.length > 0">
|
||||
<div class="card">
|
||||
<div class="card-body" style="min-height: 77px" [style.height]="collapsed ? '77px':''">
|
||||
<ng-container *ngFor="let md of markdowns; let i = index">
|
||||
<div class="card-body" style="min-height: 77px" [style.height]="!open ? '77px':''">
|
||||
<ng-container *ngFor="let md of markdowns; let last = last">
|
||||
<markdown
|
||||
*ngIf="!collapsed"
|
||||
[data]="md">
|
||||
*ngIf="open"
|
||||
[data]="md.text">
|
||||
</markdown>
|
||||
<span *ngIf="!open" class="text-preview">
|
||||
<markdown
|
||||
[inline]="true"
|
||||
[data]="md.text">
|
||||
</markdown>
|
||||
<span *ngIf="collapsed" class="text-preview">
|
||||
{{md}}
|
||||
</span>
|
||||
<hr *ngIf="i != markdowns.length-1">
|
||||
<hr *ngIf="!last">
|
||||
</ng-container>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-blog-details text-body" (click)="toggleCollapsed()">
|
||||
<ng-icon [name]="open ? 'ionChevronUpOutline' : 'ionChevronDownOutline'"></ng-icon>
|
||||
</button>
|
||||
</div>
|
||||
</ng-container>
|
||||
|
@ -1,7 +1,8 @@
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { FileDTO } from '../../../../../common/entities/FileDTO';
|
||||
import { BlogService } from './blog.service';
|
||||
import {Component, EventEmitter, Input, Output} from '@angular/core';
|
||||
import {BlogService, GroupedMarkdown} from './blog.service';
|
||||
import {OnChanges} from '../../../../../../node_modules/@angular/core';
|
||||
import {Utils} from '../../../../../common/Utils';
|
||||
import {map, Observable} from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-blog',
|
||||
@ -9,22 +10,30 @@ import { OnChanges } from '../../../../../../node_modules/@angular/core';
|
||||
styleUrls: ['./blog.gallery.component.css'],
|
||||
})
|
||||
export class GalleryBlogComponent implements OnChanges {
|
||||
@Input() mdFiles: FileDTO[];
|
||||
@Input() collapsed: boolean;
|
||||
markdowns: string[] = [];
|
||||
@Input() open: boolean;
|
||||
@Input() date: Date;
|
||||
@Output() openChange = new EventEmitter<boolean>();
|
||||
public markdowns: string[] = [];
|
||||
mkObservable: Observable<GroupedMarkdown[]>;
|
||||
|
||||
constructor(public blogService: BlogService) {}
|
||||
constructor(public blogService: BlogService) {
|
||||
}
|
||||
|
||||
|
||||
ngOnChanges(): void {
|
||||
this.loadMarkdown().catch(console.error);
|
||||
const utcDate = this.date ? this.date.getTime() : undefined;
|
||||
this.mkObservable = this.blogService.groupedMarkdowns.pipe(map(gm => {
|
||||
if (!this.date) {
|
||||
return gm.filter(g => !g.date);
|
||||
}
|
||||
return gm.filter(g => g.date == utcDate);
|
||||
}));
|
||||
}
|
||||
|
||||
async loadMarkdown(): Promise<void> {
|
||||
this.markdowns = [];
|
||||
for (const f of this.mdFiles) {
|
||||
this.markdowns.push(await this.blogService.getMarkDown(f));
|
||||
}
|
||||
|
||||
toggleCollapsed(): void {
|
||||
this.open = !this.open;
|
||||
this.openChange.emit(this.open);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,93 @@ import { Injectable } from '@angular/core';
|
||||
import {NetworkService} from '../../../model/network/network.service';
|
||||
import {FileDTO} from '../../../../../common/entities/FileDTO';
|
||||
import {Utils} from '../../../../../common/Utils';
|
||||
import {ContentService} from '../content.service';
|
||||
import {mergeMap, Observable} from 'rxjs';
|
||||
import {MDFilesFilterPipe} from '../../../pipes/MDFilesFilterPipe';
|
||||
|
||||
@Injectable()
|
||||
export class BlogService {
|
||||
cache: { [key: string]: Promise<string> | string } = {};
|
||||
public groupedMarkdowns: Observable<GroupedMarkdown[]>;
|
||||
|
||||
constructor(private networkService: NetworkService) {}
|
||||
constructor(private networkService: NetworkService,
|
||||
private galleryService: ContentService,
|
||||
private mdFilesFilterPipe: MDFilesFilterPipe) {
|
||||
|
||||
this.groupedMarkdowns = this.galleryService.sortedFilteredContent.pipe(
|
||||
mergeMap(async content => {
|
||||
if (!content) {
|
||||
return [];
|
||||
}
|
||||
const dates = content.mediaGroups.map(g => g.date)
|
||||
.filter(d => !!d).map(d => d.getTime());
|
||||
|
||||
const files = this.mdFilesFilterPipe.transform(content.metaFile)
|
||||
.map(f => this.splitMarkDown(f, dates));
|
||||
|
||||
return (await Promise.all(files)).flat();
|
||||
}));
|
||||
}
|
||||
|
||||
private async splitMarkDown(file: FileDTO, dates: number[]): Promise<GroupedMarkdown[]> {
|
||||
const markdown = await this.getMarkDown(file);
|
||||
|
||||
if (dates.length == 0) {
|
||||
return [{
|
||||
text: markdown,
|
||||
file: file
|
||||
}];
|
||||
}
|
||||
|
||||
dates.sort();
|
||||
|
||||
const splitterRgx = new RegExp(/<!--\s*@pg-date:?\s*\d{4}-\d{1,2}-\d{1,2}\s*-->/, 'gi');
|
||||
const dateRgx = new RegExp(/\d{4}-\d{1,2}-\d{1,2}/);
|
||||
|
||||
const ret: GroupedMarkdown[] = [];
|
||||
const matches = Array.from(markdown.matchAll(splitterRgx));
|
||||
|
||||
if (matches.length == 0) {
|
||||
return [{
|
||||
text: markdown,
|
||||
file: file
|
||||
}];
|
||||
}
|
||||
|
||||
ret.push({
|
||||
text: markdown.substring(0, matches[0].index),
|
||||
file: file
|
||||
});
|
||||
|
||||
|
||||
for (let i = 0; i < matches.length; ++i) {
|
||||
const matchedStr = matches[i][0];
|
||||
// get UTC midnight date
|
||||
const dateNum = Utils.makeUTCMidnight(new Date(matchedStr.match(dateRgx)[0])).getTime();
|
||||
|
||||
let groupDate = dates.find((d, i) => i > dates.length - 1 ? false : dates[i + 1] > dateNum); //dates are sorted
|
||||
|
||||
// cant find the date. put to the last group (as it was later)
|
||||
if (groupDate === undefined) {
|
||||
groupDate = dates[dates.length - 1];
|
||||
}
|
||||
const text = i + 1 >= matches.length ? markdown.substring(matches[i].index) : markdown.substring(matches[i].index, matches[i + 1].index);
|
||||
|
||||
// if it would be in the same group. Concatenate it
|
||||
const sameGroup = ret.find(g => g.date == groupDate);
|
||||
if (sameGroup) {
|
||||
sameGroup.text += text;
|
||||
continue;
|
||||
}
|
||||
ret.push({
|
||||
date: groupDate,
|
||||
text: text,
|
||||
file: file
|
||||
});
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public getMarkDown(file: FileDTO): Promise<string> {
|
||||
const filePath = Utils.concatUrls(
|
||||
@ -27,3 +108,9 @@ export class BlogService {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export interface GroupedMarkdown {
|
||||
date?: number;
|
||||
text: string;
|
||||
file: FileDTO;
|
||||
}
|
||||
|
@ -8,7 +8,7 @@ import {GroupingMethod, SortingMethod} from '../../../../common/entities/Sorting
|
||||
import {VersionService} from '../../model/version.service';
|
||||
import {SearchQueryDTO, SearchQueryTypes,} from '../../../../common/entities/SearchQueryDTO';
|
||||
import {ContentWrapper} from '../../../../common/entities/ConentWrapper';
|
||||
import {ContentWrapperWithError} from './content.service';
|
||||
import {ContentWrapperWithError} from './contentLoader.service';
|
||||
import {ThemeModes} from '../../../../common/config/public/ClientConfig';
|
||||
|
||||
interface CacheItem<T> {
|
||||
|
@ -1,148 +1,35 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {NetworkService} from '../../model/network/network.service';
|
||||
import {ContentWrapper} from '../../../../common/entities/ConentWrapper';
|
||||
import {
|
||||
ParentDirectoryDTO,
|
||||
SubDirectoryDTO,
|
||||
} from '../../../../common/entities/DirectoryDTO';
|
||||
import {SubDirectoryDTO,} from '../../../../common/entities/DirectoryDTO';
|
||||
import {GalleryCacheService} from './cache.gallery.service';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Config} from '../../../../common/config/public/Config';
|
||||
import {ShareService} from './share.service';
|
||||
import {NavigationService} from '../../model/navigation.service';
|
||||
import {QueryParams} from '../../../../common/QueryParams';
|
||||
import {SearchQueryDTO} from '../../../../common/entities/SearchQueryDTO';
|
||||
import {ErrorCodes} from '../../../../common/entities/Error';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {MediaDTO} from '../../../../common/entities/MediaDTO';
|
||||
import {FileDTO} from '../../../../common/entities/FileDTO';
|
||||
import {GallerySortingService, GroupedDirectoryContent} from './navigator/sorting.service';
|
||||
import {FilterService} from './filter/filter.service';
|
||||
import {ContentLoaderService} from './contentLoader.service';
|
||||
|
||||
@Injectable()
|
||||
export class ContentService {
|
||||
public content: BehaviorSubject<ContentWrapperWithError>;
|
||||
public directoryContent: Observable<DirectoryContent>;
|
||||
lastRequest: { directory: string } = {
|
||||
directory: null,
|
||||
};
|
||||
private lastDirectory: ParentDirectoryDTO;
|
||||
private searchId: any;
|
||||
private ongoingSearch: string = null;
|
||||
public sortedFilteredContent: Observable<GroupedDirectoryContent>;
|
||||
|
||||
constructor(
|
||||
private networkService: NetworkService,
|
||||
private galleryCacheService: GalleryCacheService,
|
||||
private shareService: ShareService,
|
||||
private navigationService: NavigationService
|
||||
private contentLoaderService: ContentLoaderService,
|
||||
private sortingService: GallerySortingService,
|
||||
private filterService: FilterService
|
||||
) {
|
||||
this.content = new BehaviorSubject<ContentWrapperWithError>(
|
||||
new ContentWrapperWithError()
|
||||
);
|
||||
this.directoryContent = this.content.pipe(
|
||||
map((c) => (c.directory ? c.directory : c.searchResult))
|
||||
);
|
||||
}
|
||||
|
||||
setContent(content: ContentWrapperWithError): void {
|
||||
this.content.next(content);
|
||||
}
|
||||
|
||||
public async loadDirectory(directoryName: string): Promise<void> {
|
||||
|
||||
// load from cache
|
||||
const cw = this.galleryCacheService.getDirectory(directoryName);
|
||||
|
||||
ContentWrapper.unpack(cw);
|
||||
this.setContent(cw);
|
||||
this.lastRequest.directory = directoryName;
|
||||
|
||||
// prepare server request
|
||||
const params: { [key: string]: any } = {};
|
||||
if (Config.Sharing.enabled === true) {
|
||||
if (this.shareService.isSharing()) {
|
||||
params[QueryParams.gallery.sharingKey_query] =
|
||||
this.shareService.getSharingKey();
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
cw.directory &&
|
||||
cw.directory.lastModified &&
|
||||
cw.directory.lastScanned &&
|
||||
!cw.directory.isPartial
|
||||
) {
|
||||
params[QueryParams.gallery.knownLastModified] =
|
||||
cw.directory.lastModified;
|
||||
params[QueryParams.gallery.knownLastScanned] =
|
||||
cw.directory.lastScanned;
|
||||
}
|
||||
|
||||
try {
|
||||
const cw = await this.networkService.getJson<ContentWrapperWithError>(
|
||||
'/gallery/content/' + encodeURIComponent(directoryName),
|
||||
params
|
||||
this.sortedFilteredContent = this.sortingService
|
||||
.applySorting(
|
||||
this.filterService.applyFilters(this.contentLoaderService.originalContent)
|
||||
);
|
||||
|
||||
if (!cw || cw.notModified === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.galleryCacheService.setDirectory(cw); // save it before adding references
|
||||
|
||||
if (this.lastRequest.directory !== directoryName) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentWrapper.unpack(cw);
|
||||
|
||||
this.lastDirectory = cw.directory;
|
||||
this.setContent(cw);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.navigationService.toGallery().catch(console.error);
|
||||
}
|
||||
}
|
||||
|
||||
public async search(query: string): Promise<void> {
|
||||
if (this.searchId != null) {
|
||||
clearTimeout(this.searchId);
|
||||
}
|
||||
|
||||
this.ongoingSearch = query;
|
||||
|
||||
this.setContent(new ContentWrapperWithError());
|
||||
let cw = this.galleryCacheService.getSearch(JSON.parse(query));
|
||||
if (!cw || cw.searchResult == null) {
|
||||
try {
|
||||
cw = await this.networkService.getJson<ContentWrapperWithError>('/search/' + query);
|
||||
this.galleryCacheService.setSearch(cw);
|
||||
} catch (e) {
|
||||
if (e.code === ErrorCodes.LocationLookUp_ERROR) {
|
||||
cw.error = 'Cannot find location: ' + e.message;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ongoingSearch !== query) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentWrapper.unpack(cw);
|
||||
this.setContent(cw);
|
||||
}
|
||||
|
||||
isSearchResult(): boolean {
|
||||
return !!this.content.value.searchResult;
|
||||
}
|
||||
}
|
||||
|
||||
export class ContentWrapperWithError extends ContentWrapper {
|
||||
public error?: string;
|
||||
}
|
||||
|
||||
export interface DirectoryContent {
|
||||
directories: SubDirectoryDTO[];
|
||||
media: MediaDTO[];
|
||||
metaFile: FileDTO[];
|
||||
}
|
||||
|
145
src/frontend/app/ui/gallery/contentLoader.service.ts
Normal file
145
src/frontend/app/ui/gallery/contentLoader.service.ts
Normal file
@ -0,0 +1,145 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {NetworkService} from '../../model/network/network.service';
|
||||
import {ContentWrapper} from '../../../../common/entities/ConentWrapper';
|
||||
import {SubDirectoryDTO,} from '../../../../common/entities/DirectoryDTO';
|
||||
import {GalleryCacheService} from './cache.gallery.service';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Config} from '../../../../common/config/public/Config';
|
||||
import {ShareService} from './share.service';
|
||||
import {NavigationService} from '../../model/navigation.service';
|
||||
import {QueryParams} from '../../../../common/QueryParams';
|
||||
import {ErrorCodes} from '../../../../common/entities/Error';
|
||||
import {map} from 'rxjs/operators';
|
||||
import {MediaDTO} from '../../../../common/entities/MediaDTO';
|
||||
import {FileDTO} from '../../../../common/entities/FileDTO';
|
||||
import {GroupedDirectoryContent} from './navigator/sorting.service';
|
||||
|
||||
@Injectable()
|
||||
export class ContentLoaderService {
|
||||
public content: BehaviorSubject<ContentWrapperWithError>;
|
||||
public originalContent: Observable<DirectoryContent>;
|
||||
public sortedFilteredContent: Observable<GroupedDirectoryContent>;
|
||||
lastRequest: { directory: string } = {
|
||||
directory: null,
|
||||
};
|
||||
private searchId: any;
|
||||
private ongoingSearch: string = null;
|
||||
|
||||
constructor(
|
||||
private networkService: NetworkService,
|
||||
private galleryCacheService: GalleryCacheService,
|
||||
private shareService: ShareService,
|
||||
private navigationService: NavigationService,
|
||||
) {
|
||||
this.content = new BehaviorSubject<ContentWrapperWithError>(
|
||||
new ContentWrapperWithError()
|
||||
);
|
||||
this.originalContent = this.content.pipe(
|
||||
map((c) => (c.directory ? c.directory : c.searchResult))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
setContent(content: ContentWrapperWithError): void {
|
||||
this.content.next(content);
|
||||
}
|
||||
|
||||
public async loadDirectory(directoryName: string): Promise<void> {
|
||||
|
||||
// load from cache
|
||||
const cw = this.galleryCacheService.getDirectory(directoryName);
|
||||
|
||||
ContentWrapper.unpack(cw);
|
||||
this.setContent(cw);
|
||||
this.lastRequest.directory = directoryName;
|
||||
|
||||
// prepare server request
|
||||
const params: { [key: string]: any } = {};
|
||||
if (Config.Sharing.enabled === true) {
|
||||
if (this.shareService.isSharing()) {
|
||||
params[QueryParams.gallery.sharingKey_query] =
|
||||
this.shareService.getSharingKey();
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
cw.directory &&
|
||||
cw.directory.lastModified &&
|
||||
cw.directory.lastScanned &&
|
||||
!cw.directory.isPartial
|
||||
) {
|
||||
params[QueryParams.gallery.knownLastModified] =
|
||||
cw.directory.lastModified;
|
||||
params[QueryParams.gallery.knownLastScanned] =
|
||||
cw.directory.lastScanned;
|
||||
}
|
||||
|
||||
try {
|
||||
const cw = await this.networkService.getJson<ContentWrapperWithError>(
|
||||
'/gallery/content/' + encodeURIComponent(directoryName),
|
||||
params
|
||||
);
|
||||
|
||||
if (!cw || cw.notModified === true) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.galleryCacheService.setDirectory(cw); // save it before adding references
|
||||
|
||||
if (this.lastRequest.directory !== directoryName) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentWrapper.unpack(cw);
|
||||
|
||||
this.setContent(cw);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
this.navigationService.toGallery().catch(console.error);
|
||||
}
|
||||
}
|
||||
|
||||
public async search(query: string): Promise<void> {
|
||||
if (this.searchId != null) {
|
||||
clearTimeout(this.searchId);
|
||||
}
|
||||
|
||||
this.ongoingSearch = query;
|
||||
|
||||
this.setContent(new ContentWrapperWithError());
|
||||
let cw = this.galleryCacheService.getSearch(JSON.parse(query));
|
||||
if (!cw || cw.searchResult == null) {
|
||||
try {
|
||||
cw = await this.networkService.getJson<ContentWrapperWithError>('/search/' + query);
|
||||
this.galleryCacheService.setSearch(cw);
|
||||
} catch (e) {
|
||||
if (e.code === ErrorCodes.LocationLookUp_ERROR) {
|
||||
cw.error = 'Cannot find location: ' + e.message;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.ongoingSearch !== query) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContentWrapper.unpack(cw);
|
||||
this.setContent(cw);
|
||||
}
|
||||
|
||||
isSearchResult(): boolean {
|
||||
return !!this.content.value.searchResult;
|
||||
}
|
||||
}
|
||||
|
||||
export class ContentWrapperWithError extends ContentWrapper {
|
||||
public error?: string;
|
||||
}
|
||||
|
||||
export interface DirectoryContent {
|
||||
directories: SubDirectoryDTO[];
|
||||
media: MediaDTO[];
|
||||
metaFile: FileDTO[];
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {PhotoDTO} from '../../../../../common/entities/PhotoDTO';
|
||||
import {DirectoryContent} from '../content.service';
|
||||
import {DirectoryContent} from '../contentLoader.service';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
|
||||
export enum FilterRenderType {
|
||||
|
@ -3,15 +3,6 @@
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.blog-wrapper {
|
||||
opacity: 0.8;
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.blog-wrapper:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.blog-map-row {
|
||||
width: 100%;
|
||||
@ -22,18 +13,6 @@
|
||||
min-height: 80px;
|
||||
}
|
||||
|
||||
.btn-blog-details {
|
||||
width: calc(100% - 5px);
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
margin-left: 2px;
|
||||
margin-right: 2px;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.btn-blog-details:hover {
|
||||
background-image: linear-gradient(transparent, rgba(var(--bs-body-color-rgb),0.5));
|
||||
}
|
||||
|
||||
app-gallery-blog {
|
||||
float: left;
|
||||
|
@ -40,17 +40,10 @@
|
||||
[directories]="directoryContent?.directories || []"></app-gallery-directories>
|
||||
|
||||
<div class="blog-map-row" *ngIf="ShowMarkDown || ShowMap">
|
||||
<div class="blog-wrapper"
|
||||
<app-gallery-blog
|
||||
[style.width]="blogOpen ? '100%' : 'calc(100% - 100px)'"
|
||||
*ngIf="ShowMarkDown">
|
||||
<app-gallery-blog [collapsed]="!blogOpen"
|
||||
[mdFiles]="directoryContent.metaFile | mdFiles"></app-gallery-blog>
|
||||
|
||||
|
||||
<button class="btn btn-blog-details text-body" (click)="blogOpen=!blogOpen">
|
||||
<ng-icon [name]="blogOpen ? 'ionChevronUpOutline' : 'ionChevronDownOutline'"></ng-icon>
|
||||
</button>
|
||||
</div>
|
||||
*ngIf="ShowMarkDown"
|
||||
[(open)]="blogOpen"></app-gallery-blog>
|
||||
<app-gallery-map
|
||||
class="rounded"
|
||||
[class.rounded-start-0]="ShowMarkDown"
|
||||
|
@ -1,7 +1,7 @@
|
||||
import {Component, OnDestroy, OnInit, ViewChild} from '@angular/core';
|
||||
import {AuthenticationService} from '../../model/network/authentication.service';
|
||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||
import {ContentService, ContentWrapperWithError,} from './content.service';
|
||||
import {ContentService} from './content.service';
|
||||
import {GalleryGridComponent} from './grid/grid.gallery.component';
|
||||
import {Config} from '../../../../common/config/public/Config';
|
||||
import {ShareService} from './share.service';
|
||||
@ -18,6 +18,7 @@ import {FilterService} from './filter/filter.service';
|
||||
import {PiTitleService} from '../../model/pi-title.service';
|
||||
import {GPXFilesFilterPipe} from '../../pipes/GPXFilesFilterPipe';
|
||||
import {MDFilesFilterPipe} from '../../pipes/MDFilesFilterPipe';
|
||||
import { ContentLoaderService,ContentWrapperWithError } from './contentLoader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery',
|
||||
@ -43,7 +44,6 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
} = null;
|
||||
public readonly mapEnabled: boolean;
|
||||
public directoryContent: GroupedDirectoryContent;
|
||||
public readonly mediaObs: Observable<MediaDTO[]>;
|
||||
private $counter: Observable<number>;
|
||||
private subscription: { [key: string]: Subscription } = {
|
||||
content: null,
|
||||
@ -53,6 +53,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
};
|
||||
|
||||
constructor(
|
||||
public contentLoader: ContentLoaderService,
|
||||
public galleryService: ContentService,
|
||||
private authService: AuthenticationService,
|
||||
private router: Router,
|
||||
@ -70,7 +71,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
get ContentWrapper(): ContentWrapperWithError {
|
||||
return this.galleryService.content.value;
|
||||
return this.contentLoader.content.value;
|
||||
}
|
||||
|
||||
updateTimer(t: number): void {
|
||||
@ -133,10 +134,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
this.showRandomPhotoBuilder =
|
||||
Config.RandomPhoto.enabled &&
|
||||
this.authService.isAuthorized(UserRoles.User);
|
||||
this.subscription.content = this.sortingService
|
||||
.applySorting(
|
||||
this.filterService.applyFilters(this.galleryService.directoryContent)
|
||||
)
|
||||
this.subscription.content = this.galleryService.sortedFilteredContent
|
||||
.subscribe((dc: GroupedDirectoryContent) => {
|
||||
this.onContentChange(dc);
|
||||
});
|
||||
@ -153,7 +151,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
private onRoute = async (params: Params): Promise<void> => {
|
||||
const searchQuery = params[QueryParams.gallery.search.query];
|
||||
if (searchQuery) {
|
||||
this.galleryService.search(searchQuery).catch(console.error);
|
||||
this.contentLoader.search(searchQuery).catch(console.error);
|
||||
this.piTitleService.setSearchTitle(searchQuery);
|
||||
return;
|
||||
}
|
||||
@ -178,7 +176,7 @@ export class GalleryComponent implements OnInit, OnDestroy {
|
||||
directoryName = directoryName || '';
|
||||
|
||||
this.piTitleService.setDirectoryTitle(directoryName);
|
||||
this.galleryService.loadDirectory(directoryName);
|
||||
this.contentLoader.loadDirectory(directoryName);
|
||||
};
|
||||
|
||||
private onContentChange = (content: GroupedDirectoryContent): void => {
|
||||
|
@ -3,13 +3,24 @@
|
||||
<ng-container *ngFor="let group of mediaToRender">
|
||||
<ng-container *ngIf="group.name">
|
||||
<ng-container [ngSwitch]="sortingService.grouping.value.method">
|
||||
<div *ngSwitchCase="GroupByTypes.Rating" class="mt-4 mb-3"><h6 class="ms-2">
|
||||
<ng-icon *ngFor="let i of [0,1,2,3,4]" [name]="(i < (group.name | parseInt)) ? 'ionStar' : 'ionStarOutline'"></ng-icon>
|
||||
</h6></div>
|
||||
<div *ngSwitchCase="GroupByTypes.PersonCount" class="mt-4 mb-3"><h6 class="ms-2">{{group.name}} <ng-icon class="ms-1" name="ionPeopleOutline"></ng-icon></h6></div>
|
||||
<div *ngSwitchCase="GroupByTypes.Rating" class="mt-4 mb-3">
|
||||
<h6 class="ms-2">
|
||||
<ng-icon *ngFor="let i of [0,1,2,3,4]"
|
||||
[name]="(i < (group.name | parseInt)) ? 'ionStar' : 'ionStarOutline'"></ng-icon>
|
||||
</h6>
|
||||
</div>
|
||||
<div *ngSwitchCase="GroupByTypes.PersonCount" class="mt-4 mb-3">
|
||||
<h6 class="ms-2">{{group.name}}
|
||||
<ng-icon class="ms-1" name="ionPeopleOutline"></ng-icon>
|
||||
</h6>
|
||||
</div>
|
||||
<div *ngSwitchDefault class="mt-4 mb-3"><h6 class="ms-2">{{group.name}}</h6></div>
|
||||
</ng-container>
|
||||
</ng-container>
|
||||
|
||||
<ng-container *ngIf="group.date">
|
||||
<app-gallery-blog [date]="group.date" [open]="false"></app-gallery-blog>
|
||||
</ng-container>
|
||||
<div class="media-grid">
|
||||
<app-gallery-grid-photo
|
||||
*ngFor="let gridPhoto of group.media"
|
||||
|
@ -22,7 +22,6 @@ import {PageHelper} from '../../../model/page.helper';
|
||||
import {Subscription} from 'rxjs';
|
||||
import {ActivatedRoute, Params, Router} from '@angular/router';
|
||||
import {QueryService} from '../../../model/query.service';
|
||||
import {ContentService} from '../content.service';
|
||||
import {MediaDTO, MediaDTOUtils,} from '../../../../../common/entities/MediaDTO';
|
||||
import {QueryParams} from '../../../../../common/QueryParams';
|
||||
import {GallerySortingService, MediaGroup} from '../navigator/sorting.service';
|
||||
@ -65,7 +64,6 @@ export class GalleryGridComponent
|
||||
private changeDetector: ChangeDetectorRef,
|
||||
public queryService: QueryService,
|
||||
private router: Router,
|
||||
public galleryService: ContentService,
|
||||
public sortingService: GallerySortingService,
|
||||
private route: ActivatedRoute
|
||||
) {
|
||||
@ -259,7 +257,11 @@ export class GalleryGridComponent
|
||||
if (this.mediaToRender.length == 0 ||
|
||||
this.mediaToRender[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,
|
||||
date: this.mediaGroups[this.mediaToRender.length].date,
|
||||
media: []
|
||||
} as GridMediaGroup);
|
||||
}
|
||||
|
||||
let maxRowHeight = this.getMaxRowHeight();
|
||||
@ -453,4 +455,5 @@ export class GalleryGridComponent
|
||||
interface GridMediaGroup {
|
||||
media: GridMedia[];
|
||||
name: string;
|
||||
date?: Date;
|
||||
}
|
||||
|
@ -4,7 +4,7 @@
|
||||
<button type="button" class="btn-close" (click)="close()" aria-label="Close">
|
||||
</button>
|
||||
</div>
|
||||
<div class="row" *ngIf="galleryService.isSearchResult()">
|
||||
<div class="row" *ngIf="contentLoaderService.isSearchResult()">
|
||||
<div class="col-1 ps-0">
|
||||
<ng-icon class="details-icon" name="ionFolderOutline"></ng-icon>
|
||||
</div>
|
||||
|
@ -11,6 +11,7 @@ import {AuthenticationService} from '../../../../model/network/authentication.se
|
||||
import {LatLngLiteral, marker, Marker, TileLayer, tileLayer} from 'leaflet';
|
||||
import {ContentService} from '../../content.service';
|
||||
import {ThemeService} from '../../../../model/theme.service';
|
||||
import { ContentLoaderService } from '../../contentLoader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-info-panel',
|
||||
@ -31,7 +32,7 @@ export class InfoPanelLightboxComponent implements OnInit, OnChanges {
|
||||
|
||||
constructor(
|
||||
public queryService: QueryService,
|
||||
public galleryService: ContentService,
|
||||
public contentLoaderService: ContentLoaderService,
|
||||
public mapService: MapService,
|
||||
private authService: AuthenticationService,
|
||||
private themeService: ThemeService
|
||||
|
@ -13,7 +13,7 @@
|
||||
<ol *ngIf="isSearch" class="mb-0 mt-1 breadcrumb">
|
||||
<li class="active">
|
||||
<ng-container i18n>Searching for:</ng-container>
|
||||
<strong> {{galleryService.content.value?.searchResult?.searchQuery | searchQuery}}</strong>
|
||||
<strong> {{contentLoaderService.content.value?.searchResult?.searchQuery | searchQuery}}</strong>
|
||||
</li>
|
||||
</ol>
|
||||
|
||||
|
@ -4,7 +4,6 @@ import {DomSanitizer} from '@angular/platform-browser';
|
||||
import {UserDTOUtils} from '../../../../../common/entities/UserDTO';
|
||||
import {AuthenticationService} from '../../../model/network/authentication.service';
|
||||
import {QueryService} from '../../../model/query.service';
|
||||
import {ContentService, ContentWrapperWithError, DirectoryContent,} from '../content.service';
|
||||
import {Utils} from '../../../../../common/Utils';
|
||||
import {GroupByTypes, GroupingMethod, SortByDirectionalTypes, SortByTypes} from '../../../../../common/entities/SortingMethods';
|
||||
import {Config} from '../../../../../common/config/public/Config';
|
||||
@ -15,6 +14,7 @@ import {GallerySortingService} from './sorting.service';
|
||||
import {PageHelper} from '../../../model/page.helper';
|
||||
import {BsDropdownDirective} from 'ngx-bootstrap/dropdown';
|
||||
import {FilterService} from '../filter/filter.service';
|
||||
import {ContentLoaderService, ContentWrapperWithError, DirectoryContent} from '../contentLoader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-navbar',
|
||||
@ -47,7 +47,7 @@ export class GalleryNavigatorComponent {
|
||||
constructor(
|
||||
public authService: AuthenticationService,
|
||||
public queryService: QueryService,
|
||||
public galleryService: ContentService,
|
||||
public contentLoaderService: ContentLoaderService,
|
||||
public filterService: FilterService,
|
||||
public sortingService: GallerySortingService,
|
||||
private router: Router,
|
||||
@ -57,11 +57,11 @@ export class GalleryNavigatorComponent {
|
||||
// can't group by random
|
||||
this.groupingByTypes = Utils.enumToArray(GroupByTypes);
|
||||
this.RootFolderName = $localize`Home`;
|
||||
this.wrappedContent = this.galleryService.content;
|
||||
this.wrappedContent = this.contentLoaderService.content;
|
||||
this.directoryContent = this.wrappedContent.pipe(
|
||||
map((c) => (c.directory ? c.directory : c.searchResult))
|
||||
);
|
||||
this.routes = this.galleryService.content.pipe(
|
||||
this.routes = this.contentLoaderService.content.pipe(
|
||||
map((c) => {
|
||||
this.parentPath = null;
|
||||
if (!c.directory) {
|
||||
@ -124,15 +124,15 @@ export class GalleryNavigatorComponent {
|
||||
}
|
||||
|
||||
get isDirectory(): boolean {
|
||||
return !!this.galleryService.content.value.directory;
|
||||
return !!this.contentLoaderService.content.value.directory;
|
||||
}
|
||||
|
||||
get isSearch(): boolean {
|
||||
return !!this.galleryService.content.value.searchResult;
|
||||
return !!this.contentLoaderService.content.value.searchResult;
|
||||
}
|
||||
|
||||
get ItemCount(): number {
|
||||
const c = this.galleryService.content.value;
|
||||
const c = this.contentLoaderService.content.value;
|
||||
return c.directory
|
||||
? c.directory.mediaCount
|
||||
: c.searchResult
|
||||
@ -142,7 +142,7 @@ export class GalleryNavigatorComponent {
|
||||
|
||||
isDefaultSortingAndGrouping(): boolean {
|
||||
return this.sortingService.isDefaultSortingAndGrouping(
|
||||
this.galleryService.content.value
|
||||
this.contentLoaderService.content.value
|
||||
);
|
||||
}
|
||||
|
||||
@ -193,7 +193,7 @@ export class GalleryNavigatorComponent {
|
||||
|
||||
|
||||
getDownloadZipLink(): string {
|
||||
const c = this.galleryService.content.value;
|
||||
const c = this.contentLoaderService.content.value;
|
||||
if (!c.directory) {
|
||||
return null;
|
||||
}
|
||||
@ -212,7 +212,7 @@ export class GalleryNavigatorComponent {
|
||||
}
|
||||
|
||||
getDirectoryFlattenSearchQuery(): string {
|
||||
const c = this.galleryService.content.value;
|
||||
const c = this.contentLoaderService.content.value;
|
||||
if (!c.directory) {
|
||||
return null;
|
||||
}
|
||||
|
@ -4,9 +4,8 @@ import {NetworkService} from '../../../model/network/network.service';
|
||||
import {GalleryCacheService} from '../cache.gallery.service';
|
||||
import {BehaviorSubject, Observable} from 'rxjs';
|
||||
import {Config} from '../../../../../common/config/public/Config';
|
||||
import {GroupingMethod, SortByTypes, SortingMethod} from '../../../../../common/entities/SortingMethods';
|
||||
import {GroupByTypes, GroupingMethod, SortByTypes, SortingMethod} from '../../../../../common/entities/SortingMethods';
|
||||
import {PG2ConfMap} from '../../../../../common/PG2ConfMap';
|
||||
import {ContentService, DirectoryContent} from '../content.service';
|
||||
import {PhotoDTO} from '../../../../../common/entities/PhotoDTO';
|
||||
import {map, switchMap} from 'rxjs/operators';
|
||||
import {SeededRandomService} from '../../../model/seededRandom.service';
|
||||
@ -14,6 +13,8 @@ import {ContentWrapper} from '../../../../../common/entities/ConentWrapper';
|
||||
import {SubDirectoryDTO} from '../../../../../common/entities/DirectoryDTO';
|
||||
import {MediaDTO} from '../../../../../common/entities/MediaDTO';
|
||||
import {FileDTO} from '../../../../../common/entities/FileDTO';
|
||||
import {Utils} from '../../../../../common/Utils';
|
||||
import {ContentLoaderService, DirectoryContent} from '../contentLoader.service';
|
||||
|
||||
@Injectable()
|
||||
export class GallerySortingService {
|
||||
@ -24,7 +25,7 @@ export class GallerySortingService {
|
||||
constructor(
|
||||
private networkService: NetworkService,
|
||||
private galleryCacheService: GalleryCacheService,
|
||||
private galleryService: ContentService,
|
||||
private galleryService: ContentLoaderService,
|
||||
private rndService: SeededRandomService,
|
||||
private datePipe: DatePipe
|
||||
) {
|
||||
@ -176,6 +177,38 @@ export class GallerySortingService {
|
||||
return;
|
||||
}
|
||||
|
||||
private getGroupByNameFn(grouping: GroupingMethod) {
|
||||
switch (grouping.method) {
|
||||
case SortByTypes.Date:
|
||||
return (m: MediaDTO) => this.datePipe.transform(m.metadata.creationDate, 'longDate', 'UTC');
|
||||
|
||||
case SortByTypes.Name:
|
||||
return (m: MediaDTO) => m.name.at(0).toUpperCase();
|
||||
|
||||
case SortByTypes.Rating:
|
||||
return (m: MediaDTO) => ((m as PhotoDTO).metadata.rating || 0).toString();
|
||||
|
||||
case SortByTypes.FileSize: {
|
||||
const groups = [0.5, 1, 2, 5, 10, 15, 20, 30, 50, 100, 200, 500, 1000]; // MBs
|
||||
return (m: MediaDTO) => {
|
||||
const mbites = ((m as PhotoDTO).metadata.fileSize || 0) / 1024 / 1024;
|
||||
const i = groups.findIndex((s) => s > mbites);
|
||||
if (i == -1) {
|
||||
return '>' + groups[groups.length - 1] + ' MB';
|
||||
} else if (i == 0) {
|
||||
return '<' + groups[0] + ' MB';
|
||||
}
|
||||
return groups[i - 1] + ' - ' + groups[i] + ' MB';
|
||||
};
|
||||
}
|
||||
|
||||
case SortByTypes.PersonCount:
|
||||
return (m: MediaDTO) => ((m as PhotoDTO).metadata.faces || []).length.toString();
|
||||
|
||||
}
|
||||
return (m: MediaDTO) => '';
|
||||
}
|
||||
|
||||
public applySorting(
|
||||
directoryContent: Observable<DirectoryContent>
|
||||
): Observable<GroupedDirectoryContent> {
|
||||
@ -243,36 +276,10 @@ export class GallerySortingService {
|
||||
if (dirContent.media) {
|
||||
const mCopy = dirContent.media;
|
||||
this.sortMedia(grouping, mCopy);
|
||||
let groupFN = (m: MediaDTO) => '';
|
||||
switch (grouping.method) {
|
||||
case SortByTypes.Date:
|
||||
groupFN = (m: MediaDTO) => this.datePipe.transform(m.metadata.creationDate, 'longDate');
|
||||
break;
|
||||
case SortByTypes.Name:
|
||||
groupFN = (m: MediaDTO) => m.name.at(0).toUpperCase();
|
||||
break;
|
||||
case SortByTypes.Rating:
|
||||
groupFN = (m: MediaDTO) => ((m as PhotoDTO).metadata.rating || 0).toString();
|
||||
break;
|
||||
case SortByTypes.FileSize: {
|
||||
const groups = [0.5, 1, 2, 5, 10, 15, 20, 30, 50]; // MBs
|
||||
groupFN = (m: MediaDTO) => {
|
||||
const mbites = ((m as PhotoDTO).metadata.fileSize || 0) / 1024 / 1024;
|
||||
const i = groups.findIndex((s) => s > mbites);
|
||||
if (i == -1) {
|
||||
return '>' + groups[groups.length - 1] + ' MB';
|
||||
} else if (i == 0) {
|
||||
return '<' + groups[0] + ' MB';
|
||||
}
|
||||
return groups[i - 1] + ' - ' + groups[i] + ' MB';
|
||||
};
|
||||
}
|
||||
break;
|
||||
case SortByTypes.PersonCount:
|
||||
groupFN = (m: MediaDTO) => ((m as PhotoDTO).metadata.faces || []).length.toString();
|
||||
break;
|
||||
}
|
||||
const groupFN = this.getGroupByNameFn(grouping);
|
||||
|
||||
c.mediaGroups = [];
|
||||
|
||||
for (const m of mCopy) {
|
||||
const k = groupFN(m);
|
||||
if (c.mediaGroups.length == 0 || c.mediaGroups[c.mediaGroups.length - 1].name != k) {
|
||||
@ -280,7 +287,13 @@ export class GallerySortingService {
|
||||
}
|
||||
c.mediaGroups[c.mediaGroups.length - 1].media.push(m);
|
||||
}
|
||||
c.mediaGroups;
|
||||
}
|
||||
|
||||
if (grouping.method === GroupByTypes.Date) {
|
||||
// We do not need the youngest as we group by day. All photos are from the same day
|
||||
c.mediaGroups.forEach(g => {
|
||||
g.date = Utils.makeUTCMidnight(new Date(g.media?.[0]?.metadata?.creationDate));
|
||||
});
|
||||
}
|
||||
|
||||
// sort groups
|
||||
@ -300,6 +313,7 @@ export class GallerySortingService {
|
||||
|
||||
export interface MediaGroup {
|
||||
name: string;
|
||||
date?: Date; // used for blog. It allows to chop off blog to smaller pieces
|
||||
media: MediaDTO[];
|
||||
}
|
||||
|
||||
|
@ -15,6 +15,7 @@ import {
|
||||
import { ActivatedRoute, Params } from '@angular/router';
|
||||
import { QueryParams } from '../../../../../common/QueryParams';
|
||||
import { SearchQueryParserService } from '../search/search-query-parser.service';
|
||||
import {ContentLoaderService} from '../contentLoader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-random-query-builder',
|
||||
@ -36,7 +37,7 @@ export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
||||
private readonly subscription: Subscription = null;
|
||||
|
||||
constructor(
|
||||
public galleryService: ContentService,
|
||||
public contentLoaderService: ContentLoaderService,
|
||||
private notification: NotificationService,
|
||||
private searchQueryParserService: SearchQueryParserService,
|
||||
private route: ActivatedRoute,
|
||||
@ -65,7 +66,7 @@ export class RandomQueryBuilderGalleryComponent implements OnInit, OnDestroy {
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.contentSubscription = this.galleryService.content.subscribe(
|
||||
this.contentSubscription = this.contentLoaderService.content.subscribe(
|
||||
(content: ContentWrapper) => {
|
||||
this.enabled = !!content.directory;
|
||||
if (!this.enabled) {
|
||||
|
@ -12,6 +12,7 @@ import {Subscription} from 'rxjs';
|
||||
import {UserRoles} from '../../../../../common/entities/UserDTO';
|
||||
import {AuthenticationService} from '../../../model/network/authentication.service';
|
||||
import {ClipboardService} from 'ngx-clipboard';
|
||||
import {ContentLoaderService} from '../contentLoader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-share',
|
||||
@ -51,7 +52,7 @@ export class GalleryShareComponent implements OnInit, OnDestroy {
|
||||
|
||||
constructor(
|
||||
public sharingService: ShareService,
|
||||
public galleryService: ContentService,
|
||||
public galleryService: ContentLoaderService,
|
||||
private notification: NotificationService,
|
||||
private modalService: BsModalService,
|
||||
public authService: AuthenticationService,
|
||||
|
Loading…
x
Reference in New Issue
Block a user