Skip to content

Commit 2feb539

Browse files
authored
Fix issue: 165: Disable Animations (#406)
* Fix issue: 165: Disable Animations * refactor: use setIntervalImmediately with 1000ms timer for animation toggle * refactor: simplify CSS and run prettier formatting * fix: animations disabled on first launch despite setting being off Fixed an issue where animations were disabled when the application first launched, even though the 'Disable Animations' setting was turned off in the config. The problem occurred because the animation state check only ran when there was a change in the setting. On first launch, since the value remained false (animations enabled), the comparison would be: lastAnimationState (false) !== currentState (false) = false This meant updateAnimationClass() was never called initially, leaving animations disabled by default. Solution: Initialize lastAnimationState as undefined instead of reading from config. This ensures the first check always triggers: lastAnimationState (undefined) !== currentState (false) = true Now animations are correctly enabled on first launch and can be toggled by the user in settings as intended. Resolves #165
1 parent 56824e4 commit 2feb539

File tree

3 files changed

+97
-1
lines changed

3 files changed

+97
-1
lines changed

src/renderer/App.vue

Lines changed: 70 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,14 @@
149149
import { RouterLink, useRoute, useRouter } from "vue-router";
150150
import { routes } from "./router";
151151
import { Icon } from "@iconify/vue";
152-
import { onMounted, ref, useTemplateRef, watch } from "vue";
152+
import { onMounted, onUnmounted, ref, useTemplateRef, watch } from "vue";
153153
import { isInstalled } from "./lib/install";
154154
import { Winboat } from "./lib/winboat";
155155
import { openAnchorLink } from "./utils/openLink";
156156
import { WinboatConfig } from "./lib/config";
157157
import { USBManager } from "./lib/usbmanager";
158158
import { GUEST_NOVNC_PORT } from "./lib/constants";
159+
import { setIntervalImmediately } from "./utils/interval";
159160
const { BrowserWindow }: typeof import("@electron/remote") = require("@electron/remote");
160161
const os: typeof import("os") = require("os");
161162
const path: typeof import("path") = require("path");
@@ -173,6 +174,7 @@ const MANUAL_UPDATE_TIMEOUT = 60000; // 60 seconds
173174
const updateDialog = useTemplateRef("updateDialog");
174175
const rerenderCounter = ref(0); // TODO: Hack for non-reactive data
175176
const novncURL = ref("");
177+
let animationCheckInterval: NodeJS.Timeout | null = null;
176178
177179
onMounted(async () => {
178180
const winboatInstalled = await isInstalled();
@@ -186,6 +188,30 @@ onMounted(async () => {
186188
$router.push("/home");
187189
}
188190
191+
// Apply or remove disable-animations class based on config
192+
const updateAnimationClass = () => {
193+
if (wbConfig?.config.disableAnimations) {
194+
document.body.classList.add("disable-animations");
195+
console.log("Animations disabled");
196+
} else {
197+
document.body.classList.remove("disable-animations");
198+
console.log("Animations enabled");
199+
}
200+
};
201+
202+
// Poll for config changes since the Proxy doesn't trigger Vue reactivity
203+
// This is similar to how rerenderCounter is used elsewhere in the codebase
204+
// Start with undefined so that the first call will always apply the current state
205+
let lastAnimationState: boolean | undefined = undefined;
206+
animationCheckInterval = setIntervalImmediately(() => {
207+
const currentState = wbConfig?.config.disableAnimations;
208+
if (currentState !== lastAnimationState) {
209+
lastAnimationState = currentState;
210+
updateAnimationClass();
211+
rerenderCounter.value++; // Force re-render to update transitions
212+
}
213+
}, 1000); // Check every 1000ms
214+
189215
// Watch for guest server updates and show dialog
190216
watch(
191217
() => winboat?.isUpdatingGuestServer.value,
@@ -209,6 +235,13 @@ onMounted(async () => {
209235
);
210236
});
211237
238+
onUnmounted(() => {
239+
// Clean up the interval when component unmounts
240+
if (animationCheckInterval) {
241+
clearInterval(animationCheckInterval);
242+
}
243+
});
244+
212245
function handleMinimize() {
213246
console.log("Minimize");
214247
window.electronAPI.minimizeWindow();
@@ -296,4 +329,40 @@ dialog::backdrop {
296329
);
297330
-webkit-mask-image: -webkit-gradient(linear, left 0%, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
298331
}
332+
333+
/* Disable all animations when the setting is enabled */
334+
body.disable-animations,
335+
body.disable-animations *,
336+
body.disable-animations *::before,
337+
body.disable-animations *::after {
338+
animation: none !important;
339+
transition: none !important;
340+
}
341+
342+
/* Specifically disable Vue transition components */
343+
body.disable-animations .fade-enter-active,
344+
body.disable-animations .fade-leave-active,
345+
body.disable-animations .devices-move,
346+
body.disable-animations .devices-enter-active,
347+
body.disable-animations .devices-leave-active,
348+
body.disable-animations .menu-move,
349+
body.disable-animations .menu-enter-active,
350+
body.disable-animations .menu-leave-active,
351+
body.disable-animations .apps-move,
352+
body.disable-animations .apps-enter-active,
353+
body.disable-animations .apps-leave-active,
354+
body.disable-animations .bounce-enter-active,
355+
body.disable-animations .bounce-leave-active,
356+
body.disable-animations .bouncedown-enter-active,
357+
body.disable-animations .bouncedown-leave-active,
358+
body.disable-animations .bounce-in,
359+
body.disable-animations .bouncedown-in {
360+
transition: none !important;
361+
animation: none !important;
362+
}
363+
364+
/* Disable keyframe animations */
365+
body.disable-animations .blob-anim {
366+
animation: none !important;
367+
}
299368
</style>

src/renderer/lib/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export type WinboatConfigObj = {
2121
advancedFeatures: boolean;
2222
multiMonitor: number;
2323
rdpArgs: RdpArg[];
24+
disableAnimations: boolean;
2425
};
2526

2627
const defaultConfig: WinboatConfigObj = {
@@ -34,6 +35,7 @@ const defaultConfig: WinboatConfigObj = {
3435
advancedFeatures: false,
3536
multiMonitor: 0,
3637
rdpArgs: [],
38+
disableAnimations: false,
3739
};
3840

3941
export class WinboatConfig {

src/renderer/views/Config.vue

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -512,6 +512,31 @@
512512
></x-switch>
513513
</div>
514514
</x-card>
515+
516+
<!-- Disable Animations -->
517+
<x-card
518+
class="flex flex-row justify-between items-center p-2 py-3 my-0 w-full backdrop-blur-xl backdrop-brightness-150 bg-neutral-800/20"
519+
>
520+
<div>
521+
<div class="flex flex-row gap-2 items-center mb-2">
522+
<Icon class="inline-flex text-violet-400 size-8" icon="mdi:animation-outline"></Icon>
523+
<h1 class="my-0 text-lg font-semibold">Disable Animations</h1>
524+
</div>
525+
<p class="text-neutral-400 text-[0.9rem] !pt-0 !mt-0">
526+
If enabled, all animations in the UI will be disabled (useful when GPU acceleration isn't
527+
working well)
528+
</p>
529+
</div>
530+
<div class="flex flex-row gap-2 justify-center items-center">
531+
<x-switch
532+
:toggled="wbConfig.config.disableAnimations"
533+
@toggle="
534+
(_: any) => (wbConfig.config.disableAnimations = !wbConfig.config.disableAnimations)
535+
"
536+
size="large"
537+
></x-switch>
538+
</div>
539+
</x-card>
515540
</div>
516541
</div>
517542

0 commit comments

Comments
 (0)