From 7d1be7f2d3e96fba3409dc972721a7675aa94368 Mon Sep 17 00:00:00 2001 From: emirsassan Date: Fri, 27 Jun 2025 10:27:51 +0300 Subject: [PATCH] chore: port useSettings i have to refactor settings one more time --- .../frontend/src/hooks/useSettings.tsx | 138 ++++++++++++++++++ apps/onelauncher/frontend/src/main.tsx | 9 +- .../frontend/src/routes/app/browser/index.tsx | 75 +--------- .../frontend/src/routes/app/dev.tsx | 108 ++++++++++++++ .../src/routes/app/settings/minecraft.tsx | 2 +- 5 files changed, 257 insertions(+), 75 deletions(-) create mode 100644 apps/onelauncher/frontend/src/hooks/useSettings.tsx create mode 100644 apps/onelauncher/frontend/src/routes/app/dev.tsx diff --git a/apps/onelauncher/frontend/src/hooks/useSettings.tsx b/apps/onelauncher/frontend/src/hooks/useSettings.tsx new file mode 100644 index 00000000..6b052d60 --- /dev/null +++ b/apps/onelauncher/frontend/src/hooks/useSettings.tsx @@ -0,0 +1,138 @@ +/* eslint-disable no-console -- ok */ +/* eslint-disable react-hooks/rules-of-hooks -- stfu */ +/* eslint-disable ts/naming-convention -- please shut the fuck up i need to see if its working or not */ +import type { Settings } from '@/bindings.gen'; +import { bindings } from '@/main'; +import { useCommand } from '@onelauncher/common'; +import React, { createContext, useCallback, useContext, useEffect, useState } from 'react'; + +interface SettingsControllerType { + settings: Settings | undefined; + saveChangedSettings: () => void; + settingsToSave: Partial | null; + setSettingsToSave: (settings: Partial | null) => void; + settingsChanged: boolean; + setSettingsChanged: (changed: boolean) => void; + createSetting: (name: K, value: V) => [V, (value: V) => void]; +} + +const SettingsContext = createContext(null); + +interface SettingsProviderProps { + children: React.ReactNode; +} + +export function SettingsProvider({ children }: SettingsProviderProps) { + const { data: settings } = useCommand('readSettings', bindings.core.readSettings); + const [settingsChanged, setSettingsChanged] = useState(false); + const [settingsToSave, setSettingsToSave] = useState | null>(null); + + const filteredSettingsToSave = settingsToSave + ? Object.fromEntries( + Object.entries(settingsToSave), + ) as Partial + : {}; + + const patchedSettings: Settings = { + ...settings, + ...filteredSettingsToSave, + } as Settings; + + const writeQuery = useCommand('writeSettings', () => bindings.core.writeSettings(patchedSettings), { + enabled: false, + subscribed: false, + }); + + useEffect(() => { + const handleBeforeUnload = () => { + setSettingsChanged(false); + }; + + window.addEventListener('beforeunload', handleBeforeUnload); + return () => window.removeEventListener('beforeunload', handleBeforeUnload); + }, []); + + const saveChangedSettings = () => { + if (!settings) + return; + + console.log(settings); + console.log(settingsToSave); + + writeQuery.refetch(); + + setSettingsChanged(false); + }; + + const handleSetSettingsToSave = useCallback((newSettings: Partial | null) => { + setSettingsToSave(newSettings); + setSettingsChanged(true); + }, []); + + const createSetting = useCallback(( + name: K, + initialValue: V, + ): [V, (value: V) => void] => { + const [value, setValue] = useState(initialValue); + + useEffect(() => { + const didChange = settings?.[name] !== value; + console.log(`did change? ${didChange}`); + + if (didChange && settings) { + setSettingsToSave(prev => ({ + ...prev, + [name]: value, + })); + setSettingsChanged(true); + } + }, [value, name]); + + return [value, setValue]; + }, [settings]); + + const controller: SettingsControllerType = { + settings, + saveChangedSettings, + settingsToSave, + setSettingsToSave: handleSetSettingsToSave, + settingsChanged, + setSettingsChanged, + createSetting, + }; + + if (settings === undefined) + return null; + + return ( + + {children} + + {settingsChanged && ( +
+
+ You have unsaved changes! + +
+
+ )} +
+ ); +} + +export function useSettings(): SettingsControllerType { + const context = useContext(SettingsContext); + + if (!context) + throw new Error('useSettings should be called inside its SettingsProvider'); + + return context; +} + +export default useSettings; diff --git a/apps/onelauncher/frontend/src/main.tsx b/apps/onelauncher/frontend/src/main.tsx index 3acfdc42..930f49bd 100644 --- a/apps/onelauncher/frontend/src/main.tsx +++ b/apps/onelauncher/frontend/src/main.tsx @@ -6,6 +6,7 @@ import ReactDOM from 'react-dom/client'; import { createTauRPCProxy } from './bindings.gen'; import { NotificationProvider } from './hooks/useNotification'; +import { SettingsProvider } from './hooks/useSettings'; import { routeTree } from './routeTree.gen'; import './fonts'; import 'overlayscrollbars/overlayscrollbars.css'; @@ -56,9 +57,11 @@ if (rootElement && !rootElement.innerHTML) { root.render( - - - + + + + + , ); diff --git a/apps/onelauncher/frontend/src/routes/app/browser/index.tsx b/apps/onelauncher/frontend/src/routes/app/browser/index.tsx index 5a248895..0eb945b3 100644 --- a/apps/onelauncher/frontend/src/routes/app/browser/index.tsx +++ b/apps/onelauncher/frontend/src/routes/app/browser/index.tsx @@ -1,83 +1,16 @@ -import Modal from '@/components/overlay/Modal'; -import useNotifications from '@/hooks/useNotification'; -import { bindings } from '@/main'; -import { useCommand } from '@onelauncher/common'; -import { Button, Dropdown, TextField } from '@onelauncher/common/components'; import { createFileRoute } from '@tanstack/react-router'; +import { BracketsEllipsesIcon } from '@untitled-theme/icons-react'; export const Route = createFileRoute('/app/browser/')({ component: RouteComponent, }); function RouteComponent() { - const { create, list, clear } = useNotifications(); - const result = useCommand('read_settings', bindings.core.readSettings); - - const addSimpleNotif = () => { - create({ - message: 'This is a simple notification message', - title: 'Simple Notification', - }); - }; - - const addProgressNotif = () => { - create({ - message: 'Download in progress...', - title: 'Downloading File', - fraction: Math.floor(Math.random() * 100), - }); - }; - - const addErrorNotif = () => { - create({ - message: 'Something went wrong while processing your request', - title: 'Error', - }); - }; - return (
-

asdasdas

- - - - {/* we can open the modal but we cant close it for some reason */} - - - - -

sadsadsad

-
-
- - - Slmalr - Slmalr 2 - - -
- - - - -
- -
-

- Current Notifications ( - {Object.keys(list).length} - ): -

-
-					{JSON.stringify(list, null, 2)}
-				
-
- -
-

Settings

-
-					{JSON.stringify(result.data, null, 2)}
-				
+
+ +

WIP

); diff --git a/apps/onelauncher/frontend/src/routes/app/dev.tsx b/apps/onelauncher/frontend/src/routes/app/dev.tsx new file mode 100644 index 00000000..f86582e6 --- /dev/null +++ b/apps/onelauncher/frontend/src/routes/app/dev.tsx @@ -0,0 +1,108 @@ +import Modal from '@/components/overlay/Modal'; +import useNotifications from '@/hooks/useNotification'; +import useSettings from '@/hooks/useSettings'; +import { bindings } from '@/main'; +import { useCommand } from '@onelauncher/common'; +import { Button, Dropdown, Switch, TextField } from '@onelauncher/common/components'; +import { createFileRoute } from '@tanstack/react-router'; + +export const Route = createFileRoute('/app/dev')({ + component: RouteComponent, +}); + +function RouteComponent() { + const { create, list, clear } = useNotifications(); + const { settings, createSetting } = useSettings(); + const result = useCommand('read_settings', bindings.core.readSettings); + + const addSimpleNotif = () => { + create({ + message: 'This is a simple notification message', + title: 'Simple Notification', + }); + }; + + const addProgressNotif = () => { + create({ + message: 'Download in progress...', + title: 'Downloading File', + fraction: Math.floor(Math.random() * 100), + }); + }; + + const addErrorNotif = () => { + create({ + message: 'Something went wrong while processing your request', + title: 'Error', + }); + }; + + const [parallel, setParallel] = createSetting('allow_parallel_running_clusters', settings?.allow_parallel_running_clusters); + + return ( +
+

this is really became my test place fr

+ + + + {/* we can open the modal but we cant close it for some reason */} + + + + +

sadsadsad

+
+
+ + + Slmalr + Slmalr 2 + + +
+ + + + +
+ +
+

+ Current Notifications ( + {Object.keys(list).length} + ): +

+
+					{JSON.stringify(list, null, 2)}
+				
+
+ +
+
+
+

Settings

+
+							{JSON.stringify(result.data, null, 2)}
+						
+
+ +
+

Settings again but this time its from useSettings hook

+
+							{JSON.stringify(settings, null, 2)}
+						
+
+
+ +
+
+
+							{parallel ? 'Parallel running is enabled' : 'Parallel running is disabled'}
+						
+ setParallel(val)} /> +
+
+
+
+ ); +} diff --git a/apps/onelauncher/frontend/src/routes/app/settings/minecraft.tsx b/apps/onelauncher/frontend/src/routes/app/settings/minecraft.tsx index 61a0dd7b..7530c688 100644 --- a/apps/onelauncher/frontend/src/routes/app/settings/minecraft.tsx +++ b/apps/onelauncher/frontend/src/routes/app/settings/minecraft.tsx @@ -101,11 +101,11 @@ export function GameSettings(props: GameSettingProps) {
{ settings.mem_max = Number(e.target.value); }} type="number" + value={settings.mem_max ?? 2048} />