From e68fbbbe44d12f207428e5188fd189276bf8afae Mon Sep 17 00:00:00 2001 From: "Patrik J. Braun" Date: Tue, 26 Dec 2023 00:36:50 +0100 Subject: [PATCH] Create customizable lightbox text. fixes #801 --- src/common/config/public/ClientConfig.ts | 414 +++++++++++------- src/frontend/app/app.module.ts | 1 + .../controls.lightbox.gallery.component.css | 17 +- .../controls.lightbox.gallery.component.html | 28 +- .../controls.lightbox.gallery.component.ts | 115 +++-- 5 files changed, 371 insertions(+), 204 deletions(-) diff --git a/src/common/config/public/ClientConfig.ts b/src/common/config/public/ClientConfig.ts index 7fb940b7..316d738a 100644 --- a/src/common/config/public/ClientConfig.ts +++ b/src/common/config/public/ClientConfig.ts @@ -34,6 +34,32 @@ export enum ScrollUpModes { never = 1, mobileOnly, always } +/** + * Used for lightbox titles + */ +export enum LightBoxTitleTexts { + NONE = 1, + file, + resolution, + size, + + caption, + title, + + keywords, + persons, + location, + date, + rating, + + camera, + lens, + iso, + fstop, + focal_length + +} + export type TAGS = { client?: true, priority?: ConfigPriority, @@ -68,10 +94,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Maximum items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Maximum items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown at once. If there is not enough items to reach this value, it takes upto double of the individual items.` }) maxItems: number = 20; @@ -79,10 +105,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Max photo items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max photo items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per photo category.` }) fileName: number = 2; @@ -90,10 +116,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Max directory items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max directory items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per directory category.` }) directory: number = 2; @@ -101,10 +127,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Max caption items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max caption items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per caption category.` }) caption: number = 3; @@ -112,10 +138,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Max position items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max position items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per position category.` }) position: number = 3; @@ -123,10 +149,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Max faces items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max faces items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per faces category.` }) person: number = 5; @@ -134,10 +160,10 @@ export class AutoCompleteItemsPerCategoryConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Max keyword items`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max keyword items`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per keyword category.` }) keyword: number = 5; @@ -147,20 +173,20 @@ export class AutoCompleteItemsPerCategoryConfig { export class AutoCompleteConfig { @ConfigProperty({ tags: - { - name: $localize`Enable Autocomplete`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Enable Autocomplete`, + priority: ConfigPriority.advanced + }, description: $localize`Show hints while typing search query.` }) enabled: boolean = true; @ConfigProperty({ tags: - { - name: $localize`Max items per category`, - priority: ConfigPriority.underTheHood - }, + { + name: $localize`Max items per category`, + priority: ConfigPriority.underTheHood + }, description: $localize`Maximum number autocomplete items shown per category.` }) ItemsPerCategory: AutoCompleteItemsPerCategoryConfig = new AutoCompleteItemsPerCategoryConfig(); @@ -168,11 +194,11 @@ export class AutoCompleteConfig { @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Cache timeout`, - priority: ConfigPriority.underTheHood, - unit: 'ms' - }, + { + name: $localize`Cache timeout`, + priority: ConfigPriority.underTheHood, + unit: 'ms' + }, description: $localize`Autocomplete cache timeout. ` }) cacheTimeout: number = 1000 * 60 * 60; @@ -182,66 +208,66 @@ export class AutoCompleteConfig { export class ClientSearchConfig { @ConfigProperty({ tags: - { - name: $localize`Enable`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Enable`, + priority: ConfigPriority.advanced + }, description: $localize`Enables searching.` }) enabled: boolean = true; @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Cache timeout`, - priority: ConfigPriority.underTheHood, - unit: 'ms' - }, + { + name: $localize`Cache timeout`, + priority: ConfigPriority.underTheHood, + unit: 'ms' + }, description: $localize`Search cache timeout.` }) searchCacheTimeout: number = 1000 * 60 * 60; @ConfigProperty({ tags: - { - name: $localize`Autocomplete`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Autocomplete`, + priority: ConfigPriority.advanced + }, }) AutoComplete: AutoCompleteConfig = new AutoCompleteConfig(); @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Maximum media result`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Maximum media result`, + priority: ConfigPriority.advanced + }, description: $localize`Maximum number of photos and videos that are listed in one search result.` }) maxMediaResult: number = 10000; @ConfigProperty({ type: 'unsignedInt', tags: - { - name: $localize`Maximum directory result`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Maximum directory result`, + priority: ConfigPriority.advanced + }, description: $localize`Maximum number of directories that are listed in one search result.` }) maxDirectoryResult: number = 200; @ConfigProperty({ tags: - { - name: $localize`List directories`, - priority: ConfigPriority.advanced - }, + { + name: $localize`List directories`, + priority: ConfigPriority.advanced + }, description: $localize`Search returns also with directories, not just media.` }) listDirectories: boolean = false; @ConfigProperty({ tags: - { - name: $localize`List metafiles`, - priority: ConfigPriority.advanced - }, + { + name: $localize`List metafiles`, + priority: ConfigPriority.advanced + }, description: $localize`Search also returns with metafiles from directories that contain a media file of the matched search result.`, }) listMetafiles: boolean = true; @@ -251,10 +277,10 @@ export class ClientSearchConfig { export class ClientAlbumConfig { @ConfigProperty({ tags: - { - name: $localize`Enable`, - priority: ConfigPriority.advanced - } + { + name: $localize`Enable`, + priority: ConfigPriority.advanced + } }) enabled: boolean = true; } @@ -263,19 +289,19 @@ export class ClientAlbumConfig { export class ClientSharingConfig { @ConfigProperty({ tags: - { - name: $localize`Enable`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Enable`, + priority: ConfigPriority.advanced + }, description: $localize`Enables sharing.`, }) enabled: boolean = true; @ConfigProperty({ tags: - { - name: $localize`Require password`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Require password`, + priority: ConfigPriority.advanced + }, description: $localize`Requires password protected sharing links.`, }) passwordRequired: boolean = false; @@ -285,10 +311,10 @@ export class ClientSharingConfig { export class ClientRandomPhotoConfig { @ConfigProperty({ tags: - { - name: $localize`Enable`, - priority: ConfigPriority.advanced - }, + { + name: $localize`Enable`, + priority: ConfigPriority.advanced + }, description: $localize`Enables random link generation.`, }) enabled: boolean = true; @@ -298,26 +324,26 @@ export class ClientRandomPhotoConfig { export class MapLayers { @ConfigProperty({ tags: - { - priority: ConfigPriority.advanced - }, + { + priority: ConfigPriority.advanced + }, description: $localize`Name of a map layer.`, }) name: string = 'street'; @ConfigProperty({ tags: - { - priority: ConfigPriority.advanced, - hint: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' - }, + { + priority: ConfigPriority.advanced, + hint: 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png' + }, description: $localize`Url of a map layer.`, }) url: string = ''; @ConfigProperty({ tags: - { - priority: ConfigPriority.advanced, - }, + { + priority: ConfigPriority.advanced, + }, description: $localize`Sets if the layer is dark (used as default in the dark mode).`, }) darkLayer: boolean = false; @@ -485,11 +511,11 @@ export class ClientMapConfig { mapProvider: MapProviders = MapProviders.OpenStreetMap; @ConfigProperty({ tags: - { - name: $localize`Mapbox access token`, - relevant: (c: any) => c.mapProvider === MapProviders.Mapbox, - priority: ConfigPriority.advanced - }, + { + name: $localize`Mapbox access token`, + relevant: (c: any) => c.mapProvider === MapProviders.Mapbox, + priority: ConfigPriority.advanced + }, description: $localize`MapBox needs an access token to work, create one at https://www.mapbox.com.`, }) mapboxAccessToken: string = ''; @@ -527,62 +553,62 @@ export class ClientMapConfig { }) MapPathGroupConfig: MapPathGroupConfig[] = [ new MapPathGroupConfig('Transportation', - [new MapPathGroupThemeConfig( - ['flight', 'flying'], - new PathThemeConfig('var(--bs-orange)', - '4 8', - new SVGIconConfig('0 0 567 512', '') - ) - ), new MapPathGroupThemeConfig( - ['drive', 'driving'], - new PathThemeConfig('var(--bs-orange)', - '4 8', - new SVGIconConfig('0 0 640 512', '') - ) - ), new MapPathGroupThemeConfig( - ['ship', 'sailing', 'cruise'], - new PathThemeConfig('var(--bs-orange)', - '4 8', - new SVGIconConfig('0 0 576 512', '') - ) - )]), + [new MapPathGroupThemeConfig( + ['flight', 'flying'], + new PathThemeConfig('var(--bs-orange)', + '4 8', + new SVGIconConfig('0 0 567 512', '') + ) + ), new MapPathGroupThemeConfig( + ['drive', 'driving'], + new PathThemeConfig('var(--bs-orange)', + '4 8', + new SVGIconConfig('0 0 640 512', '') + ) + ), new MapPathGroupThemeConfig( + ['ship', 'sailing', 'cruise'], + new PathThemeConfig('var(--bs-orange)', + '4 8', + new SVGIconConfig('0 0 576 512', '') + ) + )]), new MapPathGroupConfig('Sport', - [new MapPathGroupThemeConfig( - ['run'], - new PathThemeConfig('var(--bs-primary)', - '', - new SVGIconConfig('0 0 417 512', '') - ) - ), new MapPathGroupThemeConfig( - ['walk'], - new PathThemeConfig('var(--bs-primary)', - '', - new SVGIconConfig('0 0 320 512', '') - ) - ), new MapPathGroupThemeConfig( - ['hike', 'hiking'], - new PathThemeConfig('var(--bs-primary)', - '', - new SVGIconConfig('0 0 384 512', '') - ) - ), new MapPathGroupThemeConfig( - ['bike', 'biking', 'cycling'], - new PathThemeConfig('var(--bs-primary)', - '', - new SVGIconConfig('0 0 640 512', '') - ) - ), new MapPathGroupThemeConfig( - ['skiing', 'ski'], - new PathThemeConfig('var(--bs-primary)', - '', - new SVGIconConfig('0 0 512 512', '') - ) - )]), + [new MapPathGroupThemeConfig( + ['run'], + new PathThemeConfig('var(--bs-primary)', + '', + new SVGIconConfig('0 0 417 512', '') + ) + ), new MapPathGroupThemeConfig( + ['walk'], + new PathThemeConfig('var(--bs-primary)', + '', + new SVGIconConfig('0 0 320 512', '') + ) + ), new MapPathGroupThemeConfig( + ['hike', 'hiking'], + new PathThemeConfig('var(--bs-primary)', + '', + new SVGIconConfig('0 0 384 512', '') + ) + ), new MapPathGroupThemeConfig( + ['bike', 'biking', 'cycling'], + new PathThemeConfig('var(--bs-primary)', + '', + new SVGIconConfig('0 0 640 512', '') + ) + ), new MapPathGroupThemeConfig( + ['skiing', 'ski'], + new PathThemeConfig('var(--bs-primary)', + '', + new SVGIconConfig('0 0 512 512', '') + ) + )]), new MapPathGroupConfig('Other paths', - [new MapPathGroupThemeConfig( - [], // Match all - new PathThemeConfig('var(--bs-secondary)') - )]) + [new MapPathGroupThemeConfig( + [], // Match all + new PathThemeConfig('var(--bs-secondary)') + )]) ]; @ConfigProperty({ type: 'positiveFloat', @@ -898,6 +924,47 @@ export class NavBarConfig { } + +@SubConfigClass({tags: {client: true}, softReadonly: true}) +export class ClientLightboxTitleConfig { + + @ConfigProperty({ + type: LightBoxTitleTexts, + tags: { + name: $localize`Top left title`, + priority: ConfigPriority.advanced + }, + }) + topLeftTitle: LightBoxTitleTexts = LightBoxTitleTexts.title; + + @ConfigProperty({ + type: LightBoxTitleTexts, + tags: { + name: $localize`Top left subtitle`, + priority: ConfigPriority.advanced + }, + }) + topLeftSubtitle: LightBoxTitleTexts = LightBoxTitleTexts.caption; + + @ConfigProperty({ + type: LightBoxTitleTexts, + tags: { + name: $localize`Bottom left title`, + priority: ConfigPriority.advanced + }, + }) + bottomLeftTitle: LightBoxTitleTexts = LightBoxTitleTexts.location; + + @ConfigProperty({ + type: LightBoxTitleTexts, + tags: { + name: $localize`Bottom right subtitle`, + priority: ConfigPriority.advanced + }, + }) + bottomLeftSubtitle: LightBoxTitleTexts = LightBoxTitleTexts.persons; +} + @SubConfigClass({tags: {client: true}, softReadonly: true}) export class ClientLightboxConfig { @@ -936,6 +1003,17 @@ export class ClientLightboxConfig { description: $localize`If enabled, lightbox will loop videos by default.` }) loopVideos: boolean = false; + + + @ConfigProperty({ + tags: { + name: $localize`Titles`, + priority: ConfigPriority.advanced, + githubIssue: 801, + } as TAGS, + description: $localize`Set these to customize the text (caption, location, etc.) in the lightbox that are always visible over the photo (not in the info panel).` + }) + Titles: ClientLightboxTitleConfig = new ClientLightboxTitleConfig(); } @SubConfigClass({tags: {client: true}, softReadonly: true}) @@ -1007,17 +1085,17 @@ export class ThemesConfig { }) availableThemes: ThemeConfig[] = [ new ThemeConfig( - 'classic', - ':root nav.navbar {\n' + - '--bs-navbar-color: rgba(255, 255, 255, 0.55);\n' + - '--bs-navbar-hover-color: rgba(255, 255, 255, 0.75);\n' + - '--bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);\n' + - '--bs-navbar-active-color: #fff;\n' + - '--bs-navbar-brand-color: #fff;\n' + - '--bs-navbar-brand-hover-color: #fff;\n' + - '--bs-bg-opacity: 1;\n' + - 'background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important;\n' + - '}' + 'classic', + ':root nav.navbar {\n' + + '--bs-navbar-color: rgba(255, 255, 255, 0.55);\n' + + '--bs-navbar-hover-color: rgba(255, 255, 255, 0.75);\n' + + '--bs-navbar-disabled-color: rgba(255, 255, 255, 0.25);\n' + + '--bs-navbar-active-color: #fff;\n' + + '--bs-navbar-brand-color: #fff;\n' + + '--bs-navbar-brand-hover-color: #fff;\n' + + '--bs-bg-opacity: 1;\n' + + 'background-color: rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important;\n' + + '}' )]; } @@ -1166,7 +1244,7 @@ export class ClientPhotoConvertingConfig { name: $localize`Load full resolution image on zoom.`, priority: ConfigPriority.advanced, uiDisabled: (sc: ClientPhotoConvertingConfig) => - !sc.enabled + !sc.enabled }, description: $localize`Enables loading the full resolution image on zoom in the ligthbox (preview).`, }) @@ -1391,7 +1469,7 @@ export class ClientServiceConfig { } as TAGS, description: $localize`Sets the icon of the app`, }) - // source: https://icons.getbootstrap.com/ + // source: https://icons.getbootstrap.com/ svgIcon: SVGIconConfig = new SVGIconConfig(`0 0 512 512`, ''); } diff --git a/src/frontend/app/app.module.ts b/src/frontend/app/app.module.ts index 51e21661..3ae1946f 100644 --- a/src/frontend/app/app.module.ts +++ b/src/frontend/app/app.module.ts @@ -386,6 +386,7 @@ Marker.prototype.options.icon = MarkerFactory.defIcon; CookieService, GPXFilesFilterPipe, MDFilesFilterPipe, + FileSizePipe, DatePipe ], bootstrap: [AppComponent], diff --git a/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.css b/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.css index f01b431a..98fbb927 100644 --- a/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.css +++ b/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.css @@ -98,9 +98,8 @@ vertical-align: top; } -.controls-caption { +.controls-title { opacity: 0.7; - top: 0; position: absolute; height: initial; text-align: left; @@ -110,6 +109,18 @@ border-radius: 5px !important; } +.controls-subtitle-text{ + font-size: .6em; +} + +.controls-top-left-title { + top: 0; +} + +.controls-bottom-left-title { + bottom: 2rem; +} + .controls-zoom { bottom: 0; @@ -291,7 +302,7 @@ input[type="range"].zoom-progress::-moz-range-track { opacity: 0.0; } -.controls-caption.controls-nodim { +.controls-title.controls-nodim { opacity: 0.7; } diff --git a/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.html b/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.html index 197d8732..8cc1fb96 100644 --- a/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.html +++ b/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.html @@ -1,14 +1,19 @@
-
{{Title}}
+ *ngIf="TopLeftTitle || TopLeftSubtitle"> +
{{ TopLeftTitle }}
+ +
{{ TopLeftSubtitle }}
+
+
- +
-
@@ -32,7 +37,7 @@ class="border-0 highlight control-button" data-bs-auto-close="outside" aria-controls="dropdown-basic"> - +
{{face.name}} + >{{ face.name }}
@@ -179,6 +184,14 @@ #canvas width="55px" height="55px"> +
+
{{ BottomLeftTitle }}
+ +
{{ BottomLeftSubtitle }}
+
+
@@ -194,7 +207,6 @@
-
diff --git a/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.ts b/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.ts index 97ccbe05..441ed90c 100644 --- a/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.ts +++ b/src/frontend/app/ui/gallery/lightbox/controls/controls.lightbox.gallery.component.ts @@ -11,12 +11,17 @@ import {SearchQueryTypes, TextSearch, TextSearchQueryMatchTypes,} from '../../.. import {AuthenticationService} from '../../../../model/network/authentication.service'; import {LightboxService} from '../lightbox.service'; import {GalleryCacheService} from '../../cache.gallery.service'; +import {Utils} from '../../../../../../common/Utils'; +import {FileSizePipe} from '../../../../pipes/FileSizePipe'; +import {DatePipe} from '@angular/common'; +import {LightBoxTitleTexts} from '../../../../../../common/config/public/ClientConfig'; export enum PlayBackStates { Paused = 1, Play = 2, } + @Component({ selector: 'app-lightbox-controls', styleUrls: ['./controls.lightbox.gallery.component.css', './inputrange.css'], @@ -61,10 +66,12 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { private prevZoom = 1; constructor( - public lightboxService: LightboxService, - public fullScreenService: FullScreenService, - private authService: AuthenticationService, - private cacheService: GalleryCacheService + public lightboxService: LightboxService, + public fullScreenService: FullScreenService, + private authService: AuthenticationService, + private cacheService: GalleryCacheService, + private fileSizePipe: FileSizePipe, + private datePipe: DatePipe ) { this.searchEnabled = this.authService.canSearch(); } @@ -97,13 +104,6 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { this.checkZoomAndDrag(); } - get Title(): string { - if (!this.activePhoto) { - return null; - } - return (this.activePhoto.gridMedia.media as PhotoDTO).metadata.caption; - } - public containerWidth(): void { return this.root.nativeElement.width; } @@ -271,14 +271,14 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { private showNextMedia = () => { if (this.mediaElement.imageLoadFinished.this === false || - this.mediaElement.imageLoadFinished.next === false) { + this.mediaElement.imageLoadFinished.next === false) { return; } // do not skip video if its playing if ( - this.activePhoto && - this.activePhoto.gridMedia.isVideo() && - !this.mediaElement.Paused + this.activePhoto && + this.activePhoto.gridMedia.isVideo() && + !this.mediaElement.Paused ) { return; } @@ -290,8 +290,8 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { // Video is a special snowflake. It won't go to next media if a video is playing if (!(this.activePhoto && - this.activePhoto.gridMedia.isVideo() && - !this.mediaElement.Paused)) { + this.activePhoto.gridMedia.isVideo() && + !this.mediaElement.Paused)) { p = (t % (this.selectedSlideshowSpeed * 10)) / this.selectedSlideshowSpeed / 10; // ticks every 100 ms } @@ -322,12 +322,12 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { this.pause(); this.drawSliderProgress(0); this.timerSub = interval(100) - .pipe(filter((t) => { - this.drawSliderProgress(t); - return t % (this.selectedSlideshowSpeed * 10) === 0; // ticks every 100 ms - })) - .pipe(skip(1)) // do not skip to next photo right away - .subscribe(this.showNextMedia); + .pipe(filter((t) => { + this.drawSliderProgress(t); + return t % (this.selectedSlideshowSpeed * 10) === 0; // ticks every 100 ms + })) + .pipe(skip(1)) // do not skip to next photo right away + .subscribe(this.showNextMedia); this.playBackState = PlayBackStates.Play; } @@ -381,7 +381,7 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { } const photoAspect = MediaDTOUtils.calcAspectRatio( - this.activePhoto.gridMedia.media + this.activePhoto.gridMedia.media ); const widthFilled = photoAspect > this.photoFrameDim.aspect; const divWidth = this.photoFrameDim.width; @@ -442,7 +442,7 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { } const photoAspect = MediaDTOUtils.calcAspectRatio( - this.activePhoto.gridMedia.media + this.activePhoto.gridMedia.media ); if (photoAspect < this.photoFrameDim.aspect) { @@ -459,5 +459,70 @@ export class ControlsLightboxComponent implements OnDestroy, OnInit, OnChanges { this.nextPhoto.emit(); } + + getText(type: LightBoxTitleTexts): string { + if (!this.activePhoto?.gridMedia?.media) { + return null; + } + const m = this.activePhoto.gridMedia.media as PhotoDTO; + switch (type) { + case LightBoxTitleTexts.file: + return Utils.concatUrls( + m.directory.path, + m.directory.name, + m.name + ); + case LightBoxTitleTexts.resolution: + return `${m.metadata.size.width}x${m.metadata.size.height}`; + case LightBoxTitleTexts.size: + return this.fileSizePipe.transform(m.metadata.fileSize); + case LightBoxTitleTexts.title: + return m.metadata.title; + case LightBoxTitleTexts.caption: + return m.metadata.caption; + case LightBoxTitleTexts.keywords: + return m.metadata.keywords.join(', '); + case LightBoxTitleTexts.persons: + return m.metadata.faces?.map(f => f.name)?.join(', '); + case LightBoxTitleTexts.date: + return this.datePipe.transform(m.metadata.creationDate, 'longDate'); + case LightBoxTitleTexts.location: + return ( + m.metadata.positionData?.city || + m.metadata.positionData?.state || + m.metadata.positionData?.country || '' + ).trim(); + case LightBoxTitleTexts.camera: + return m.metadata.cameraData?.model; + case LightBoxTitleTexts.lens: + return m.metadata.cameraData?.lens; + case LightBoxTitleTexts.iso: + return m.metadata.cameraData?.ISO.toString(); + case LightBoxTitleTexts.fstop: + if (m.metadata.cameraData?.fStop > 1) { + return m.metadata.cameraData?.fStop.toString(); + } + return '1/' + Math.round(1 / m.metadata.cameraData?.fStop); + case LightBoxTitleTexts.focal_length: + return m.metadata.cameraData?.focalLength.toString(); + } + return null; + } + + get TopLeftTitle(): string { + return this.getText(Config.Gallery.Lightbox.Titles.topLeftTitle); + } + + get TopLeftSubtitle(): string { + return this.getText(Config.Gallery.Lightbox.Titles.topLeftSubtitle); + } + + get BottomLeftTitle(): string { + return this.getText(Config.Gallery.Lightbox.Titles.bottomLeftTitle); + } + get BottomLeftSubtitle(): string { + return this.getText(Config.Gallery.Lightbox.Titles.bottomLeftSubtitle); + } + }