You've already forked pigallery2
mirror of
https://github.com/bpatrik/pigallery2.git
synced 2025-12-07 23:23:49 +02:00
Create wakelock to prevent dimming. fixes #1044
This commit is contained in:
@@ -3,6 +3,7 @@ import {GalleryPhotoComponent} from '../grid/photo/photo.grid.gallery.component'
|
||||
import {Dimension, DimensionUtils} from '../../../model/IRenderable';
|
||||
import {FullScreenService} from '../fullscreen.service';
|
||||
import {OverlayService} from '../overlay.service';
|
||||
import {WakeLockService} from '../wakelock.service';
|
||||
import {animate, AnimationBuilder, AnimationPlayer, style,} from '@angular/animations';
|
||||
import {GalleryLightboxMediaComponent} from './media/media.lightbox.gallery.component';
|
||||
import {Subscription} from 'rxjs';
|
||||
@@ -16,9 +17,9 @@ import {ControlsLightboxComponent} from './controls/controls.lightbox.gallery.co
|
||||
import {SupportedFormats} from '../../../../../common/SupportedFormats';
|
||||
import {GridMedia} from '../grid/GridMedia';
|
||||
import {PiTitleService} from '../../../model/pi-title.service';
|
||||
import { NgIf, NgFor } from '@angular/common';
|
||||
import { NgIconComponent } from '@ng-icons/core';
|
||||
import { InfoPanelLightboxComponent } from './infopanel/info-panel.lightbox.gallery.component';
|
||||
import {NgFor, NgIf} from '@angular/common';
|
||||
import {NgIconComponent} from '@ng-icons/core';
|
||||
import {InfoPanelLightboxComponent} from './infopanel/info-panel.lightbox.gallery.component';
|
||||
|
||||
export enum LightboxStates {
|
||||
Open = 1,
|
||||
@@ -28,17 +29,17 @@ export enum LightboxStates {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-gallery-lightbox',
|
||||
styleUrls: ['./lightbox.gallery.component.css'],
|
||||
templateUrl: './lightbox.gallery.component.html',
|
||||
imports: [
|
||||
GalleryLightboxMediaComponent,
|
||||
NgIf,
|
||||
NgIconComponent,
|
||||
NgFor,
|
||||
ControlsLightboxComponent,
|
||||
InfoPanelLightboxComponent,
|
||||
]
|
||||
selector: 'app-gallery-lightbox',
|
||||
styleUrls: ['./lightbox.gallery.component.css'],
|
||||
templateUrl: './lightbox.gallery.component.html',
|
||||
imports: [
|
||||
GalleryLightboxMediaComponent,
|
||||
NgIf,
|
||||
NgIconComponent,
|
||||
NgFor,
|
||||
ControlsLightboxComponent,
|
||||
InfoPanelLightboxComponent,
|
||||
]
|
||||
})
|
||||
export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
@ViewChild('photo', {static: true})
|
||||
@@ -53,11 +54,12 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
public status: LightboxStates = LightboxStates.Closed;
|
||||
public infoPanelVisible = false;
|
||||
public infoPanelWidth = 0;
|
||||
private infoPanelMaxWidth = 400;
|
||||
public animating = false;
|
||||
public photoFrameDim = {width: 1, height: 1, aspect: 1};
|
||||
public videoSourceError = false;
|
||||
public transcodeNeedVideos = SupportedFormats.TranscodeNeed.Videos;
|
||||
slideShowRunning: boolean;
|
||||
private infoPanelMaxWidth = 400;
|
||||
private startPhotoDimension: Dimension = {
|
||||
top: 0,
|
||||
left: 0,
|
||||
@@ -76,7 +78,6 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
photosChange: null,
|
||||
route: null,
|
||||
};
|
||||
slideShowRunning: boolean;
|
||||
|
||||
constructor(
|
||||
public fullScreenService: FullScreenService,
|
||||
@@ -86,7 +87,8 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
private router: Router,
|
||||
private queryService: QueryService,
|
||||
private route: ActivatedRoute,
|
||||
private piTitleService: PiTitleService
|
||||
private piTitleService: PiTitleService,
|
||||
private wakeLockService: WakeLockService
|
||||
) {
|
||||
}
|
||||
|
||||
@@ -97,6 +99,13 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
return (this.activePhoto.gridMedia.media as PhotoDTO).metadata.caption;
|
||||
}
|
||||
|
||||
get NexGridMedia(): GridMedia {
|
||||
if (this.activePhotoId + 1 < this.gridPhotoQL?.length) {
|
||||
return this.gridPhotoQL.get(this.activePhotoId + 1)?.gridMedia;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public toggleFullscreen(): void {
|
||||
if (this.fullScreenService.isFullScreenEnabled()) {
|
||||
this.fullScreenService.exitFullScreen();
|
||||
@@ -105,13 +114,6 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
}
|
||||
|
||||
private updateInfoPanelWidth() {
|
||||
this.infoPanelMaxWidth = Math.min(400, Math.ceil(window.innerWidth + 1));
|
||||
if ((window.innerWidth - this.infoPanelMaxWidth) < this.infoPanelMaxWidth * 0.3) {
|
||||
this.infoPanelMaxWidth = Math.ceil(window.innerWidth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
ngOnInit(): void {
|
||||
this.infoPanelMaxWidth = 1000;
|
||||
this.updatePhotoFrameDim();
|
||||
@@ -146,23 +148,8 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
);
|
||||
}
|
||||
|
||||
private runSlideShow() {
|
||||
if (!this.activePhoto && this.gridPhotoQL?.length > 0) {
|
||||
this.navigateToPhoto(0);
|
||||
}
|
||||
this.slideShowRunning = true;
|
||||
this.controls?.runSlideShow();
|
||||
}
|
||||
|
||||
private stopSlideShow() {
|
||||
this.slideShowRunning = false;
|
||||
this.controls?.stopSlideShow();
|
||||
}
|
||||
|
||||
ngOnDestroy(): void {
|
||||
if (this.controls) {
|
||||
this.controls.stopSlideShow();
|
||||
}
|
||||
this.stopSlideShow();
|
||||
if (this.subscription.photosChange != null) {
|
||||
this.subscription.photosChange.unsubscribe();
|
||||
}
|
||||
@@ -253,9 +240,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
}
|
||||
|
||||
public prevImage(): void {
|
||||
if (this.controls) {
|
||||
this.controls.stopSlideShow();
|
||||
}
|
||||
this.stopSlideShow();
|
||||
if (this.activePhotoId > 0) {
|
||||
this.navigateToPhoto(this.activePhotoId - 1);
|
||||
}
|
||||
@@ -433,6 +418,39 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
this.videoSourceError = true;
|
||||
}
|
||||
|
||||
togglePlayback(value: boolean): void {
|
||||
if (this.slideShowRunning === value) {
|
||||
return;
|
||||
}
|
||||
this.slideShowRunning = value;
|
||||
// resets query. This side effect is to assign playback = true to the url
|
||||
this.navigateToPhoto(this.activePhotoId);
|
||||
}
|
||||
|
||||
private updateInfoPanelWidth() {
|
||||
this.infoPanelMaxWidth = Math.min(400, Math.ceil(window.innerWidth + 1));
|
||||
if ((window.innerWidth - this.infoPanelMaxWidth) < this.infoPanelMaxWidth * 0.3) {
|
||||
this.infoPanelMaxWidth = Math.ceil(window.innerWidth + 1);
|
||||
}
|
||||
}
|
||||
|
||||
private runSlideShow() {
|
||||
if (!this.activePhoto && this.gridPhotoQL?.length > 0) {
|
||||
this.navigateToPhoto(0);
|
||||
}
|
||||
this.slideShowRunning = true;
|
||||
this.controls?.runSlideShow();
|
||||
// Request wake lock to prevent screen dimming during slideshow
|
||||
this.wakeLockService.requestWakeLock().catch(console.error);
|
||||
}
|
||||
|
||||
private stopSlideShow() {
|
||||
this.slideShowRunning = false;
|
||||
this.controls?.stopSlideShow();
|
||||
// Release wake lock when slideshow stops
|
||||
this.wakeLockService.releaseWakeLock().catch(console.error);
|
||||
}
|
||||
|
||||
private updatePhotoFrameDim = (): void => {
|
||||
this.photoFrameDim = {
|
||||
width: Math.max(
|
||||
@@ -474,9 +492,7 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
this.status = LightboxStates.Closing;
|
||||
this.fullScreenService.exitFullScreen();
|
||||
|
||||
if (this.controls) {
|
||||
this.controls.stopSlideShow();
|
||||
}
|
||||
this.stopSlideShow();
|
||||
|
||||
this.animating = true;
|
||||
const lightboxDimension = this.activePhoto.getDimension();
|
||||
@@ -565,21 +581,5 @@ export class GalleryLightboxComponent implements OnDestroy, OnInit {
|
||||
|
||||
return {top, left, width, height} as Dimension;
|
||||
}
|
||||
|
||||
get NexGridMedia(): GridMedia {
|
||||
if (this.activePhotoId + 1 < this.gridPhotoQL?.length) {
|
||||
return this.gridPhotoQL.get(this.activePhotoId + 1)?.gridMedia;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
togglePlayback(value: boolean): void {
|
||||
if (this.slideShowRunning === value) {
|
||||
return;
|
||||
}
|
||||
this.slideShowRunning = value;
|
||||
// resets query. This side effect is to assign playback = true to the url
|
||||
this.navigateToPhoto(this.activePhotoId);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
63
src/frontend/app/ui/gallery/wakelock.service.ts
Normal file
63
src/frontend/app/ui/gallery/wakelock.service.ts
Normal file
@@ -0,0 +1,63 @@
|
||||
import {Injectable} from '@angular/core';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class WakeLockService {
|
||||
private wakeLock: WakeLockSentinel | null = null;
|
||||
|
||||
/**
|
||||
* Request a wake lock to prevent the screen from dimming or turning off
|
||||
*/
|
||||
async requestWakeLock(): Promise<void> {
|
||||
if (!this.isSupported()) {
|
||||
console.warn('Wake Lock API is not supported in this browser');
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.wakeLock) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
this.wakeLock = await navigator.wakeLock.request('screen');
|
||||
|
||||
// Listen for wake lock release
|
||||
this.wakeLock.addEventListener('release', () => {
|
||||
this.wakeLock = null;
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Failed to request wake lock:', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Release the current wake lock
|
||||
*/
|
||||
async releaseWakeLock(): Promise<void> {
|
||||
if (!this.wakeLock) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await this.wakeLock.release();
|
||||
this.wakeLock = null;
|
||||
} catch (err) {
|
||||
console.error('Failed to release wake lock:', err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if wake lock is currently active
|
||||
*/
|
||||
isWakeLockActive(): boolean {
|
||||
return this.wakeLock !== null && !this.wakeLock.released;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Wake Lock API is supported
|
||||
*/
|
||||
isSupported(): boolean {
|
||||
return 'wakeLock' in navigator;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user