Skip to content

Commit 87e7c2e

Browse files
authored
Merge pull request #8004 from dkanada/book-osd
2 parents 7a1665d + 6aa203a commit 87e7c2e

10 files changed

Lines changed: 135 additions & 167 deletions

File tree

src/plugins/bookPlayer/BookOsd/BookOsd.scss

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
z-index: 1002;
55
display: flex;
66
justify-content: space-between;
7+
pointer-events: none;
78
flex-direction: column;
89
}
910

@@ -14,6 +15,7 @@
1415
height: 5vh;
1516
padding: 0 0.8vw;
1617
background-color: var(--jf-palette-AppBar-defaultBg);
18+
pointer-events: auto;
1719
}
1820

1921
// TODO disable landscape on mobile devices
@@ -23,6 +25,10 @@
2325
}
2426
}
2527

28+
.bookOsdSpacer {
29+
flex: 1;
30+
}
31+
2632
.bookOsdTop {
2733
padding-top: env(safe-area-inset-top);
2834
}
@@ -31,10 +37,6 @@
3137
padding-bottom: env(safe-area-inset-bottom);
3238
}
3339

34-
.bookOsdMargin {
35-
margin-left: auto;
36-
}
37-
3840
.bookOsdTitle {
3941
font-size: 1.1rem;
4042
margin-left: 0.35rem;

src/plugins/bookPlayer/BookOsd/BookOsd.tsx

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,32 +3,57 @@ import React, { type FC, useCallback, useState } from 'react';
33
import './BookOsd.scss';
44
import IconButton from '../../../elements/emby-button/IconButton';
55
import globalize from 'lib/globalize';
6+
import * as userSettings from '../../../scripts/settings/userSettings';
7+
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
68

79
interface BookOsdProps {
8-
title: string;
10+
item: BaseItemDto;
911
onExit: () => void;
1012
onPrevious: () => void;
1113
onNext: () => void;
1214
onOpenTableOfContents?: () => void;
1315
onRotateTheme?: () => void;
1416
onDecreaseFontSize?: () => void;
1517
onIncreaseFontSize?: () => void;
18+
onToggleDirection?: () => void;
19+
onToggleLayout?: () => void;
1620
onToggleFullscreen?: () => void;
1721
}
1822

23+
interface ComicsPlayerSettings {
24+
langDir?: string;
25+
pagesPerView?: number;
26+
}
27+
1928
const BookOsd: FC<BookOsdProps> = ({
20-
title,
29+
item,
2130
onExit,
2231
onPrevious,
2332
onNext,
2433
onOpenTableOfContents,
2534
onRotateTheme,
2635
onDecreaseFontSize,
2736
onIncreaseFontSize,
37+
onToggleDirection,
38+
onToggleLayout,
2839
onToggleFullscreen
2940
}) => {
41+
const settings = userSettings.getComicsPlayerSettings(item.Id!) as ComicsPlayerSettings;
42+
43+
const [direction, setDirection] = useState(settings.langDir === 'rtl');
44+
const [layout, setLayout] = useState(settings.pagesPerView === 2);
3045
const [fullscreen, setFullscreen] = useState(false);
3146

47+
const onClickDirection = useCallback(() => {
48+
onToggleDirection?.();
49+
setDirection(state => !state);
50+
}, [onToggleDirection]);
51+
52+
const onClickLayout = useCallback(() => {
53+
onToggleLayout?.();
54+
setLayout(state => !state);
55+
}, [onToggleLayout]);
56+
3257
const onClickFullscreen = useCallback(() => {
3358
onToggleFullscreen?.();
3459
setFullscreen(state => !state);
@@ -38,19 +63,19 @@ const BookOsd: FC<BookOsdProps> = ({
3863
<div className='bookOsd'>
3964
<div className='bookOsdRow bookOsdTop'>
4065
<IconButton onClick={onExit} icon='arrow_back' title={globalize.translate('ButtonBack')} />
41-
<span className='bookOsdTitle'>{title}</span>
66+
<span className='bookOsdTitle'>{item.Name}</span>
4267
</div>
4368

4469
<div className='bookOsdRow bookOsdBottom'>
4570
<IconButton onClick={onPrevious} icon='navigate_before' title={globalize.translate('Previous')} />
4671
<IconButton onClick={onNext} icon='navigate_next' title={globalize.translate('Next')} />
72+
<div className='bookOsdSpacer' />
4773

4874
{onOpenTableOfContents && (
4975
<IconButton
5076
onClick={onOpenTableOfContents}
5177
icon='toc'
5278
title={globalize.translate('TableOfContents')}
53-
className='bookOsdMargin'
5479
/>
5580
)}
5681

@@ -78,6 +103,22 @@ const BookOsd: FC<BookOsdProps> = ({
78103
/>
79104
)}
80105

106+
{onToggleDirection && (
107+
<IconButton
108+
onClick={onClickDirection}
109+
icon={direction ? 'arrow_circle_left' : 'arrow_circle_right'}
110+
title={globalize.translate(direction ? 'ViewRightToLeft' : 'ViewLeftToRight')}
111+
/>
112+
)}
113+
114+
{onToggleLayout && (
115+
<IconButton
116+
onClick={onClickLayout}
117+
icon={layout ? 'import_contacts' : 'devices_fold'}
118+
title={globalize.translate(layout ? 'ViewDoublePage' : 'ViewSinglePage')}
119+
/>
120+
)}
121+
81122
{onToggleFullscreen && (
82123
<IconButton
83124
onClick={onClickFullscreen}

src/plugins/bookPlayer/plugin.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,8 +192,7 @@ export class BookPlayer {
192192
this.rendition?.on('keydown', this.onWindowKeyDown);
193193

194194
if (browser.safari) {
195-
const player = document.querySelector('.bookOsd');
196-
this.addSwipeGestures(player);
195+
this.addSwipeGestures(document.querySelector('#bookPlayerContainer'));
197196
} else {
198197
this.rendition?.on('rendered', (e, i) => this.addSwipeGestures(i.document.documentElement));
199198
}
@@ -298,7 +297,7 @@ export class BookPlayer {
298297

299298
this.mediaElement = elem;
300299
this.unmountBookOsd = renderComponent(BookOsd, {
301-
title: options.items[0].Name,
300+
item: options.items[0],
302301
onExit: this.onDialogClosed,
303302
onPrevious: this.previous,
304303
onNext: this.next,

src/plugins/comicsPlayer/plugin.js

Lines changed: 35 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,11 @@ import dialogHelper from '../../components/dialogHelper/dialogHelper';
99
import keyboardnavigation from '../../scripts/keyboardNavigation';
1010
import { appRouter } from '../../components/router/appRouter';
1111
import * as userSettings from '../../scripts/settings/userSettings';
12+
import BookOsd from '../bookPlayer/BookOsd/BookOsd';
13+
import Events from '../../utils/events.ts';
14+
import { renderComponent } from '../../utils/reactUtils';
1215

16+
import 'material-design-icons-iconfont';
1317
import './style.scss';
1418

1519
// supported book file extensions
@@ -25,6 +29,11 @@ export class ComicsPlayer {
2529
this.priority = 1;
2630
this.imageMap = new Map();
2731

32+
this.previous = this.previous.bind(this);
33+
this.next = this.next.bind(this);
34+
this.onDirChanged = this.onDirChanged.bind(this);
35+
this.onViewChanged = this.onViewChanged.bind(this);
36+
2837
this.onDialogClosed = this.onDialogClosed.bind(this);
2938
this.onWindowKeyDown = this.onWindowKeyDown.bind(this);
3039
}
@@ -36,12 +45,13 @@ export class ComicsPlayer {
3645
const mediaSourceId = options.items[0].Id;
3746
this.comicsPlayerSettings = userSettings.getComicsPlayerSettings(mediaSourceId);
3847

39-
const elem = this.createMediaElement();
48+
const elem = this.createMediaElement(options);
4049
return this.setCurrentSrc(elem, options);
4150
}
4251

4352
stop() {
4453
this.unbindEvents();
54+
this.unmountBookOsd?.();
4555

4656
const stopInfo = {
4757
src: this.item
@@ -99,7 +109,7 @@ export class ComicsPlayer {
99109
this.stop();
100110
}
101111

102-
onDirChanged = () => {
112+
onDirChanged() {
103113
let langDir = this.comicsPlayerSettings.langDir;
104114

105115
if (!langDir || langDir === 'ltr') {
@@ -111,26 +121,16 @@ export class ComicsPlayer {
111121
this.changeLanguageDirection(langDir);
112122

113123
this.comicsPlayerSettings.langDir = langDir;
114-
};
124+
}
115125

116126
changeLanguageDirection(langDir) {
117127
const currentPage = this.currentPage;
118128

119129
this.swiperInstance.changeLanguageDirection(langDir);
120-
121-
const prevIcon = langDir === 'ltr' ? 'arrow_circle_left' : 'arrow_circle_right';
122-
this.mediaElement.querySelector('.btnToggleLangDir > span').classList.remove(prevIcon);
123-
124-
const newIcon = langDir === 'ltr' ? 'arrow_circle_right' : 'arrow_circle_left';
125-
this.mediaElement.querySelector('.btnToggleLangDir > span').classList.add(newIcon);
126-
127-
const dirTitle = langDir === 'ltr' ? 'Right To Left' : 'Left To Right';
128-
this.mediaElement.querySelector('.btnToggleLangDir').title = dirTitle;
129-
130130
this.reload(currentPage);
131131
}
132132

133-
onViewChanged = () => {
133+
onViewChanged() {
134134
let view = this.comicsPlayerSettings.pagesPerView;
135135

136136
if (!view || view === 1) {
@@ -142,23 +142,14 @@ export class ComicsPlayer {
142142
this.changeView(view);
143143

144144
this.comicsPlayerSettings.pagesPerView = view;
145-
};
145+
}
146146

147147
changeView(view) {
148148
const currentPage = this.currentPage;
149149

150150
this.swiperInstance.params.slidesPerView = view;
151151
this.swiperInstance.params.slidesPerGroup = view;
152152

153-
const prevIcon = view === 1 ? 'devices_fold' : 'import_contacts';
154-
this.mediaElement.querySelector('.btnToggleView > span').classList.remove(prevIcon);
155-
156-
const newIcon = view === 1 ? 'import_contacts' : 'devices_fold';
157-
this.mediaElement.querySelector('.btnToggleView > span').classList.add(newIcon);
158-
159-
const viewTitle = view === 1 ? 'Double Page View' : 'Single Page View';
160-
this.mediaElement.querySelector('.btnToggleView').title = viewTitle;
161-
162153
this.reload(currentPage);
163154
}
164155

@@ -191,37 +182,17 @@ export class ComicsPlayer {
191182
}
192183
}
193184

194-
bindMediaElementEvents() {
195-
const elem = this.mediaElement;
196-
197-
elem?.addEventListener('close', this.onDialogClosed, { once: true });
198-
elem?.querySelector('.btnExit').addEventListener('click', this.onDialogClosed, { once: true });
199-
elem?.querySelector('.btnToggleLangDir').addEventListener('click', this.onDirChanged);
200-
elem?.querySelector('.btnToggleView').addEventListener('click', this.onViewChanged);
201-
}
202-
203185
bindEvents() {
204-
this.bindMediaElementEvents();
205-
186+
this.mediaElement?.addEventListener('close', this.onDialogClosed, { once: true });
206187
document.addEventListener('keydown', this.onWindowKeyDown);
207188
}
208189

209-
unbindMediaElementEvents() {
210-
const elem = this.mediaElement;
211-
212-
elem?.removeEventListener('close', this.onDialogClosed);
213-
elem?.querySelector('.btnExit').removeEventListener('click', this.onDialogClosed);
214-
elem?.querySelector('.btnToggleLangDir').removeEventListener('click', this.onDirChanged);
215-
elem?.querySelector('.btnToggleView').removeEventListener('click', this.onViewChanged);
216-
}
217-
218190
unbindEvents() {
219-
this.unbindMediaElementEvents();
220-
191+
this.mediaElement?.removeEventListener('close', this.onDialogClosed);
221192
document.removeEventListener('keydown', this.onWindowKeyDown);
222193
}
223194

224-
createMediaElement() {
195+
createMediaElement(options) {
225196
let elem = this.mediaElement;
226197
if (elem) {
227198
return elem;
@@ -238,39 +209,25 @@ export class ComicsPlayer {
238209
removeOnClose: true
239210
});
240211

241-
const viewIcon = this.comicsPlayerSettings.pagesPerView === 1 ? 'import_contacts' : 'devices_fold';
242-
const dirIcon = this.comicsPlayerSettings.langDir === 'ltr' ? 'arrow_circle_right' : 'arrow_circle_left';
243-
244212
elem.id = 'comicsPlayer';
245213
elem.classList.add('slideshowDialog');
246-
elem.innerHTML = `<div dir=${this.comicsPlayerSettings.langDir} class="slideshowSwiperContainer">
214+
elem.innerHTML = `<div id="bookOsdMount"></div><div dir=${this.comicsPlayerSettings.langDir} class="slideshowSwiperContainer">
247215
<div class="swiper-wrapper"></div>
248-
<div class="swiper-button-next actionButtonIcon"></div>
249-
<div class="swiper-button-prev actionButtonIcon"></div>
250216
<div class="swiper-pagination"></div>
251-
</div>
252-
<div class="actionButtons">
253-
<button is="paper-icon-button-light" class="autoSize btnToggleLangDir" tabindex="-1">
254-
<span class="material-icons actionButtonIcon ${dirIcon}" aria-hidden="true"></span>
255-
</button>
256-
<button is="paper-icon-button-light" class="autoSize btnToggleView" tabindex="-1">
257-
<span class="material-icons actionButtonIcon ${viewIcon}" aria-hidden="true"></span>
258-
</button>
259-
<button is="paper-icon-button-light" class="autoSize btnExit" tabindex="-1">
260-
<span class="material-icons actionButtonIcon close" aria-hidden="true"></span>
261-
</button>
262217
</div>`;
263218

264219
dialogHelper.open(elem);
265220
}
266221

267222
this.mediaElement = elem;
268-
269-
const dirTitle = this.comicsPlayerSettings.langDir === 'ltr' ? 'Right To Left' : 'Left To Right';
270-
this.mediaElement.querySelector('.btnToggleLangDir').title = dirTitle;
271-
272-
const viewTitle = this.comicsPlayerSettings.pagesPerView === 1 ? 'Double Page View' : 'Single Page View';
273-
this.mediaElement.querySelector('.btnToggleView').title = viewTitle;
223+
this.unmountBookOsd = renderComponent(BookOsd, {
224+
item: options.items[0],
225+
onExit: this.onDialogClosed,
226+
onPrevious: this.previous,
227+
onNext: this.next,
228+
onToggleDirection: this.onDirChanged,
229+
onToggleLayout: this.onViewChanged
230+
}, elem.querySelector('#bookOsdMount'));
274231

275232
this.bindEvents();
276233
return elem;
@@ -333,10 +290,6 @@ export class ComicsPlayer {
333290
slidesPerGroup: this.comicsPlayerSettings.pagesPerView,
334291
slidesPerColumn: 1,
335292
initialSlide: this.currentPage,
336-
navigation: {
337-
nextEl: '.swiper-button-next',
338-
prevEl: '.swiper-button-prev'
339-
},
340293
pagination: {
341294
el: '.swiper-pagination',
342295
clickable: true,
@@ -360,6 +313,14 @@ export class ComicsPlayer {
360313
});
361314
}
362315

316+
next() {
317+
this.swiperInstance?.slideNext();
318+
}
319+
320+
previous() {
321+
this.swiperInstance?.slidePrev();
322+
}
323+
363324
getImgFromUrl(url) {
364325
return `<div class="swiper-slide">
365326
<div class="slider-zoom-container">

0 commit comments

Comments
 (0)