Skip to content

Commit

Permalink
feat: Add custom window frame option + some tweaks
Browse files Browse the repository at this point in the history
  • Loading branch information
LynithDev committed Sep 15, 2024
1 parent eafd9ee commit 30b2de6
Show file tree
Hide file tree
Showing 17 changed files with 155 additions and 27 deletions.
2 changes: 2 additions & 0 deletions apps/desktop/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
14 changes: 13 additions & 1 deletion apps/desktop/src/api/commands/mod.rs
Original file line number Diff line number Diff line change
@@ -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::*;
Expand Down Expand Up @@ -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,
]
}};
}
Expand All @@ -100,3 +104,11 @@ pub async fn get_settings() -> Result<Settings, String> {
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())
}
20 changes: 19 additions & 1 deletion apps/desktop/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use api::statics::get_program_info;
use onelauncher::utils::window::set_window_styling;
use tauri::{Emitter, Manager};

pub mod api;
Expand Down Expand Up @@ -91,7 +92,24 @@ pub async fn run_app<F: FnOnce(&tauri::AppHandle<tauri::Wry>) + Send + 'static>(

fn setup(handle: &tauri::AppHandle) -> Result<(), Box<dyn std::error::Error>> {
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(())
}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/ui/components/SettingsRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ function SettingsRow(props: SettingsRowProps) {
</div>

<div class="flex flex-1 flex-col gap-2">
<h3 class="text-lg">{props.title}</h3>
<h3 class="text-lg capitalize">{props.title}</h3>
<p class="text-wrap text-sm">{props.description}</p>
</div>

Expand Down
24 changes: 13 additions & 11 deletions apps/frontend/src/ui/components/WindowFrame.tsx
Original file line number Diff line number Diff line change
@@ -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';

Check failure on line 5 in apps/frontend/src/ui/components/WindowFrame.tsx

View workflow job for this annotation

GitHub Actions / EcmaScript Checks

Expected "solid-js" (type) to come before "solid-js" (external)
import Button from './base/Button';
import Modal, { createModal } from './overlay/Modal';

Expand Down Expand Up @@ -51,17 +51,19 @@ function WindowFrame() {
});

return (
<div class="z-[99999] h-8 w-screen flex flex-row items-center justify-between gap-0.5 bg-page-elevated pr-0.5" data-tauri-drag-region>
<div class="flex flex-row items-center">
<TitlebarButton icon={ChevronLeftIcon} onClick={() => history.back()} />
</div>
<Show when={settings().custom_frame}>
<div class="z-[99999] h-8 w-screen flex flex-row items-center justify-between gap-0.5 bg-page-elevated pr-0.5" data-tauri-drag-region>
<div class="flex flex-row items-center">
<TitlebarButton icon={ChevronLeftIcon} onClick={() => history.back()} />
</div>

<div class="flex flex-row items-center justify-end">
<TitlebarButton icon={MinusIcon} onClick={() => minimize()} />
<TitlebarButton icon={Maximize02Icon} onClick={() => maximize()} />
<TitlebarButton danger icon={XCloseIcon} onClick={() => quit()} />
<div class="flex flex-row items-center justify-end">
<TitlebarButton icon={MinusIcon} onClick={() => minimize()} />
<TitlebarButton icon={Maximize02Icon} onClick={() => maximize()} />
<TitlebarButton danger icon={XCloseIcon} onClick={() => quit()} />
</div>
</div>
</div>
</Show>
);
}

Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/ui/components/base/Button.module.scss
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/ui/components/base/Button.tsx
Original file line number Diff line number Diff line change
@@ -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';

Check failure on line 2 in apps/frontend/src/ui/components/base/Button.tsx

View workflow job for this annotation

GitHub Actions / EcmaScript Checks

Expected "solid-js" (type) to come before "solid-js" (external)
import styles from './Button.module.scss';

type ButtonProps = JSX.ButtonHTMLAttributes<HTMLButtonElement> & ParentProps & {
Expand Down
51 changes: 51 additions & 0 deletions apps/frontend/src/ui/components/content/ProviderIcon.tsx
Original file line number Diff line number Diff line change
@@ -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';

Check failure on line 3 in apps/frontend/src/ui/components/content/ProviderIcon.tsx

View workflow job for this annotation

GitHub Actions / EcmaScript Checks

Expected "@onelauncher/client/bindings" (type) to come before "solid-js" (external)

export function getProviderLogoElement(provider: ManagedPackage | Providers): string | Component {
const providerName = (typeof provider === 'string' ? provider : provider.provider)?.toLowerCase() as Lowercase<Providers>;

// [provider logo, is svg]
const mapping: Record<Lowercase<Providers>, string | Component> = {
modrinth: ModrinthImage,
};

return mapping[providerName];
}

type ProviderIconProps = JSX.HTMLAttributes<HTMLImageElement> & {
provider: Providers | undefined;
};

function ProviderIcon(props: ProviderIconProps) {
const [split, rest] = splitProps(props, ['provider', 'class']);

const Element = () => {
const value = getProviderLogoElement(split.provider!);

return (
<Switch>
<Match when={typeof value === 'string'}>
<img {...rest} {...(split.class ? { class: split.class } : {})} alt={`${split.provider}'s logo`} src={value as string} />
</Match>
<Match when>
{value}
</Match>
</Switch>
);
};

return (
<Show
children={(
<Element />
)}
fallback={(
<div class={`bg-gray-05 ${split.class || ''}`} {...rest as JSX.HTMLAttributes<HTMLDivElement>} />
)}
when={split.provider !== undefined}
/>
);
}

export default ProviderIcon;
2 changes: 1 addition & 1 deletion apps/frontend/src/ui/components/game/LoaderIcon.tsx
Original file line number Diff line number Diff line change
@@ -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';

Check failure on line 6 in apps/frontend/src/ui/components/game/LoaderIcon.tsx

View workflow job for this annotation

GitHub Actions / EcmaScript Checks

Expected "@onelauncher/client/bindings" (type) to come before "solid-js" (external)

export function getLoaderLogoSrc(loader: Cluster | Loader): string {
const loaderName = (typeof loader === 'string' ? loader : loader.meta.loader)?.toLowerCase() as Loader;
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/ui/pages/browser/BrowserMain.tsx
Original file line number Diff line number Diff line change
@@ -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';

Check failure on line 7 in apps/frontend/src/ui/pages/browser/BrowserMain.tsx

View workflow job for this annotation

GitHub Actions / EcmaScript Checks

Expected "@onelauncher/client/bindings" (type) to come before "solid-js" (external)
import { BrowserContent } from './BrowserRoot';

function BrowserMain() {
Expand Down
5 changes: 3 additions & 2 deletions apps/frontend/src/ui/pages/browser/BrowserRoot.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -119,7 +120,6 @@ function BrowserSidebar() {
<Button
buttonStyle="secondary"
children={controller.cluster()?.meta.name || 'None'}
iconLeft={<Settings01Icon />}
onClick={controller.displayClusterSelector}
/>
</div>
Expand All @@ -135,6 +135,7 @@ function BrowserSidebar() {
<For each={PROVIDERS}>
{provider => (
<Dropdown.Row>
<ProviderIcon class="h-4 w-4" provider={provider} />
{provider}
</Dropdown.Row>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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 (
Expand Down Expand Up @@ -59,6 +65,21 @@ function SettingsAppearance() {
</Dropdown>
</SettingsRow>

<SettingsRow
description="Uses custom window frame for the launcher."
icon={<Monitor01Icon />}
title="Custom Window Frame"
>
<Toggle
checked={() => settings().custom_frame ?? true}
onChecked={(value) => {
settings().custom_frame = value;
Window.getCurrent().setDecorations(value);
// setShouldReload(true);
}}
/>
</SettingsRow>

<SettingsRow
description="Disables all animations in the launcher."
icon={<Speedometer04Icon />}
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/utils/browser.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion apps/frontend/src/utils/index.ts
Original file line number Diff line number Diff line change
@@ -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';

Check failure on line 3 in apps/frontend/src/utils/index.ts

View workflow job for this annotation

GitHub Actions / EcmaScript Checks

Expected "@onelauncher/client/bindings" (type) to come before "@tauri-apps/plugin-shell" (external)

export function setAsyncTimeout(ms: number): Promise<void>;
export function setAsyncTimeout(callback: () => any, ms: number): Promise<void>;
Expand Down
7 changes: 3 additions & 4 deletions packages/core/src/store/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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,
};

Expand Down Expand Up @@ -155,7 +155,6 @@ pub enum BrowserListView {
#[default]
Grid,
List,
Preview,
}

/// A `OneLauncher` theme managed by the GUI.
Expand Down
3 changes: 3 additions & 0 deletions packages/core/src/utils/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,6 @@
pub mod http;
pub mod java;
pub mod watcher;

#[cfg(feature = "tauri")]
pub mod window;
19 changes: 19 additions & 0 deletions packages/core/src/utils/window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use tauri::WebviewWindow;

pub fn set_window_styling(
win: &WebviewWindow,
custom: bool,
) -> Result<(), Box<dyn std::error::Error>> {
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(())
}

0 comments on commit 30b2de6

Please sign in to comment.