From de7023064500a9bcbb361c2a67534d75d68e761a Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Fri, 27 Dec 2024 12:50:19 +0100 Subject: [PATCH] LAUNCHER-5 feat: Disable mod buttons when the cluster is running LAUNCHER-16 feat: Running cluster indicator on home page --- apps/frontend/src/ui/hooks/useProcessor.tsx | 40 +++++++++++++++++++ apps/frontend/src/ui/pages/Home.tsx | 21 +++++++++- .../src/ui/pages/cluster/ClusterMods.tsx | 16 +++++--- .../src/ui/pages/cluster/ClusterRoot.tsx | 28 ++----------- 4 files changed, 73 insertions(+), 32 deletions(-) create mode 100644 apps/frontend/src/ui/hooks/useProcessor.tsx diff --git a/apps/frontend/src/ui/hooks/useProcessor.tsx b/apps/frontend/src/ui/hooks/useProcessor.tsx new file mode 100644 index 00000000..10f8de3a --- /dev/null +++ b/apps/frontend/src/ui/hooks/useProcessor.tsx @@ -0,0 +1,40 @@ +import type { Cluster, DetailedProcess } from '@onelauncher/client/bindings'; +import type { UnlistenFn } from '@tauri-apps/api/event'; +import { bridge } from '~imports'; +import { type Accessor, createEffect, createSignal, onCleanup, onMount, type Resource } from 'solid-js'; +import useCommand, { tryResult } from './useCommand'; + +interface ProcessorHookType { + running: Resource; + stop: (id: string) => Promise; + isRunning: Accessor; +}; + +export default function useProcessor(cluster: Cluster): ProcessorHookType { + const [runningProcesses, { refetch: refetchProcesses }] = useCommand(() => bridge.commands.getProcessesDetailedByPath(cluster.path!)); + const [unlisten, setUnlisten] = createSignal(); + const [isRunning, setIsRunning] = createSignal(false); + + onMount(async () => { + const unlisten = await bridge.events.processPayload.listen((e) => { + if (e.payload.event === 'started' || e.payload.event === 'finished') + refetchProcesses(); + }); + + setUnlisten(() => unlisten); + }); + + onCleanup(() => { + unlisten()?.(); + }); + + createEffect(() => { + setIsRunning((runningProcesses()?.length ?? 0) > 0); + }); + + return { + running: runningProcesses, + stop: async id => await tryResult(() => bridge.commands.killProcess(id)), + isRunning, + }; +} diff --git a/apps/frontend/src/ui/pages/Home.tsx b/apps/frontend/src/ui/pages/Home.tsx index 0466c864..b2213b61 100644 --- a/apps/frontend/src/ui/pages/Home.tsx +++ b/apps/frontend/src/ui/pages/Home.tsx @@ -8,11 +8,13 @@ import { } from '@untitled-theme/icons-solid'; import { bridge } from '~imports'; import ClusterCover from '~ui/components/game/ClusterCover'; +import PlayerHead from '~ui/components/game/PlayerHead'; import { useClusterCreator } from '~ui/components/overlay/cluster/ClusterCreationModal'; import { useLaunchCluster, useRecentCluster } from '~ui/hooks/useCluster'; import useCommand from '~ui/hooks/useCommand'; -import { formatAsDuration, upperFirst } from '~utils'; +import useProcessor from '~ui/hooks/useProcessor'; +import { formatAsDuration, upperFirst } from '~utils'; import { For, onMount, Show } from 'solid-js'; import BannerBackground from '../../assets/images/header.png'; import Button from '../components/base/Button'; @@ -170,6 +172,7 @@ function Banner() { function ClusterCard(props: Cluster) { const navigate = useNavigate(); + const { running, isRunning } = useProcessor(props); function openClusterPage(_e: MouseEvent) { navigate(`/clusters/?id=${props.uuid}`); @@ -180,7 +183,11 @@ function ClusterCard(props: Cluster) { return ( <>
openClusterPage(e)} >
@@ -193,6 +200,16 @@ function ClusterCard(props: Cluster) { cluster={props} />
+ + +
+ + {process => ( + + )} + +
+
diff --git a/apps/frontend/src/ui/pages/cluster/ClusterMods.tsx b/apps/frontend/src/ui/pages/cluster/ClusterMods.tsx index 9b377c1f..cc110488 100644 --- a/apps/frontend/src/ui/pages/cluster/ClusterMods.tsx +++ b/apps/frontend/src/ui/pages/cluster/ClusterMods.tsx @@ -9,11 +9,13 @@ import Sidebar from '~ui/components/Sidebar'; import useBrowser from '~ui/hooks/useBrowser'; import useClusterContext from '~ui/hooks/useCluster'; import useCommand from '~ui/hooks/useCommand'; -import { createEffect, createSignal, For, Match, Show, Switch } from 'solid-js'; +import useProcessor from '~ui/hooks/useProcessor'; +import { type Accessor, createEffect, createSignal, For, Match, Show, Switch } from 'solid-js'; // TODO: This needs a rewrite. function ClusterMods() { const [cluster] = useClusterContext(); + const { isRunning } = useProcessor(cluster()!); const [mods, { refetch: refetchMods }] = useCommand(cluster, () => bridge.commands.getClusterPackages(cluster()?.path || '', 'mod')); // Mods to display, should be a clone of the mods array but sorted @@ -101,7 +103,7 @@ function ClusterMods() { 0}> {mod => ( - + )} @@ -120,6 +122,7 @@ export default ClusterMods; interface ModEntryProps { pkg: Package; refetch: () => void; + isRunning: Accessor; }; function ModEntry(props: ModEntryProps) { @@ -241,9 +244,12 @@ function ModEntry(props: ModEntryProps) { */} - +
diff --git a/apps/frontend/src/ui/pages/cluster/ClusterRoot.tsx b/apps/frontend/src/ui/pages/cluster/ClusterRoot.tsx index b99a3abd..8f935208 100644 --- a/apps/frontend/src/ui/pages/cluster/ClusterRoot.tsx +++ b/apps/frontend/src/ui/pages/cluster/ClusterRoot.tsx @@ -1,12 +1,10 @@ -import type { UnlistenFn } from '@tauri-apps/api/event'; import { type Navigator, Route, useIsRouting, useSearchParams } from '@solidjs/router'; import { EyeIcon, File06Icon, Globe04Icon, Image03Icon, PackagePlusIcon, Settings04Icon } from '@untitled-theme/icons-solid'; -import { bridge } from '~imports'; import PlayerHead from '~ui/components/game/PlayerHead'; import useClusterContext, { ClusterProvider } from '~ui/hooks/useCluster'; -import { tryResult } from '~ui/hooks/useCommand'; +import useProcessor from '~ui/hooks/useProcessor'; import { supportsMods } from '~utils'; -import { createEffect, createResource, createSignal, onCleanup, onMount, type ParentProps, Show } from 'solid-js'; +import { createEffect, type ParentProps, Show } from 'solid-js'; import AnimatedRoutes from '../../components/AnimatedRoutes'; import ErrorBoundary from '../../components/ErrorBoundary'; import Sidebar from '../../components/Sidebar'; @@ -71,14 +69,7 @@ ClusterRoot.open = function (navigate: Navigator, uuid: string) { function ClusterSidebar() { const [cluster, { refetch: refetchCluster }] = useClusterContext(); - const [listener, setListener] = createSignal(); - const [runningProcesses, { refetch: refetchProcesses }] = createResource([], async () => { - const c = cluster(); - if (!c || typeof c.path !== 'string') - return []; - - return tryResult(() => bridge.commands.getProcessesDetailedByPath(c.path!)); - }); + const { running: runningProcesses } = useProcessor(cluster()!); const isRouting = useIsRouting(); @@ -87,19 +78,6 @@ function ClusterSidebar() { refetchCluster(); }); - onMount(async () => { - const unlisten = await bridge.events.processPayload.listen(({ payload }) => { - if (payload.event === 'started' || payload.event === 'finished') - refetchProcesses(); - }); - - setListener(() => unlisten); - }); - - onCleanup(() => { - listener?.()?.(); - }); - return (