From f683288429a6f577751cd7aabbe04d15d8f36223 Mon Sep 17 00:00:00 2001 From: meet-k-pandya Date: Tue, 13 Sep 2022 00:17:35 +0530 Subject: [PATCH] Added toggle for direction and double page view --- CONTRIBUTORS.md | 1 + package-lock.json | 52 +++++----- package.json | 2 +- src/components/slideshow/slideshow.js | 7 +- src/plugins/comicsPlayer/plugin.js | 141 ++++++++++++++++++++++++-- src/plugins/comicsPlayer/style.scss | 17 ++++ src/scripts/settings/userSettings.js | 28 +++++ src/themes/dark/theme.css | 9 ++ 8 files changed, 218 insertions(+), 39 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 355f08852..9261538ff 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -53,6 +53,7 @@ - [Matthew Jones](https://github.com/matthew-jones-uk) - [taku0](https://github.com/taku0) - [is343](https://github.com/is343) + - [Meet Pandya](https://github.com/meet-k-pandya) # Emby Contributors diff --git a/package-lock.json b/package-lock.json index e3f63b1de..7ad207d95 100644 --- a/package-lock.json +++ b/package-lock.json @@ -46,7 +46,7 @@ "resize-observer-polyfill": "1.5.1", "screenfull": "6.0.2", "sortablejs": "1.15.0", - "swiper": "6.8.4", + "swiper": "8.4.0", "webcomponents.js": "0.7.24", "whatwg-fetch": "3.6.2", "workbox-core": "6.2.4", @@ -6504,11 +6504,11 @@ ] }, "node_modules/dom7": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", - "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.4.tgz", + "integrity": "sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw==", "dependencies": { - "ssr-window": "^3.0.0-alpha.1" + "ssr-window": "^4.0.0" } }, "node_modules/domelementtype": { @@ -14740,9 +14740,9 @@ "dev": true }, "node_modules/ssr-window": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", - "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", + "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==" }, "node_modules/stable": { "version": "0.1.8", @@ -17579,13 +17579,13 @@ } }, "node_modules/swiper": { - "version": "6.8.4", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-6.8.4.tgz", - "integrity": "sha512-O+buF9Q+sMA0H7luMS8R59hCaJKlpo8PXhQ6ZYu6Rn2v9OsFd4d1jmrv14QvxtQpKAvL/ZiovEeANI/uDGet7g==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.4.0.tgz", + "integrity": "sha512-6ax9prHdb6bsgmAHPRsAqfQwMdKjQEv7ya2D+p+UjR/bx7oyR56lDq5ELaKcZCr9glaPi7+k9BlPDhVLtq9Bag==", "funding": [ { "type": "patreon", - "url": "https://www.patreon.com/vladimirkharlampidi" + "url": "https://www.patreon.com/swiperjs" }, { "type": "open_collective", @@ -17594,8 +17594,8 @@ ], "hasInstallScript": true, "dependencies": { - "dom7": "^3.0.0", - "ssr-window": "^3.0.0" + "dom7": "^4.0.4", + "ssr-window": "^4.0.2" }, "engines": { "node": ">= 4.7.0" @@ -24310,11 +24310,11 @@ } }, "dom7": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/dom7/-/dom7-3.0.0.tgz", - "integrity": "sha512-oNlcUdHsC4zb7Msx7JN3K0Nro1dzJ48knvBOnDPKJ2GV9wl1i5vydJZUSyOfrkKFDZEud/jBsTk92S/VGSAe/g==", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/dom7/-/dom7-4.0.4.tgz", + "integrity": "sha512-DSSgBzQ4rJWQp1u6o+3FVwMNnT5bzQbMb+o31TjYYeRi05uAcpF8koxdfzeoe5ElzPmua7W7N28YJhF7iEKqIw==", "requires": { - "ssr-window": "^3.0.0-alpha.1" + "ssr-window": "^4.0.0" } }, "domelementtype": { @@ -30429,9 +30429,9 @@ "dev": true }, "ssr-window": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-3.0.0.tgz", - "integrity": "sha512-q+8UfWDg9Itrg0yWK7oe5p/XRCJpJF9OBtXfOPgSJl+u3Xd5KI328RUEvUqSMVM9CiQUEf1QdBzJMkYGErj9QA==" + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/ssr-window/-/ssr-window-4.0.2.tgz", + "integrity": "sha512-ISv/Ch+ig7SOtw7G2+qkwfVASzazUnvlDTwypdLoPoySv+6MqlOV10VwPSE6EWkGjhW50lUmghPmpYZXMu/+AQ==" }, "stable": { "version": "0.1.8", @@ -32661,12 +32661,12 @@ } }, "swiper": { - "version": "6.8.4", - "resolved": "https://registry.npmjs.org/swiper/-/swiper-6.8.4.tgz", - "integrity": "sha512-O+buF9Q+sMA0H7luMS8R59hCaJKlpo8PXhQ6ZYu6Rn2v9OsFd4d1jmrv14QvxtQpKAvL/ZiovEeANI/uDGet7g==", + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/swiper/-/swiper-8.4.0.tgz", + "integrity": "sha512-6ax9prHdb6bsgmAHPRsAqfQwMdKjQEv7ya2D+p+UjR/bx7oyR56lDq5ELaKcZCr9glaPi7+k9BlPDhVLtq9Bag==", "requires": { - "dom7": "^3.0.0", - "ssr-window": "^3.0.0" + "dom7": "^4.0.4", + "ssr-window": "^4.0.2" } }, "table": { diff --git a/package.json b/package.json index 79b18bf69..e6af838d3 100644 --- a/package.json +++ b/package.json @@ -100,7 +100,7 @@ "resize-observer-polyfill": "1.5.1", "screenfull": "6.0.2", "sortablejs": "1.15.0", - "swiper": "6.8.4", + "swiper": "8.4.0", "webcomponents.js": "0.7.24", "whatwg-fetch": "3.6.2", "workbox-core": "6.2.4", diff --git a/src/components/slideshow/slideshow.js b/src/components/slideshow/slideshow.js index c24b031a6..e5af0c81d 100644 --- a/src/components/slideshow/slideshow.js +++ b/src/components/slideshow/slideshow.js @@ -13,9 +13,10 @@ import './style.scss'; import 'material-design-icons-iconfont'; import '../../elements/emby-button/paper-icon-button-light'; import ServerConnections from '../ServerConnections'; -// eslint-disable-next-line import/named, import/namespace -import { Swiper } from 'swiper/swiper-bundle.esm'; -import 'swiper/swiper-bundle.css'; +//eslint-disable-next-line import/no-unresolved +import { Swiper } from 'swiper/bundle'; +//eslint-disable-next-line import/no-unresolved +import 'swiper/css/bundle'; import screenfull from 'screenfull'; /** diff --git a/src/plugins/comicsPlayer/plugin.js b/src/plugins/comicsPlayer/plugin.js index 42aaa3105..3082b4a5b 100644 --- a/src/plugins/comicsPlayer/plugin.js +++ b/src/plugins/comicsPlayer/plugin.js @@ -5,9 +5,11 @@ import dialogHelper from '../../components/dialogHelper/dialogHelper'; import keyboardnavigation from '../../scripts/keyboardNavigation'; import { appRouter } from '../../components/appRouter'; import ServerConnections from '../../components/ServerConnections'; -// eslint-disable-next-line import/named, import/namespace -import { Swiper } from 'swiper/swiper-bundle.esm'; -import 'swiper/swiper-bundle.css'; +import * as userSettings from '../../scripts/settings/userSettings'; +//eslint-disable-next-line import/no-unresolved +import { Swiper } from 'swiper/bundle'; +//eslint-disable-next-line import/no-unresolved +import 'swiper/css/bundle'; import './style.scss'; @@ -27,6 +29,9 @@ export class ComicsPlayer { this.currentPage = 0; this.pageCount = 0; + const mediaSourceId = options.items[0].Id; + this.comicsPlayerSettings = userSettings.getComicsPlayerSettings(mediaSourceId); + const elem = this.createMediaElement(); return this.setCurrentSrc(elem, options); } @@ -40,6 +45,9 @@ export class ComicsPlayer { Events.trigger(this, 'stopped', [stopInfo]); + const mediaSourceId = this.item.Id; + userSettings.setComicsPlayerSettings(this.comicsPlayerSettings, mediaSourceId); + this.archiveSource?.release(); const elem = this.mediaElement; @@ -87,6 +95,85 @@ export class ComicsPlayer { this.stop(); } + onDirChanged = () => { + let langDir = this.comicsPlayerSettings.langDir; + + if (!langDir || langDir === 'ltr') + langDir = 'rtl'; + else + langDir = 'ltr'; + + this.changeLanguageDirection(langDir); + + this.comicsPlayerSettings.langDir = langDir; + }; + + changeLanguageDirection(langDir) { + const currentPage = this.currentPage; + + this.swiperInstance.changeLanguageDirection(langDir); + + const prevIcon = langDir === 'ltr' ? 'arrow_circle_left' : 'arrow_circle_right'; + this.mediaElement.querySelector('.btnToggleLangDir > span').classList.remove(prevIcon); + + const newIcon = langDir === 'ltr' ? 'arrow_circle_right' : 'arrow_circle_left'; + this.mediaElement.querySelector('.btnToggleLangDir > span').classList.add(newIcon); + + const dirTitle = langDir === 'ltr' ? 'Right To Left' : 'Left To Right'; + this.mediaElement.querySelector('.btnToggleLangDir').title = dirTitle; + + this.reload(currentPage); + } + + onViewChanged = () => { + let view = this.comicsPlayerSettings.pagesPerView; + + if (!view || view === 1) + view = 2; + else + view = 1; + + this.changeView(view); + + this.comicsPlayerSettings.pagesPerView = view; + }; + + changeView(view) { + const currentPage = this.currentPage; + + this.swiperInstance.params.slidesPerView = view; + this.swiperInstance.params.slidesPerGroup = view; + + const prevIcon = view === 1 ? 'devices_fold' : 'import_contacts'; + this.mediaElement.querySelector('.btnToggleView > span').classList.remove(prevIcon); + + const newIcon = view === 1 ? 'import_contacts' : 'devices_fold'; + this.mediaElement.querySelector('.btnToggleView > span').classList.add(newIcon); + + const viewTitle = view === 1 ? 'Double Page View' : 'Single Page View'; + this.mediaElement.querySelector('.btnToggleView').title = viewTitle; + + this.reload(currentPage); + } + + reload(currentPage) { + const effect = this.swiperInstance.params.effect; + + this.swiperInstance.params.effect = 'none'; + this.swiperInstance.update(); + + this.swiperInstance.slideNext(); + this.swiperInstance.slidePrev(); + + if (this.currentPage != currentPage) { + this.swiperInstance.slideTo(currentPage); + this.swiperInstance.update(); + } + + this.swiperInstance.params.effect = effect; + this.swiperInstance.update(); + } + onWindowKeyUp(e) { const key = keyboardnavigation.getKeyName(e); switch (key) { @@ -101,6 +188,8 @@ export class ComicsPlayer { elem?.addEventListener('close', this.onDialogClosed, { once: true }); elem?.querySelector('.btnExit').addEventListener('click', this.onDialogClosed, { once: true }); + elem?.querySelector('.btnToggleLangDir').addEventListener('click', this.onDirChanged); + elem?.querySelector('.btnToggleView').addEventListener('click', this.onViewChanged); } bindEvents() { @@ -114,6 +203,8 @@ export class ComicsPlayer { elem?.removeEventListener('close', this.onDialogClosed); elem?.querySelector('.btnExit').removeEventListener('click', this.onDialogClosed); + elem?.querySelector('.btnToggleLangDir').removeEventListener('click', this.onDirChanged); + elem?.querySelector('.btnToggleView').removeEventListener('click', this.onViewChanged); } unbindEvents() { @@ -139,18 +230,40 @@ export class ComicsPlayer { removeOnClose: true }); + const viewIcon = this.comicsPlayerSettings.pagesPerView === 1 ? 'import_contacts' : 'devices_fold'; + const dirIcon = this.comicsPlayerSettings.langDir === 'ltr' ? 'arrow_circle_right' : 'arrow_circle_left'; + elem.id = 'comicsPlayer'; elem.classList.add('slideshowDialog'); - - elem.innerHTML = `
-
- -
`; + elem.innerHTML = `
+
+
+
+
+
+
+ + + +
`; dialogHelper.open(elem); } this.mediaElement = elem; + + const dirTitle = this.comicsPlayerSettings.langDir === 'ltr' ? 'Right To Left' : 'Left To Right'; + this.mediaElement.querySelector('.btnToggleLangDir').title = dirTitle; + + const viewTitle = this.comicsPlayerSettings.pagesPerView === 1 ? 'Double Page View' : 'Single Page View'; + this.mediaElement.querySelector('.btnToggleView').title = viewTitle; + this.bindEvents(); return elem; } @@ -199,9 +312,19 @@ export class ComicsPlayer { enabled: true }, preloadImages: true, - slidesPerView: 1, + slidesPerView: this.comicsPlayerSettings.pagesPerView, + slidesPerGroup: this.comicsPlayerSettings.pagesPerView, slidesPerColumn: 1, initialSlide: this.currentPage, + navigation: { + nextEl: '.swiper-button-next', + prevEl: '.swiper-button-prev' + }, + pagination: { + el: '.swiper-pagination', + clickable: true, + type: 'fraction' + }, // reduces memory consumption for large libraries while allowing preloading of images virtual: { slides: this.archiveSource.urls, diff --git a/src/plugins/comicsPlayer/style.scss b/src/plugins/comicsPlayer/style.scss index 08b408a3f..b19992c30 100644 --- a/src/plugins/comicsPlayer/style.scss +++ b/src/plugins/comicsPlayer/style.scss @@ -13,5 +13,22 @@ .swiper-slide-img { max-height: 100%; max-width: 100%; + height: 100%; + width: 100%; + object-fit: contain; + } + + .swiper-pagination { + width: max-content; + background: #fff; + color: #000; + padding: 2px 5px 2px 5px; + left: 50%; + transform: translate(-50%, 0%); + text-shadow: 0 0 20px #fff; + } + + .actionButtons > button:hover { + background: #fff; } } diff --git a/src/scripts/settings/userSettings.js b/src/scripts/settings/userSettings.js index 7eb9d2ff4..c6d0441c9 100644 --- a/src/scripts/settings/userSettings.js +++ b/src/scripts/settings/userSettings.js @@ -20,6 +20,11 @@ const defaultSubtitleAppearanceSettings = { verticalPosition: -3 }; +const defaultComicsPlayerSettings = { + langDir: 'ltr', + pagesPerView: 1 +}; + export class UserSettings { /** * Bind UserSettings instance to user. @@ -516,6 +521,27 @@ export class UserSettings { return this.set(key, JSON.stringify(value), false); } + /** + * Get comics player settings. + * @param {string} mediaSourceId - Media Source Id. + * @return {Object} Comics player settings. + */ + getComicsPlayerSettings(mediaSourceId) { + const settings = JSON.parse(this.get('comicsPlayerSettings', false) || '{}'); + return Object.assign(defaultComicsPlayerSettings, settings[mediaSourceId]); + } + + /** + * Set comics player settings. + * @param {Object} value - Comics player settings. + * @param {string} mediaSourceId - Media Source Id. + */ + setComicsPlayerSettings(value, mediaSourceId) { + const settings = JSON.parse(this.get('comicsPlayerSettings', false) || '{}'); + settings[mediaSourceId] = value; + return this.set('comicsPlayerSettings', JSON.stringify(settings), false); + } + /** * Set filter. * @param {string} key - Filter key. @@ -572,6 +598,8 @@ export const loadQuerySettings = currentSettings.loadQuerySettings.bind(currentS export const saveQuerySettings = currentSettings.saveQuerySettings.bind(currentSettings); export const getSubtitleAppearanceSettings = currentSettings.getSubtitleAppearanceSettings.bind(currentSettings); export const setSubtitleAppearanceSettings = currentSettings.setSubtitleAppearanceSettings.bind(currentSettings); +export const getComicsPlayerSettings = currentSettings.getComicsPlayerSettings.bind(currentSettings); +export const setComicsPlayerSettings = currentSettings.setComicsPlayerSettings.bind(currentSettings); export const setFilter = currentSettings.setFilter.bind(currentSettings); export const getFilter = currentSettings.getFilter.bind(currentSettings); export const customCss = currentSettings.customCss.bind(currentSettings); diff --git a/src/themes/dark/theme.css b/src/themes/dark/theme.css index ea57c76c9..1df52eaa2 100644 --- a/src/themes/dark/theme.css +++ b/src/themes/dark/theme.css @@ -487,6 +487,11 @@ html { background: #101010; } +#comicsPlayer .swiper-pagination { + background: #101010; + color: #fff; +} + #bookPlayer .topButtons { color: #fff; } @@ -495,6 +500,10 @@ html { color: #fff; } +.actionButtons > button:hover { + background: #101010 !important; +} + #dialogToc { background-color: #101010; }