From af177152f002cc8f98b050cd7945264387737845 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Tue, 18 Jun 2024 18:50:16 +0200 Subject: [PATCH] feat: Implement settings --- core/src/store/settings.rs | 8 +++++ desktop/src-tauri/build.rs | 2 +- .../permissions/onelauncher/default.toml | 2 +- desktop/src-tauri/src/api/commands.rs | 12 ++++---- desktop/src/ui/App.tsx | 3 +- desktop/src/ui/components/WindowFrame.tsx | 10 ++++--- desktop/src/ui/hooks/useSettings.tsx | 30 +++++++++++++++++-- .../settings/launcher/SettingsAppearance.tsx | 8 ++++- .../settings/launcher/SettingsGeneral.tsx | 18 +++++------ 9 files changed, 66 insertions(+), 27 deletions(-) diff --git a/core/src/store/settings.rs b/core/src/store/settings.rs index 7b045b31..da1e012a 100644 --- a/core/src/store/settings.rs +++ b/core/src/store/settings.rs @@ -15,6 +15,12 @@ const CURRENT_FORMAT_VERSION: u32 = 1; pub struct Settings { /// A OneLauncher [`Theme`] managed by the core GUI. pub theme: Theme, + /// Does not ask for confirmation when closing the OneLauncher GUI + #[serde(default)] + pub hide_close_prompt: bool, + /// Disables animations in the OneLauncher GUI + #[serde(default)] + pub disable_animations: bool, /// A global fullscreen Minecraft state. #[serde(default)] pub force_fullscreen: bool, @@ -89,6 +95,8 @@ impl Settings { } else { let settings = Self { theme: Theme::Dark, + hide_close_prompt: false, + disable_animations: false, force_fullscreen: false, resolution: Resolution::default(), java_versions: JavaVersions::new(), diff --git a/desktop/src-tauri/build.rs b/desktop/src-tauri/build.rs index 4c3f0e27..e1cf8e1b 100644 --- a/desktop/src-tauri/build.rs +++ b/desktop/src-tauri/build.rs @@ -13,7 +13,7 @@ fn main() { "get_cluster", "get_manifest", "get_settings", - "change_settings" + "set_settings" ]), ), ) diff --git a/desktop/src-tauri/permissions/onelauncher/default.toml b/desktop/src-tauri/permissions/onelauncher/default.toml index eb58e990..14f20147 100644 --- a/desktop/src-tauri/permissions/onelauncher/default.toml +++ b/desktop/src-tauri/permissions/onelauncher/default.toml @@ -9,5 +9,5 @@ permissions = [ "allow-get-manifest", "allow-login-msa", "allow-get-settings", - "allow-change-settings" + "allow-set-settings" ] diff --git a/desktop/src-tauri/src/api/commands.rs b/desktop/src-tauri/src/api/commands.rs index a20ac601..dcef7fe9 100644 --- a/desktop/src-tauri/src/api/commands.rs +++ b/desktop/src-tauri/src/api/commands.rs @@ -5,10 +5,9 @@ use std::str::FromStr; use chrono::DateTime; use onelauncher::data::{ClusterMeta, Loader, PackageData, Settings}; use onelauncher::store::{Cluster, ClusterPath}; -use onelauncher::{cluster, State}; +use onelauncher::{cluster, settings}; use serde::{Deserialize, Serialize}; use specta::Type; -use tokio::sync::RwLock; use uuid::Uuid; #[macro_export] @@ -24,7 +23,7 @@ macro_rules! collect_commands { get_cluster, get_clusters, get_settings, - change_settings + set_settings, ]) } }; @@ -129,12 +128,11 @@ pub async fn get_clusters() -> Result, String> { #[specta::specta] #[tauri::command] pub async fn get_settings() -> Result { - Ok(State::get().await?.settings.read().await.clone()) + settings::get().await.map_err(|err| err.into()) } #[specta::specta] #[tauri::command] -pub async fn change_settings(settings: Settings) -> Result<(), String> { - State::get().await?.settings.write().await.clone_from(&settings); - Ok(()) +pub async fn set_settings(settings: Settings) -> Result<(), String> { + settings::set(settings).await.map_err(|err| err.into()) } diff --git a/desktop/src/ui/App.tsx b/desktop/src/ui/App.tsx index ea1d4a3c..91593949 100644 --- a/desktop/src/ui/App.tsx +++ b/desktop/src/ui/App.tsx @@ -9,10 +9,11 @@ import { SettingsProvider } from './hooks/useSettings'; import { bridge } from '~index'; function App(props: ParentProps) { - if (!bridge.commands.isDev()) + if (!bridge.commands.isDev()) { document.addEventListener('contextmenu', (event) => { event.preventDefault(); }); + } return ( diff --git a/desktop/src/ui/components/WindowFrame.tsx b/desktop/src/ui/components/WindowFrame.tsx index 9ee955ca..f6134813 100644 --- a/desktop/src/ui/components/WindowFrame.tsx +++ b/desktop/src/ui/components/WindowFrame.tsx @@ -4,6 +4,7 @@ import type { JSX } from 'solid-js'; import { createSignal, onMount } from 'solid-js'; import Modal from './overlay/Modal'; import Button from './base/Button'; +import useSettingsContext from '~ui/hooks/useSettings'; interface TitlebarButtonProps { icon: (any: any) => JSX.Element; @@ -23,6 +24,7 @@ function TitlebarButton(props: TitlebarButtonProps) { function WindowFrame() { const [isModalVisible, setModalVisible] = createSignal(false); + const settings = useSettingsContext(); const maximize = () => Window.getCurrent().toggleMaximize(); const minimize = () => Window.getCurrent().minimize(); @@ -31,10 +33,10 @@ function WindowFrame() { onMount(() => { Window.getCurrent().onCloseRequested((event) => { - // if (appSettings.settings.closeDialog) { - // event.preventDefault(); - // setModalVisible(true); - // } + if (settings.hide_close_prompt !== true) { + event.preventDefault(); + setModalVisible(true); + } }); }); diff --git a/desktop/src/ui/hooks/useSettings.tsx b/desktop/src/ui/hooks/useSettings.tsx index 27952828..7e241748 100644 --- a/desktop/src/ui/hooks/useSettings.tsx +++ b/desktop/src/ui/hooks/useSettings.tsx @@ -1,10 +1,17 @@ -import { type Context, type ParentProps, type Resource, Show, createContext, useContext } from 'solid-js'; +import { type Context, type ParentProps, type Resource, Show, createContext, createEffect, useContext } from 'solid-js'; import useCommand from './useCommand'; import type { Settings } from '~bindings'; import { bridge } from '~index'; const SettingsContext = createContext() as Context; +/** + * Sync the launcher state (CSS, text etc) with the current settings + */ +export function syncSettings(settings: Settings) { + document.body.classList.toggle('reduce-motion', settings.disable_animations); +} + export function getSettings(): Resource | undefined { const [resource] = useCommand(bridge.commands.getSettings); return resource; @@ -13,6 +20,11 @@ export function getSettings(): Resource | undefined { export function SettingsProvider(props: ParentProps) { const settings = getSettings(); + createEffect(() => { + if (settings !== undefined && settings() !== undefined) + syncSettings(settings!()!); + }); + return ( @@ -28,7 +40,21 @@ export function useSettingsContext() { if (!context) throw new Error('useSettingsContext should be called inside its SettingsProvider'); - return context; + const contextProxy = new Proxy(context, { + set(target, key, value) { + // @ts-expect-error typescript + target[key] = value; + save(target); // TODO: Possibly make a "Save confirmation" instead of writing to the settings file every time? + return true; + }, + }); + + return contextProxy; +} + +function save(settings: Settings) { + bridge.commands.setSettings(settings); + syncSettings(settings); } export default useSettingsContext; diff --git a/desktop/src/ui/pages/settings/launcher/SettingsAppearance.tsx b/desktop/src/ui/pages/settings/launcher/SettingsAppearance.tsx index fec38aa9..424485df 100644 --- a/desktop/src/ui/pages/settings/launcher/SettingsAppearance.tsx +++ b/desktop/src/ui/pages/settings/launcher/SettingsAppearance.tsx @@ -4,8 +4,11 @@ import ScrollableContainer from '~ui/components/ScrollableContainer'; import Button from '~ui/components/base/Button'; import Toggle from '~ui/components/base/Toggle'; import Sidebar from '~ui/components/Sidebar'; +import useSettingsContext from '~ui/hooks/useSettings'; function SettingsAppearance() { + const settings = useSettingsContext(); + return (

Appearance

@@ -27,7 +30,10 @@ function SettingsAppearance() { description="Toggle all animations in the launcher." icon={} > - + settings.disable_animations = value} + />
diff --git a/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx b/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx index 12bfe99c..e4dc61ff 100644 --- a/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx +++ b/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx @@ -1,31 +1,29 @@ import { XIcon } from '@untitled-theme/icons-solid'; -import { createEffect } from 'solid-js'; import SettingsRow from '../../../components/SettingsRow'; import ScrollableContainer from '~ui/components/ScrollableContainer'; import Toggle from '~ui/components/base/Toggle'; import Sidebar from '~ui/components/Sidebar'; -import { bridge } from '~index'; -import useCommand from '~ui/hooks/useCommand'; import useSettingsContext from '~ui/hooks/useSettings'; function SettingsGeneral() { const settings = useSettingsContext(); - createEffect(() => { - console.log(settings); - }); - return (

General

+ } > - + settings.hide_close_prompt = value} + /> +
);