Merge pull request #8302 from dkanada/osd-timeout

This commit is contained in:
Bill Thornton
2026-08-03 18:00:09 -04:00
committed by GitHub
7 changed files with 60 additions and 34 deletions
+3 -8
View File
@@ -16,6 +16,9 @@
padding: 0 0.8vw;
background-color: var(--jf-palette-AppBar-defaultBg);
pointer-events: auto;
transition: all 200ms linear;
// force WebKit to promote the element onto its own compositor layer for opacity on iOS
transform: translateZ(0);
}
// TODO disable landscape on mobile devices
@@ -29,14 +32,6 @@
flex: 1;
}
.bookOsdTop {
padding-top: env(safe-area-inset-top);
}
.bookOsdBottom {
padding-bottom: env(safe-area-inset-bottom);
}
.bookOsdTitle {
font-size: 1.1rem;
margin-left: 0.35rem;
+38 -7
View File
@@ -1,4 +1,4 @@
import React, { type FC, useCallback, useEffect, useState } from 'react';
import React, { type FC, useCallback, useEffect, useRef, useState } from 'react';
import './BookOsd.scss';
import IconButton from '../../../elements/emby-button/IconButton';
@@ -40,10 +40,17 @@ const BookOsd: FC<BookOsdProps> = ({
onToggleFullscreen
}) => {
const settings = userSettings.getComicsPlayerSettings(item.Id!) as ComicsPlayerSettings;
const timeout = useRef<ReturnType<typeof setTimeout>>();
const [direction, setDirection] = useState(settings.langDir === 'rtl');
const [layout, setLayout] = useState(settings.pagesPerView === 2);
const [fullscreen, setFullscreen] = useState(false);
const [visible, setVisible] = useState(true);
const scheduleHide = useCallback(() => {
clearTimeout(timeout.current);
timeout.current = setTimeout(() => setVisible(false), 2000);
}, []);
const updateFullscreen = useCallback((state: boolean) => {
if (Screenfull.isEnabled && Screenfull.isFullscreen !== state) {
@@ -53,10 +60,6 @@ const BookOsd: FC<BookOsdProps> = ({
}
}, []);
useEffect(() => {
return () => updateFullscreen(false);
}, [updateFullscreen]);
const onClickDirection = useCallback(() => {
onToggleDirection?.();
setDirection(state => !state);
@@ -73,14 +76,42 @@ const BookOsd: FC<BookOsdProps> = ({
setFullscreen(state => !state);
}, [onToggleFullscreen, updateFullscreen, fullscreen]);
useEffect(() => {
const onPointerMove = (event: PointerEvent) => {
if (event.pointerType !== 'mouse') return;
scheduleHide();
setVisible(true);
};
const onClick = (event: MouseEvent) => {
// apply this before the BookOsd check so IconButton clicks will reset the timer
scheduleHide();
if ((event.target as Element | null)?.closest?.('.bookOsdRow')) return;
setVisible(state => !state);
};
scheduleHide();
document.addEventListener('pointermove', onPointerMove);
document.addEventListener('click', onClick);
return () => {
clearTimeout(timeout.current);
updateFullscreen(false);
document.removeEventListener('pointermove', onPointerMove);
document.removeEventListener('click', onClick);
};
}, [scheduleHide, updateFullscreen]);
return (
<div className='bookOsd'>
<div className='bookOsdRow bookOsdTop'>
<div className='bookOsdRow' style={{ paddingTop: 'env(safe-area-inset-top)', ...(!visible && { opacity: 0, pointerEvents: 'none' }) }}>
<IconButton onClick={onExit} icon='arrow_back' title={globalize.translate('ButtonBack')} />
<span className='bookOsdTitle'>{item.Name}</span>
</div>
<div className='bookOsdRow bookOsdBottom'>
<div className='bookOsdRow' style={{ paddingBottom: 'env(safe-area-inset-bottom)', ...(!visible && { opacity: 0, pointerEvents: 'none' }) }}>
<IconButton onClick={onPrevious} icon='navigate_before' title={globalize.translate('Previous')} />
<IconButton onClick={onNext} icon='navigate_next' title={globalize.translate('Next')} />
<div className='bookOsdSpacer' />
+8
View File
@@ -187,6 +187,7 @@ export class BookPlayer {
document.addEventListener('keydown', this.onWindowKeyDown);
this.rendition?.on('keydown', this.onWindowKeyDown);
this.rendition?.on('rendered', (e, i) => this.forwardEvents(i.document));
if (browser.safari) {
this.addSwipeGestures(document.querySelector('#bookPlayerContainer'));
@@ -207,6 +208,13 @@ export class BookPlayer {
this.touchHelper?.destroy();
}
// ensure certain iframe events are forwarded to the document for BookOsd visibility listeners
forwardEvents(iframe) {
// eslint-disable-next-line compat/compat
iframe.addEventListener('pointermove', (event) => document.dispatchEvent(new PointerEvent(event.type, event)));
iframe.addEventListener('click', (event) => document.dispatchEvent(new MouseEvent(event.type, event)));
}
openTableOfContents() {
if (this.loaded) {
this.tocElement = new TableOfContents(this);
+2 -6
View File
@@ -20,12 +20,8 @@
inset: 0;
z-index: 1000;
width: 100%;
/* stylelint-disable declaration-block-no-duplicate-properties */
top: 5vh;
height: 90vh;
top: calc(5vh + env(safe-area-inset-top));
height: calc(90vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
/* stylelint-enable declaration-block-no-duplicate-properties */
top: env(safe-area-inset-top);
height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
#dialogToc {
+4 -6
View File
@@ -3,12 +3,10 @@
.slideshowSwiperContainer {
position: relative;
/* stylelint-disable declaration-block-no-duplicate-properties */
top: 5vh;
height: 90vh;
top: calc(5vh + env(safe-area-inset-top));
height: calc(90vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
/* stylelint-enable declaration-block-no-duplicate-properties */
/* stylelint-disable-next-line declaration-block-no-duplicate-properties */
height: 100%;
top: env(safe-area-inset-top);
height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
.slider-zoom-container {
+1 -1
View File
@@ -294,7 +294,7 @@ export class PdfPlayer {
const devicePixelRatio = window.devicePixelRatio || 1;
this.book.getPage(number).then(page => {
const original = page.getViewport({ scale: 1 });
const scale = Math.min((window.innerHeight / original.height * 0.9), (window.innerWidth / original.width));
const scale = Math.min((window.innerHeight / original.height), (window.innerWidth / original.width));
const viewport = page.getViewport({ scale: scale * devicePixelRatio });
canvas.width = viewport.width;
+4 -6
View File
@@ -2,12 +2,10 @@
position: relative;
display: grid;
place-items: center;
/* stylelint-disable declaration-block-no-duplicate-properties */
top: 5vh;
height: 90vh;
top: calc(5vh + env(safe-area-inset-top));
height: calc(90vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
/* stylelint-enable declaration-block-no-duplicate-properties */
/* stylelint-disable-next-line declaration-block-no-duplicate-properties */
height: 100%;
top: env(safe-area-inset-top);
height: calc(100vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
}
#pdfPlayer {