Skip to content

Commit b7e4dd9

Browse files
committed
unify fullscreen support across all book players
1 parent 11dfed9 commit b7e4dd9

10 files changed

Lines changed: 62 additions & 44 deletions

File tree

src/apps/legacy/features/playback/utils/playbackSubscriber.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export interface PlaybackSubscriber {
2121
onPlayerChange?(e: Event, player: PlayerPlugin, target: PlayTarget, previousPlayer: PlayerPlugin): void
2222
onPromptSkip?(e: Event, mediaSegment: MediaSegmentDto): void
2323
onPlayerError?(e: Event, error: PlayerError): void
24-
onPlayerFullscreenChange?(e: Event): void
24+
onPlayerFullscreenChange?(e: Event, fullscreen: boolean): void
2525
onPlayerItemStarted?(e: Event, item?: BaseItemDto, mediaSource?: MediaSourceInfo): void
2626
onPlayerItemStopped?(e: Event, info: ManagedPlayerStopInfo): void
2727
onPlayerMediaStreamsChange?(e: Event): void

src/components/playback/playbackmanager.js

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,12 +52,12 @@ function supportsPhysicalVolumeControl(player) {
5252
function bindToFullscreenChange(player) {
5353
if (Screenfull.isEnabled) {
5454
Screenfull.on('change', function () {
55-
Events.trigger(player, 'fullscreenchange');
55+
Events.trigger(player, 'fullscreenchange', [Screenfull.isFullscreen]);
5656
});
5757
} else {
5858
// iOS Safari
5959
document.addEventListener('webkitfullscreenchange', function () {
60-
Events.trigger(player, 'fullscreenchange');
60+
Events.trigger(player, 'fullscreenchange', [document.webkitIsFullScreen]);
6161
}, false);
6262
}
6363
}
@@ -2266,7 +2266,9 @@ export class PlaybackManager {
22662266

22672267
options.items = items;
22682268

2269-
return player.play(options);
2269+
return player.play(options).then(() => {
2270+
onPlaybackStarted(player, options, player.streamInfo, player.streamInfo?.mediaSource);
2271+
});
22702272
}
22712273

22722274
const getAdditionalParts = async (items, mediaSourceId, startIndex) => {

src/global.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ export declare global {
1616
'viewshow': CustomEvent;
1717
}
1818

19+
interface Document {
20+
webkitIsFullScreen?: boolean;
21+
webkitCancelFullscreen?(): void;
22+
webkitEnterFullscreen?(): void;
23+
}
24+
1925
const __COMMIT_SHA__: string;
2026
const __JF_BUILD_VERSION__: string;
2127
const __PACKAGE_JSON_NAME__: string;

src/plugins/bookPlayer/BookOsd/BookOsd.tsx

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
import React, { type FC, useCallback, useState } from 'react';
1+
import React, { type FC, useCallback, useEffect, useState } from 'react';
22

33
import './BookOsd.scss';
44
import IconButton from '../../../elements/emby-button/IconButton';
55
import globalize from 'lib/globalize';
66
import * as userSettings from '../../../scripts/settings/userSettings';
77
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
8+
import Screenfull from 'screenfull';
89

910
interface BookOsdProps {
1011
item: BaseItemDto;
@@ -17,7 +18,7 @@ interface BookOsdProps {
1718
onIncreaseFontSize?: () => void;
1819
onToggleDirection?: () => void;
1920
onToggleLayout?: () => void;
20-
onToggleFullscreen?: () => void;
21+
onToggleFullscreen: () => void;
2122
}
2223

2324
interface ComicsPlayerSettings {
@@ -44,6 +45,20 @@ const BookOsd: FC<BookOsdProps> = ({
4445
const [layout, setLayout] = useState(settings.pagesPerView === 2);
4546
const [fullscreen, setFullscreen] = useState(false);
4647

48+
const updateFullscreen = useCallback((state: boolean) => {
49+
if (Screenfull.isEnabled) {
50+
void Screenfull.toggle();
51+
} else if (window.NativeShell) {
52+
state ? window.NativeShell.enableFullscreen() : window.NativeShell.disableFullscreen();
53+
} else if (document.webkitEnterFullscreen || document.webkitCancelFullscreen) {
54+
state ? document.webkitEnterFullscreen?.() : document.webkitCancelFullscreen?.();
55+
}
56+
}, []);
57+
58+
useEffect(() => {
59+
return () => updateFullscreen(false);
60+
}, [updateFullscreen]);
61+
4762
const onClickDirection = useCallback(() => {
4863
onToggleDirection?.();
4964
setDirection(state => !state);
@@ -55,9 +70,10 @@ const BookOsd: FC<BookOsdProps> = ({
5570
}, [onToggleLayout]);
5671

5772
const onClickFullscreen = useCallback(() => {
73+
updateFullscreen(!fullscreen);
5874
onToggleFullscreen?.();
5975
setFullscreen(state => !state);
60-
}, [onToggleFullscreen]);
76+
}, [onToggleFullscreen, updateFullscreen, fullscreen]);
6177

6278
return (
6379
<div className='bookOsd'>
@@ -119,13 +135,11 @@ const BookOsd: FC<BookOsdProps> = ({
119135
/>
120136
)}
121137

122-
{onToggleFullscreen && (
123-
<IconButton
124-
onClick={onClickFullscreen}
125-
icon={fullscreen ? 'fullscreen_exit' : 'fullscreen'}
126-
title={globalize.translate(fullscreen ? 'ExitFullscreen' : 'Fullscreen')}
127-
/>
128-
)}
138+
<IconButton
139+
onClick={onClickFullscreen}
140+
icon={fullscreen ? 'fullscreen_exit' : 'fullscreen'}
141+
title={globalize.translate(fullscreen ? 'ExitFullscreen' : 'Fullscreen')}
142+
/>
129143
</div>
130144
</div>
131145
);

src/plugins/bookPlayer/plugin.js

Lines changed: 2 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api';
2-
import Screenfull from 'screenfull';
32

43
import { PluginType } from 'constants/pluginType';
54
import { ServerConnections } from 'lib/jellyfin-apiclient';
@@ -53,7 +52,6 @@ export class BookPlayer {
5352
this.onWindowKeyDown = this.onWindowKeyDown.bind(this);
5453
this.addSwipeGestures = this.addSwipeGestures.bind(this);
5554
this.toggleFullscreen = this.toggleFullscreen.bind(this);
56-
this.fullscreen = false;
5755
}
5856

5957
play(options) {
@@ -94,10 +92,6 @@ export class BookPlayer {
9492
rendition.destroy();
9593
}
9694

97-
if (this.fullscreen) {
98-
this.toggleFullscreen();
99-
}
100-
10195
// hide loader in case player was not fully loaded yet
10296
loading.hide();
10397
this.cancellationToken = true;
@@ -219,18 +213,8 @@ export class BookPlayer {
219213
toggleFullscreen() {
220214
const player = document.querySelector('#bookPlayerContainer');
221215

222-
player.classList.toggle('fullscreen', !this.fullscreen);
223-
if (Screenfull.isEnabled) {
224-
Screenfull.toggle();
225-
} else if (window.NativeShell) {
226-
this.fullscreen ? window.NativeShell.disableFullscreen() : window.NativeShell.enableFullscreen();
227-
}
228-
229216
// needs to be executed with a slight delay to give NativeShell time to process the request
230217
setTimeout(() => this.rendition.resize(player.clientWidth, player.clientHeight), 200);
231-
232-
// required for mobile apps without browser fullscreen support
233-
this.fullscreen = !this.fullscreen;
234218
}
235219

236220
rotateTheme() {
@@ -305,7 +289,7 @@ export class BookPlayer {
305289
onRotateTheme: this.rotateTheme,
306290
onDecreaseFontSize: this.decreaseFontSize,
307291
onIncreaseFontSize: this.increaseFontSize,
308-
onToggleFullscreen: Screenfull.isEnabled || window.NativeShell ? this.toggleFullscreen : null
292+
onToggleFullscreen: this.toggleFullscreen
309293
}, elem.querySelector('#bookOsdMount'));
310294

311295
return elem;
@@ -340,7 +324,7 @@ export class BookPlayer {
340324
flow: 'paginated'
341325
});
342326

343-
this.currentSrc = downloadHref;
327+
this.currentSrc = () => downloadHref;
344328
this.rendition = rendition;
345329

346330
rendition.themes.register('default', THEMES[this.theme]);

src/plugins/bookPlayer/style.scss

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,6 @@
2020
inset: 0;
2121
z-index: 1000;
2222
width: 100%;
23-
top: 5vh;
24-
height: 90vh;
25-
}
26-
27-
#bookPlayerContainer.fullscreen {
2823
top: calc(5vh + env(safe-area-inset-top));
2924
height: calc(90vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
3025
}

src/plugins/comicsPlayer/plugin.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export class ComicsPlayer {
3636

3737
this.onDialogClosed = this.onDialogClosed.bind(this);
3838
this.onWindowKeyDown = this.onWindowKeyDown.bind(this);
39+
this.toggleFullscreen = this.toggleFullscreen.bind(this);
3940
}
4041

4142
play(options) {
@@ -192,6 +193,10 @@ export class ComicsPlayer {
192193
document.removeEventListener('keydown', this.onWindowKeyDown);
193194
}
194195

196+
toggleFullscreen() {
197+
setTimeout(() => this.swiperInstance?.update(), 200);
198+
}
199+
195200
createMediaElement(options) {
196201
let elem = this.mediaElement;
197202
if (elem) {
@@ -226,7 +231,8 @@ export class ComicsPlayer {
226231
onPrevious: this.previous,
227232
onNext: this.next,
228233
onToggleDirection: this.onDirChanged,
229-
onToggleLayout: this.onViewChanged
234+
onToggleLayout: this.onViewChanged,
235+
onToggleFullscreen: this.toggleFullscreen
230236
}, elem.querySelector('#bookOsdMount'));
231237

232238
this.bindEvents();
@@ -271,6 +277,7 @@ export class ComicsPlayer {
271277

272278
this.pageCount = this.archiveSource.urls.length;
273279
this.currentPage = options.startPositionTicks / 10000 || 0;
280+
this.currentSrc = () => this.currentPage;
274281

275282
this.swiperInstance = new Swiper(elem.querySelector('.slideshowSwiperContainer'), {
276283
direction: 'horizontal',

src/plugins/comicsPlayer/style.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33

44
.slideshowSwiperContainer {
55
position: relative;
6-
top: 5vh;
7-
height: 90vh;
6+
top: calc(5vh + env(safe-area-inset-top));
7+
height: calc(90vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
88
}
99

1010
.slider-zoom-container {

src/plugins/pdfPlayer/plugin.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export class PdfPlayer {
2828
this.onDialogClosed = this.onDialogClosed.bind(this);
2929
this.onWindowKeyDown = this.onWindowKeyDown.bind(this);
3030
this.onTouchStart = this.onTouchStart.bind(this);
31+
this.toggleFullscreen = this.toggleFullscreen.bind(this);
3132
}
3233

3334
play(options) {
@@ -150,6 +151,10 @@ export class PdfPlayer {
150151
document.querySelector('#container')?.removeEventListener('touchstart', this.onTouchStart);
151152
}
152153

154+
toggleFullscreen() {
155+
setTimeout(() => this.loadPage(this.progress + 1), 200);
156+
}
157+
153158
createMediaElement(options) {
154159
let elem = this.mediaElement;
155160
if (elem) {
@@ -178,7 +183,8 @@ export class PdfPlayer {
178183
item: options.items[0],
179184
onExit: this.onDialogClosed,
180185
onPrevious: this.previous,
181-
onNext: this.next
186+
onNext: this.next,
187+
onToggleFullscreen: this.toggleFullscreen
182188
}, elem.querySelector('#bookOsdMount'));
183189

184190
return elem;
@@ -261,7 +267,7 @@ export class PdfPlayer {
261267

262268
// load any missing pages in the cache
263269
for (const page of pages) {
264-
if (!this.pages[page]) {
270+
if (!this.pages[page] || this.dimensions !== window.innerWidth + window.innerHeight) {
265271
this.pages[page] = document.createElement('canvas');
266272
this.renderPage(this.pages[page], parseInt(page.slice(4), 10));
267273

@@ -271,6 +277,10 @@ export class PdfPlayer {
271277

272278
// show the requested page
273279
canvas?.parentNode.replaceChild(this.pages[prefix + number], canvas);
280+
this.currentSrc = () => this.pages[prefix + number];
281+
282+
// track size so we can render all pages again when the screen has changed
283+
this.dimensions = window.innerWidth + window.innerHeight;
274284

275285
// delete all pages outside the cache area
276286
for (const page in this.pages) {

src/plugins/pdfPlayer/style.scss

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
position: relative;
33
display: grid;
44
place-items: center;
5-
top: 5vh;
6-
height: 90vh;
5+
top: calc(5vh + env(safe-area-inset-top));
6+
height: calc(90vh - env(safe-area-inset-top) - env(safe-area-inset-bottom));
77
}
88

99
#pdfPlayer {

0 commit comments

Comments
 (0)