mirror of
https://github.com/jellyfin/jellyfin-vue.git
synced 2025-03-03 03:16:34 +00:00
refactor(store): player-element uses now computed getters/setters
Although using .value might seem cumbersome at first, having computed getters/setters are clearer code-wise when using watchers and type-wise it's clear that the variable is fully reactive (instead of having to guess) Signed-off-by: Fernando Fernández <ferferga@hotmail.com>
This commit is contained in:
parent
225e5465b9
commit
fd7fc92e3c
@ -75,7 +75,7 @@
|
||||
:cols="8"
|
||||
class="text-right">
|
||||
<VSwitch
|
||||
v-model="stretched"
|
||||
v-model="playerElement.isStretched.value"
|
||||
color="primary"
|
||||
hide-details />
|
||||
</VCol>
|
||||
@ -87,19 +87,8 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { computed } from 'vue';
|
||||
import { playbackManager } from '@/store/playback-manager';
|
||||
import { playerElement } from '@/store/player-element';
|
||||
|
||||
const menuModel = defineModel<boolean>();
|
||||
|
||||
const stretched = computed({
|
||||
get() {
|
||||
return playerElement.isStretched;
|
||||
},
|
||||
set(v: boolean) {
|
||||
playerElement.isStretched = v;
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@/store/playback-manager
|
||||
|
@ -1,19 +1,18 @@
|
||||
<template>
|
||||
<VOverlay
|
||||
:model-value="true"
|
||||
persistent
|
||||
no-click-animation
|
||||
scrim
|
||||
scroll-strategy="none"
|
||||
content-class="minimized-overlay"
|
||||
:width="$vuetify.display.mobile ? '60vw' : '25vw'">
|
||||
<JHover v-slot="{ isHovering }">
|
||||
<JHover v-slot="{ isHovering }">
|
||||
<VOverlay
|
||||
:model-value="true"
|
||||
persistent
|
||||
no-click-animation
|
||||
:scrim="false"
|
||||
scroll-strategy="none"
|
||||
content-class="minimized-overlay"
|
||||
:width="$vuetify.display.mobile ? '60vw' : '25vw'">
|
||||
<div
|
||||
class="minimized-video-container" />
|
||||
<VOverlay
|
||||
:model-value="isHovering"
|
||||
contained
|
||||
scrim
|
||||
height="100%"
|
||||
width="100%">
|
||||
<div class="d-flex flex-column">
|
||||
@ -40,7 +39,7 @@
|
||||
class="pointer-events-all"
|
||||
icon
|
||||
size="large"
|
||||
@click="() => playbackManager.setPreviousItem()">
|
||||
@click="playbackManager.setPreviousItem">
|
||||
<VIcon size="32">
|
||||
<IMdiSkipPrevious />
|
||||
</VIcon>
|
||||
@ -67,22 +66,17 @@
|
||||
</div>
|
||||
</div>
|
||||
</VOverlay>
|
||||
</JHover>
|
||||
</VOverlay>
|
||||
</VOverlay>
|
||||
</JHover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useMagicKeys, whenever } from '@vueuse/core';
|
||||
import { onBeforeUnmount, onMounted } from 'vue';
|
||||
import { playbackManager } from '@/store/playback-manager';
|
||||
import { playerElement } from '@/store/player-element';
|
||||
|
||||
const keys = useMagicKeys();
|
||||
|
||||
whenever(keys.f, playerElement.toggleFullscreenVideoPlayer);
|
||||
|
||||
onMounted(() => {
|
||||
playerElement.isPiPMounted = true;
|
||||
playerElement.isPiPMounted.value = true;
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
@ -90,7 +84,7 @@ onBeforeUnmount(() => {
|
||||
* We need to destroy JASSUB so the canvas can be recreated in the other view
|
||||
*/
|
||||
playerElement.freeSsaTrack();
|
||||
playerElement.isPiPMounted = false;
|
||||
playerElement.isPiPMounted.value = false;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
@ -12,7 +12,7 @@
|
||||
crossorigin
|
||||
playsinline
|
||||
:loop="playbackManager.isRepeatingOnce"
|
||||
:class="{ stretched: playerElement.isStretched }"
|
||||
:class="{ stretched: playerElement.isStretched.value }"
|
||||
@loadeddata="onLoadedData">
|
||||
<track
|
||||
v-for="sub in playbackManager.currentItemVttParsedSubtitleTracks"
|
||||
@ -88,9 +88,9 @@ const teleportTarget = computed<
|
||||
'.fullscreen-video-container' | '.minimized-video-container' | undefined
|
||||
>(() => {
|
||||
if (playbackManager.currentlyPlayingMediaType === 'Video') {
|
||||
if (playerElement.isFullscreenMounted) {
|
||||
if (playerElement.isFullscreenMounted.value) {
|
||||
return '.fullscreen-video-container';
|
||||
} else if (playerElement.isPiPMounted) {
|
||||
} else if (playerElement.isPiPMounted.value) {
|
||||
return '.minimized-video-container';
|
||||
}
|
||||
}
|
||||
|
@ -11,8 +11,7 @@
|
||||
<AudioControls />
|
||||
<PiPVideoPlayer
|
||||
v-if="
|
||||
playbackManager.currentlyPlayingMediaType === 'Video' &&
|
||||
!playerElement.isFullscreenVideoPlayer
|
||||
playbackManager.currentlyPlayingMediaType === 'Video'
|
||||
" />
|
||||
</template>
|
||||
|
||||
@ -22,7 +21,6 @@ import { computed, onBeforeMount, onUnmounted, provide, ref, watch } from 'vue';
|
||||
import { useDisplay } from 'vuetify';
|
||||
import type { DrawerItem } from '@/components/Layout/Navigation/NavigationDrawer.vue';
|
||||
import { playbackManager } from '@/store/playback-manager';
|
||||
import { playerElement } from '@/store/player-element';
|
||||
import { fetchIndexPage, getLibraryIcon } from '@/utils/items';
|
||||
|
||||
const display = useDisplay();
|
||||
|
@ -183,10 +183,6 @@ function handleMouseMove(): void {
|
||||
}
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
if (playerElement.isFullscreenVideoPlayer) {
|
||||
playbackManager.stop();
|
||||
}
|
||||
|
||||
/**
|
||||
* We need to destroy JASSUB so the canvas can be recreated in the other view
|
||||
*/
|
||||
|
@ -31,7 +31,6 @@ export const router = createRouter({
|
||||
* Middleware pipeline: The order IS IMPORTANT (meta handling should always go first)
|
||||
*
|
||||
* Route-specific guards should be defined in the route itself, not here.
|
||||
* See the playback pages for an example of this.
|
||||
*/
|
||||
router.beforeEach(metaGuard);
|
||||
router.beforeEach(loginGuard);
|
||||
|
@ -7,17 +7,13 @@
|
||||
import JASSUB from 'jassub';
|
||||
import jassubWorker from 'jassub/dist/jassub-worker.js?url';
|
||||
import jassubWasmUrl from 'jassub/dist/jassub-worker.wasm?url';
|
||||
import { nextTick, reactive, watch } from 'vue';
|
||||
import { computed, nextTick, reactive, watch } from 'vue';
|
||||
import { playbackManager } from './playback-manager';
|
||||
import { isArray, isNil, sealed } from '@/utils/validation';
|
||||
import { mediaElementRef } from '@/store';
|
||||
import { router } from '@/plugins/router';
|
||||
import { remote } from '@/plugins/remote';
|
||||
|
||||
let jassub: JASSUB | undefined;
|
||||
const fullscreenVideoRoute = '/playback/video';
|
||||
const fullscreenMusicRoute = '/playback/music';
|
||||
|
||||
/**
|
||||
* == INTERFACES AND TYPES ==
|
||||
*/
|
||||
@ -32,6 +28,11 @@ interface PlayerElementState {
|
||||
*/
|
||||
@sealed
|
||||
class PlayerElementStore {
|
||||
/**
|
||||
* == NON REACTIVE STATE ==
|
||||
*/
|
||||
private readonly _fullscreenVideoRoute = '/playback/video';
|
||||
private _jassub: JASSUB | undefined;
|
||||
/**
|
||||
* == STATE SECTION ==
|
||||
*/
|
||||
@ -47,52 +48,49 @@ class PlayerElementStore {
|
||||
/**
|
||||
* == GETTERS AND SETTERS ==
|
||||
*/
|
||||
public get isFullscreenMounted(): boolean {
|
||||
return this._state.isFullscreenMounted;
|
||||
}
|
||||
public readonly isFullscreenMounted = computed({
|
||||
get: () => this._state.isFullscreenMounted,
|
||||
set: (newVal: boolean) => {
|
||||
this._state.isFullscreenMounted = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
public set isFullscreenMounted(newIsMounted: boolean) {
|
||||
this._state.isFullscreenMounted = newIsMounted;
|
||||
}
|
||||
public readonly isPiPMounted = computed({
|
||||
get: () => this._state.isPiPMounted,
|
||||
set: (newVal: boolean) => {
|
||||
this._state.isPiPMounted = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
public get isPiPMounted(): boolean {
|
||||
return this._state.isPiPMounted;
|
||||
}
|
||||
public readonly isStretched = computed({
|
||||
get: () => this._state.isStretched,
|
||||
set: (newVal: boolean) => {
|
||||
this._state.isStretched = newVal;
|
||||
}
|
||||
});
|
||||
|
||||
public set isPiPMounted(newIsPipMounted: boolean) {
|
||||
this._state.isPiPMounted = newIsPipMounted;
|
||||
}
|
||||
|
||||
public get isStretched(): boolean {
|
||||
return this._state.isStretched;
|
||||
}
|
||||
|
||||
public set isStretched(newIsStretched: boolean) {
|
||||
this._state.isStretched = newIsStretched;
|
||||
}
|
||||
|
||||
public get isFullscreenVideoPlayer(): boolean {
|
||||
return router.currentRoute.value.fullPath === fullscreenVideoRoute;
|
||||
}
|
||||
public readonly isFullscreenVideoPlayer = computed(
|
||||
() => router.currentRoute.value.fullPath === this._fullscreenVideoRoute
|
||||
);
|
||||
|
||||
/**
|
||||
* == ACTIONS ==
|
||||
*/
|
||||
public readonly toggleFullscreenVideoPlayer = async (): Promise<void> => {
|
||||
if (this.isFullscreenVideoPlayer) {
|
||||
if (this.isFullscreenVideoPlayer.value) {
|
||||
router.back();
|
||||
} else {
|
||||
await router.push(fullscreenVideoRoute);
|
||||
await router.push(this._fullscreenVideoRoute);
|
||||
}
|
||||
};
|
||||
|
||||
private readonly _setSsaTrack = (trackSrc: string, attachedFonts?: string[]): void => {
|
||||
if (
|
||||
!jassub &&
|
||||
!this._jassub &&
|
||||
mediaElementRef.value &&
|
||||
mediaElementRef.value instanceof HTMLVideoElement
|
||||
) {
|
||||
jassub = new JASSUB({
|
||||
this._jassub = new JASSUB({
|
||||
video: mediaElementRef.value,
|
||||
subUrl: trackSrc,
|
||||
fonts: attachedFonts,
|
||||
@ -105,24 +103,24 @@ class PlayerElementStore {
|
||||
// OffscreenCanvas doesn't work perfectly on Workers: https://github.com/ThaUnknown/jassub/issues/33
|
||||
offscreenRender: false
|
||||
});
|
||||
} else if (jassub) {
|
||||
} else if (this._jassub) {
|
||||
if (isArray(attachedFonts)) {
|
||||
for (const font of attachedFonts) {
|
||||
jassub.addFont(font);
|
||||
this._jassub.addFont(font);
|
||||
}
|
||||
}
|
||||
|
||||
jassub.setTrackByUrl(trackSrc);
|
||||
this._jassub.setTrackByUrl(trackSrc);
|
||||
}
|
||||
};
|
||||
|
||||
public readonly freeSsaTrack = (): void => {
|
||||
if (jassub) {
|
||||
if (this._jassub) {
|
||||
try {
|
||||
jassub.destroy();
|
||||
this._jassub.destroy();
|
||||
} catch {}
|
||||
|
||||
jassub = undefined;
|
||||
this._jassub = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@ -212,15 +210,7 @@ class PlayerElementStore {
|
||||
watch(
|
||||
() => playbackManager.currentItem,
|
||||
async (newValue, oldValue) => {
|
||||
const currentFullPath = router.currentRoute.value.fullPath;
|
||||
|
||||
if (
|
||||
!newValue &&
|
||||
(currentFullPath.includes(fullscreenMusicRoute) ||
|
||||
currentFullPath.includes(fullscreenVideoRoute))
|
||||
) {
|
||||
router.back();
|
||||
} else if (
|
||||
newValue &&
|
||||
!oldValue &&
|
||||
playbackManager.currentlyPlayingMediaType === 'Video'
|
||||
|
Loading…
x
Reference in New Issue
Block a user