From 30b2de61294cb62ee7ca60b41d62767e6b541550 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Sun, 15 Sep 2024 20:48:21 +0200 Subject: [PATCH] feat: Add custom window frame option + some tweaks --- apps/desktop/capabilities/default.json | 2 + apps/desktop/src/api/commands/mod.rs | 14 ++++- apps/desktop/src/lib.rs | 20 +++++++- .../src/ui/components/SettingsRow.tsx | 2 +- .../src/ui/components/WindowFrame.tsx | 24 +++++---- .../src/ui/components/base/Button.module.scss | 2 +- .../src/ui/components/base/Button.tsx | 2 +- .../ui/components/content/ProviderIcon.tsx | 51 +++++++++++++++++++ .../src/ui/components/game/LoaderIcon.tsx | 2 +- .../src/ui/pages/browser/BrowserMain.tsx | 2 +- .../src/ui/pages/browser/BrowserRoot.tsx | 5 +- .../settings/launcher/SettingsAppearance.tsx | 23 ++++++++- apps/frontend/src/utils/browser.ts | 2 +- apps/frontend/src/utils/index.ts | 2 +- packages/core/src/store/settings.rs | 7 ++- packages/core/src/utils/mod.rs | 3 ++ packages/core/src/utils/window.rs | 19 +++++++ 17 files changed, 155 insertions(+), 27 deletions(-) create mode 100644 apps/frontend/src/ui/components/content/ProviderIcon.tsx create mode 100644 packages/core/src/utils/window.rs diff --git a/apps/desktop/capabilities/default.json b/apps/desktop/capabilities/default.json index ab2b6378..73cd4f32 100644 --- a/apps/desktop/capabilities/default.json +++ b/apps/desktop/capabilities/default.json @@ -21,6 +21,8 @@ "core:window:allow-maximize", "core:window:allow-toggle-maximize", "core:window:allow-internal-toggle-maximize", + "core:window:allow-set-decorations", + "core:window:allow-set-title-bar-style", "core:webview:allow-internal-toggle-devtools", "core:event:default", diff --git a/apps/desktop/src/api/commands/mod.rs b/apps/desktop/src/api/commands/mod.rs index 8b4b8233..b967572b 100644 --- a/apps/desktop/src/api/commands/mod.rs +++ b/apps/desktop/src/api/commands/mod.rs @@ -1,6 +1,8 @@ use interpulse::api::minecraft::Version; use onelauncher::data::Settings; use onelauncher::settings; +use tauri::AppHandle; +use tauri::Manager; mod cluster; pub use crate::api::commands::cluster::*; @@ -76,7 +78,9 @@ macro_rules! collect_commands { sync_cluster_packages_by_type, // Updater check_for_update, - install_update + install_update, + // Other + set_window_style, ] }}; } @@ -100,3 +104,11 @@ pub async fn get_settings() -> Result { pub async fn set_settings(settings: Settings) -> Result<(), String> { Ok(settings::set(settings).await?) } + +#[specta::specta] +#[tauri::command] +pub fn set_window_style(handle: AppHandle, custom: bool) -> Result<(), String> { + let window = handle.get_webview_window("main").unwrap(); + onelauncher::utils::window::set_window_styling(&window, custom) + .map_err(|e| e.to_string()) +} diff --git a/apps/desktop/src/lib.rs b/apps/desktop/src/lib.rs index ab059c03..39192225 100644 --- a/apps/desktop/src/lib.rs +++ b/apps/desktop/src/lib.rs @@ -1,4 +1,5 @@ use api::statics::get_program_info; +use onelauncher::utils::window::set_window_styling; use tauri::{Emitter, Manager}; pub mod api; @@ -91,7 +92,24 @@ pub async fn run_app) + Send + 'static>( fn setup(handle: &tauri::AppHandle) -> Result<(), Box> { let win = handle.get_webview_window("main").unwrap(); - win.show().unwrap(); + + tokio::task::spawn(async move { + let state = match onelauncher::State::get().await { + Ok(state) => state, + Err(err) => { + tracing::error!("{err}"); + return; + } + }; + + let settings = state.settings.read().await; + + if let Err(err) = set_window_styling(&win, settings.custom_frame) { + tracing::error!(err); + }; + + win.show().unwrap(); + }); Ok(()) } diff --git a/apps/frontend/src/ui/components/SettingsRow.tsx b/apps/frontend/src/ui/components/SettingsRow.tsx index 0d433e40..565d0738 100644 --- a/apps/frontend/src/ui/components/SettingsRow.tsx +++ b/apps/frontend/src/ui/components/SettingsRow.tsx @@ -21,7 +21,7 @@ function SettingsRow(props: SettingsRowProps) {
-

{props.title}

+

{props.title}

{props.description}

diff --git a/apps/frontend/src/ui/components/WindowFrame.tsx b/apps/frontend/src/ui/components/WindowFrame.tsx index 695af462..3e1a3a87 100644 --- a/apps/frontend/src/ui/components/WindowFrame.tsx +++ b/apps/frontend/src/ui/components/WindowFrame.tsx @@ -1,8 +1,8 @@ -import type { JSX } from 'solid-js'; import { Window } from '@tauri-apps/api/window'; import { ChevronLeftIcon, Maximize02Icon, MinusIcon, XCloseIcon } from '@untitled-theme/icons-solid'; import useSettings from '~ui/hooks/useSettings'; -import { onMount } from 'solid-js'; +import { onMount, Show } from 'solid-js'; +import type { JSX } from 'solid-js'; import Button from './base/Button'; import Modal, { createModal } from './overlay/Modal'; @@ -51,17 +51,19 @@ function WindowFrame() { }); return ( -
-
- history.back()} /> -
+ +
+
+ history.back()} /> +
-
- minimize()} /> - maximize()} /> - quit()} /> +
+ minimize()} /> + maximize()} /> + quit()} /> +
-
+
); } diff --git a/apps/frontend/src/ui/components/base/Button.module.scss b/apps/frontend/src/ui/components/base/Button.module.scss index 7672b4e3..755c3e94 100644 --- a/apps/frontend/src/ui/components/base/Button.module.scss +++ b/apps/frontend/src/ui/components/base/Button.module.scss @@ -1,5 +1,5 @@ .button { - @apply py-1.5 px-3 rounded-lg flex flex-row justify-center items-center gap-x-2.5; + @apply py-1.5 px-3 rounded-lg flex flex-row justify-center items-center gap-x-2.5 h-9.5; &__primary, &__iconPrimary { @apply text-onbrand hover:text-onbrand-hover active:text-onbrand-pressed disabled:text-onbrand-disabled; diff --git a/apps/frontend/src/ui/components/base/Button.tsx b/apps/frontend/src/ui/components/base/Button.tsx index 62a378a5..9aef52aa 100644 --- a/apps/frontend/src/ui/components/base/Button.tsx +++ b/apps/frontend/src/ui/components/base/Button.tsx @@ -1,5 +1,5 @@ -import type { Accessor, JSX, ParentProps } from 'solid-js'; import { createEffect, createSignal, mergeProps, on, splitProps, untrack } from 'solid-js'; +import type { Accessor, JSX, ParentProps } from 'solid-js'; import styles from './Button.module.scss'; type ButtonProps = JSX.ButtonHTMLAttributes & ParentProps & { diff --git a/apps/frontend/src/ui/components/content/ProviderIcon.tsx b/apps/frontend/src/ui/components/content/ProviderIcon.tsx new file mode 100644 index 00000000..4c16a8be --- /dev/null +++ b/apps/frontend/src/ui/components/content/ProviderIcon.tsx @@ -0,0 +1,51 @@ +import ModrinthImage from '~assets/logos/modrinth.svg?component-solid'; +import { type Component, type JSX, Match, Show, splitProps, Switch } from 'solid-js'; +import type { ManagedPackage, Providers } from '@onelauncher/client/bindings'; + +export function getProviderLogoElement(provider: ManagedPackage | Providers): string | Component { + const providerName = (typeof provider === 'string' ? provider : provider.provider)?.toLowerCase() as Lowercase; + + // [provider logo, is svg] + const mapping: Record, string | Component> = { + modrinth: ModrinthImage, + }; + + return mapping[providerName]; +} + +type ProviderIconProps = JSX.HTMLAttributes & { + provider: Providers | undefined; +}; + +function ProviderIcon(props: ProviderIconProps) { + const [split, rest] = splitProps(props, ['provider', 'class']); + + const Element = () => { + const value = getProviderLogoElement(split.provider!); + + return ( + + + {`${split.provider}'s + + + {value} + + + ); + }; + + return ( + + )} + fallback={( +
} /> + )} + when={split.provider !== undefined} + /> + ); +} + +export default ProviderIcon; diff --git a/apps/frontend/src/ui/components/game/LoaderIcon.tsx b/apps/frontend/src/ui/components/game/LoaderIcon.tsx index 105ce51e..9b598583 100644 --- a/apps/frontend/src/ui/components/game/LoaderIcon.tsx +++ b/apps/frontend/src/ui/components/game/LoaderIcon.tsx @@ -1,9 +1,9 @@ -import type { Cluster, Loader } from '@onelauncher/client/bindings'; import FabricImage from '~assets/logos/fabric.png'; import ForgeImage from '~assets/logos/forge.png'; import QuiltImage from '~assets/logos/quilt.png'; import VanillaImage from '~assets/logos/vanilla.png'; import { type JSX, splitProps } from 'solid-js'; +import type { Cluster, Loader } from '@onelauncher/client/bindings'; export function getLoaderLogoSrc(loader: Cluster | Loader): string { const loaderName = (typeof loader === 'string' ? loader : loader.meta.loader)?.toLowerCase() as Loader; diff --git a/apps/frontend/src/ui/pages/browser/BrowserMain.tsx b/apps/frontend/src/ui/pages/browser/BrowserMain.tsx index cd601ad0..9b1f0885 100644 --- a/apps/frontend/src/ui/pages/browser/BrowserMain.tsx +++ b/apps/frontend/src/ui/pages/browser/BrowserMain.tsx @@ -1,10 +1,10 @@ -import type { ManagedPackage } from '@onelauncher/client/bindings'; import { ChevronRightIcon } from '@untitled-theme/icons-solid'; import OneConfigLogo from '~assets/logos/oneconfig.svg?component-solid'; import Button from '~ui/components/base/Button'; import SearchResultsContainer from '~ui/components/content/SearchResults'; import useBrowser from '~ui/hooks/useBrowser'; import { onMount, Show } from 'solid-js'; +import type { ManagedPackage } from '@onelauncher/client/bindings'; import { BrowserContent } from './BrowserRoot'; function BrowserMain() { diff --git a/apps/frontend/src/ui/pages/browser/BrowserRoot.tsx b/apps/frontend/src/ui/pages/browser/BrowserRoot.tsx index 0af47c7d..712927b5 100644 --- a/apps/frontend/src/ui/pages/browser/BrowserRoot.tsx +++ b/apps/frontend/src/ui/pages/browser/BrowserRoot.tsx @@ -1,8 +1,9 @@ import { Route, useLocation } from '@solidjs/router'; -import { SearchMdIcon, Settings01Icon } from '@untitled-theme/icons-solid'; +import { SearchMdIcon } from '@untitled-theme/icons-solid'; import Button from '~ui/components/base/Button'; import Dropdown from '~ui/components/base/Dropdown'; import TextField from '~ui/components/base/TextField'; +import ProviderIcon from '~ui/components/content/ProviderIcon'; import useBrowser from '~ui/hooks/useBrowser'; import { PROVIDERS } from '~utils'; import { browserCategories } from '~utils/browser'; @@ -119,7 +120,6 @@ function BrowserSidebar() {
@@ -135,6 +135,7 @@ function BrowserSidebar() { {provider => ( + {provider} )} diff --git a/apps/frontend/src/ui/pages/settings/launcher/SettingsAppearance.tsx b/apps/frontend/src/ui/pages/settings/launcher/SettingsAppearance.tsx index da91e5a2..6baa390f 100644 --- a/apps/frontend/src/ui/pages/settings/launcher/SettingsAppearance.tsx +++ b/apps/frontend/src/ui/pages/settings/launcher/SettingsAppearance.tsx @@ -1,5 +1,7 @@ import { useBeforeLeave } from '@solidjs/router'; -import { PackageIcon, Speedometer04Icon } from '@untitled-theme/icons-solid'; +import { Window } from '@tauri-apps/api/window'; +import { Monitor01Icon, PackageIcon, Speedometer04Icon } from '@untitled-theme/icons-solid'; +import { bridge } from '~imports'; import Dropdown from '~ui/components/base/Dropdown'; import Toggle from '~ui/components/base/Toggle'; import ScrollableContainer from '~ui/components/ScrollableContainer'; @@ -20,10 +22,14 @@ function SettingsAppearance() { setShouldReload(false); location.reload(); } + + if (settings().custom_frame !== undefined) + bridge.commands.setWindowStyle(settings().custom_frame!); }); saveOnLeave(() => ({ disable_animations: settings().disable_animations!, + custom_frame: settings().custom_frame!, })); return ( @@ -59,6 +65,21 @@ function SettingsAppearance() { + } + title="Custom Window Frame" + > + settings().custom_frame ?? true} + onChecked={(value) => { + settings().custom_frame = value; + Window.getCurrent().setDecorations(value); + // setShouldReload(true); + }} + /> + + } diff --git a/apps/frontend/src/utils/browser.ts b/apps/frontend/src/utils/browser.ts index 716ec61f..cba8f15f 100644 --- a/apps/frontend/src/utils/browser.ts +++ b/apps/frontend/src/utils/browser.ts @@ -1,6 +1,6 @@ import type { BrowserListView, PackageType, Providers } from '@onelauncher/client/bindings'; -export const BROWSER_VIEWS: BrowserListView[] = ['grid', 'list', 'preview'] as const; +export const BROWSER_VIEWS: BrowserListView[] = ['grid', 'list'] as const; export interface CategoryItem { display: string; diff --git a/apps/frontend/src/utils/index.ts b/apps/frontend/src/utils/index.ts index e55f8368..43caa421 100644 --- a/apps/frontend/src/utils/index.ts +++ b/apps/frontend/src/utils/index.ts @@ -1,6 +1,6 @@ -import type { Cluster, ImportType, License, Loader, PackageType, Providers, VersionType } from '@onelauncher/client/bindings'; import { DurationFormat } from '@formatjs/intl-durationformat'; import { open } from '@tauri-apps/plugin-shell'; +import type { Cluster, ImportType, License, Loader, PackageType, Providers, VersionType } from '@onelauncher/client/bindings'; export function setAsyncTimeout(ms: number): Promise; export function setAsyncTimeout(callback: () => any, ms: number): Promise; diff --git a/packages/core/src/store/settings.rs b/packages/core/src/store/settings.rs index be403573..ba1320c7 100644 --- a/packages/core/src/store/settings.rs +++ b/packages/core/src/store/settings.rs @@ -63,9 +63,9 @@ pub struct Settings { /// Whether or not to minimize the launcher upon a game launch. #[serde(default)] pub hide_on_launch: bool, - /// Enable/disable advanced rendering and window decorations. + /// Enable/disable custom window decorations. #[serde(default)] - pub rendering: bool, + pub custom_frame: bool, /// Completed onboarding. #[serde(default)] pub onboarding_completed: bool, @@ -127,7 +127,7 @@ impl Settings { debug_mode: false, config_dir: Directories::init_settings_dir(), hide_on_launch: false, - rendering: true, + custom_frame: true, onboarding_completed: false, }; @@ -155,7 +155,6 @@ pub enum BrowserListView { #[default] Grid, List, - Preview, } /// A `OneLauncher` theme managed by the GUI. diff --git a/packages/core/src/utils/mod.rs b/packages/core/src/utils/mod.rs index 78d13300..293d0d95 100644 --- a/packages/core/src/utils/mod.rs +++ b/packages/core/src/utils/mod.rs @@ -8,3 +8,6 @@ pub mod http; pub mod java; pub mod watcher; + +#[cfg(feature = "tauri")] +pub mod window; diff --git a/packages/core/src/utils/window.rs b/packages/core/src/utils/window.rs new file mode 100644 index 00000000..a5579224 --- /dev/null +++ b/packages/core/src/utils/window.rs @@ -0,0 +1,19 @@ +use tauri::WebviewWindow; + +pub fn set_window_styling( + win: &WebviewWindow, + custom: bool, +) -> Result<(), Box> { + win.set_decorations(!custom)?; + + #[cfg(target_os = "macos")] + { + if custom { + win.set_title_bar_style(tauri_utils::TitleBarStyle::Overlay)?; + } else { + win.set_title_bar_style(tauri_utils::TitleBarStyle::Visible)?; + } + } + + Ok(()) +} \ No newline at end of file