mirror of
https://github.com/jellyfin/jellyfin-web.git
synced 2026-09-03 03:50:02 +03:00
Merge pull request #8302 from dkanada/osd-timeout
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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' />
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user