perf: skip transition on low FPS, improve input device detection

Signed-off-by: Fernando Fernández <ferferga@hotmail.com>
This commit is contained in:
Fernando Fernández 2024-06-20 01:56:23 +02:00
parent 8166599310
commit 909886227f
6 changed files with 35 additions and 13 deletions

View File

@ -5,14 +5,16 @@
<RouterView v-slot="{ Component, route }">
<JTransition
:name="route.meta.layout.transition.enter ?? defaultTransition"
:mode="defaultTransitionMode ?? route.meta.layout.transition.mode">
:mode="defaultTransitionMode ?? route.meta.layout.transition.mode"
important>
<Suspense @resolve="apploaded = true">
<JView
:key="route.meta.layout.name ?? 'default'"
:comp="getLayoutComponent(route.meta.layout.name)">
<JTransition
:name="route.meta.layout.transition.enter ?? defaultTransition"
:mode="defaultTransitionMode ?? route.meta.layout.transition.mode">
:mode="defaultTransitionMode ?? route.meta.layout.transition.mode"
important>
<Suspense suspensible>
<JView :key="route.path" :comp="Component" />
</Suspense>

View File

@ -17,12 +17,12 @@
</div>
<div
class="absolute-cover card-overlay d-flex justify-center align-center"
:class="{ 'card-overlay-hover': overlay && isFinePointer }">
:class="{ 'card-overlay-hover': overlay && hasFinePointer }">
<div class="card-upper-content d-flex justify-center align-center">
<slot name="upper-content" />
</div>
<div
v-if="(isHovering && overlay && isFinePointer) || forceOverlay"
v-if="(isHovering && overlay && hasFinePointer) || forceOverlay"
class="card-overlay-hover-hidden">
<slot name="center-content" />
<div class="card-lower-content d-flex justify-center align-center">
@ -57,7 +57,7 @@
<script setup lang="ts">
import { useAttrs, computed } from 'vue';
import { isNil } from '@/utils/validation';
import { isFinePointer } from '@/store';
import { hasFinePointer } from '@/store';
import type { CardShapes } from '@/utils/items';
interface Props {

View File

@ -55,7 +55,6 @@ class BlurhashWorker {
* @param width - Width of the decoded pixel array
* @param height - Height of the decoded pixel array.
* @param punch - Contrast of the decoded pixels
* @returns - Returns the decoded pixels in the proxied response by Comlink
*/
public readonly drawCanvas = ({
hash, canvas, width = DEFAULT_WIDTH, height = DEFAULT_HEIGHT, punch = DEFAULT_PUNCH

View File

@ -1,7 +1,7 @@
<template>
<div class="j-splash" :class="clientSettings.currentTheme.value">
<img src="./icon.png" alt="Jellyfin Logo">
<JTransition name="slide-y-reverse" appear>
<JTransition name="slide-y-reverse" appear important>
<div class="uno-flex uno-flex-col uno-gap-5 uno-bottom-25 uno-fixed uno-w-full uno-items-center">
<VProgressCircular indeterminate />
<VBtn v-if="remote.auth.currentUser" @click="remote.auth.logoutCurrentUser">

View File

@ -3,14 +3,14 @@
:is="props.group ? TransitionGroup : Transition"
class="j-transition"
v-bind="mergeProps($props, $attrs)"
:name="prefersNoMotion || props.disabled ? undefined : `j-transition-${props.name}`">
:name="prefersNoMotion || disabled || (isSlow && !important) ? undefined : `j-transition-${props.name}`">
<slot />
</component>
</template>
<script setup lang="ts">
import { Transition, TransitionGroup, type TransitionProps, mergeProps } from 'vue';
import { prefersNoMotion } from '@/store';
import { prefersNoMotion, isSlow } from '@/store';
export interface JTransitionProps extends BetterOmit<TransitionProps, 'name'> {
name?: 'fade' | 'rotated-zoom' | 'slide-y' | 'slide-y-reverse' | 'slide-x' | 'slide-x-reverse';
@ -24,6 +24,10 @@ export interface JTransitionProps extends BetterOmit<TransitionProps, 'name'> {
*/
group?: boolean;
disabled?: boolean;
/**
* Run the transition even on low FPS scenarios
*/
important?: boolean;
}
const props = withDefaults(defineProps<JTransitionProps>(), { name: 'fade', group: undefined, disabled: undefined });

View File

@ -1,6 +1,6 @@
import { getSystemApi } from '@jellyfin/sdk/lib/utils/api/system-api';
import { computedAsync, useMediaControls, useMediaQuery, useNetwork, useNow, useScroll } from '@vueuse/core';
import { shallowRef } from 'vue';
import { computedAsync, useFps, useMediaControls, useMediaQuery, useNetwork, useNow, useScroll } from '@vueuse/core';
import { shallowRef, computed } from 'vue';
import { remote } from '@/plugins/remote';
import { isNil } from '@/utils/validation';
/**
@ -36,10 +36,27 @@ export const mediaWebAudio = {
* Reactively tracks if the user wants animations (false) or not (true).
*/
export const prefersNoMotion = useMediaQuery('(prefers-reduced-motion)');
/**
* Reactively tracks if the device has a high precision input (like a mouse)
* IWhether the user is using a pointer with high precision (like a mouse)
*/
export const isFinePointer = useMediaQuery('(pointer:fine)');
export const hasFinePointer = useMediaQuery('(any-pointer:fine)');
/**
* Whether the user is using a pointer with low precision (like touch)
*/
export const hasTouch = useMediaQuery('(any-pointer:coarse)');
/**
* Track if there's HDR support in the screen
*/
export const hasHDRDisplay = useMediaQuery('(video-dynamic-range:high)');
/**
* Track performance
*/
const fps = useFps();
const isLowRefreshRateScreen = useMediaQuery('(update:slow)');
export const isSlow = computed(() => isLowRefreshRateScreen.value || fps.value <= 15);
/**
* Reactively tracks if the user is connected to the server