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:
Fernando Fernández 2024-03-09 18:52:42 +01:00
parent 225e5465b9
commit fd7fc92e3c
7 changed files with 56 additions and 90 deletions

View File

@ -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

View File

@ -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>

View File

@ -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';
}
}

View File

@ -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();

View File

@ -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
*/

View File

@ -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);

View File

@ -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'