mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Add OS decorations toggle (#1180)
Co-authored-by: lucas lelievre <loucass003@gmail.com>
This commit is contained in:
@@ -33,7 +33,8 @@
|
||||
"solarxr-protocol": "file:../solarxr-protocol",
|
||||
"three": "^0.163.0",
|
||||
"ts-pattern": "^5.2.0",
|
||||
"typescript": "^5.4.5"
|
||||
"typescript": "^5.4.5",
|
||||
"use-double-tap": "^1.3.6"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "vite --force",
|
||||
|
||||
@@ -450,6 +450,9 @@ settings-interface-appearance-font-os_font = OS font
|
||||
settings-interface-appearance-font-slime_font = Default font
|
||||
settings-interface-appearance-font_size = Base font scaling
|
||||
settings-interface-appearance-font_size-description = This affects the font size of the whole interface except this settings panel.
|
||||
settings-interface-appearance-decorations = Use the system native decorations
|
||||
settings-interface-appearance-decorations-description = This will not render the top bar of the interface and will use the operating system's instead.
|
||||
settings-interface-appearance-decorations-label = Use native decorations
|
||||
|
||||
## Notification settings
|
||||
settings-interface-notifications = Notifications
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
"window:allow-hide",
|
||||
"window:allow-show",
|
||||
"window:allow-set-focus",
|
||||
"window:allow-set-decorations",
|
||||
"shell:allow-open",
|
||||
"store:allow-get",
|
||||
"store:allow-set",
|
||||
|
||||
@@ -15,6 +15,7 @@ pub struct WindowState {
|
||||
height: f64,
|
||||
x: i32,
|
||||
y: i32,
|
||||
decorated: bool,
|
||||
#[serde(skip)]
|
||||
old: bool,
|
||||
}
|
||||
@@ -50,6 +51,8 @@ impl WindowState {
|
||||
window: &Window,
|
||||
ignore_maximized: bool,
|
||||
) -> Result<()> {
|
||||
self.decorated = window.is_decorated()?;
|
||||
|
||||
let maximized = window.is_maximized()?;
|
||||
self.maximized = maximized || (self.maximized && ignore_maximized);
|
||||
// We early return when it's maximized because we dont have to save the state
|
||||
@@ -70,6 +73,8 @@ impl WindowState {
|
||||
}
|
||||
|
||||
pub fn update_window(&self, window: &Window, ignore_maximized: bool) -> Result<()> {
|
||||
window.set_decorations(self.decorated)?;
|
||||
|
||||
let maximized = !ignore_maximized && window.is_maximized()?;
|
||||
if maximized && !self.maximized {
|
||||
window.unmaximize()?;
|
||||
|
||||
@@ -27,6 +27,8 @@ import { TrackersStillOnModal } from './TrackersStillOnModal';
|
||||
import { useConfig } from '@/hooks/config';
|
||||
import { listen } from '@tauri-apps/api/event';
|
||||
import { TrayOrExitModal } from './TrayOrExitModal';
|
||||
import { error } from '@/utils/logging';
|
||||
import { useDoubleTap } from 'use-double-tap';
|
||||
|
||||
export function VersionTag() {
|
||||
return (
|
||||
@@ -62,6 +64,7 @@ export function TopBar({
|
||||
const [localIp, setLocalIp] = useState<string | null>(null);
|
||||
const [showConnectedTrackersWarning, setConnectedTrackerWarning] =
|
||||
useState(false);
|
||||
const [showVersionMobile, setShowVersionMobile] = useState(false);
|
||||
const [showTrayOrExitModal, setShowTrayOrExitModal] = useState(false);
|
||||
const doesMatchSettings = useMatch({
|
||||
path: '/settings/*',
|
||||
@@ -90,6 +93,8 @@ export function TopBar({
|
||||
await closeApp();
|
||||
}
|
||||
};
|
||||
const showVersionBind = useDoubleTap(() => setShowVersionMobile(true));
|
||||
const unshowVersionBind = useDoubleTap(() => setShowVersionMobile(false));
|
||||
|
||||
useEffect(() => {
|
||||
const unlisten = listen('try-close', async () => {
|
||||
@@ -104,6 +109,11 @@ export function TopBar({
|
||||
};
|
||||
}, [config?.useTray, config?.connectedTrackersWarning]);
|
||||
|
||||
useEffect(() => {
|
||||
if (config === null || !isTauri) return;
|
||||
getCurrent().setDecorations(config?.decorations).catch(error);
|
||||
}, [config?.decorations]);
|
||||
|
||||
useEffect(() => {
|
||||
sendRPCPacket(RpcMessage.ServerInfosRequest, new ServerInfosRequestT());
|
||||
}, []);
|
||||
@@ -121,18 +131,20 @@ export function TopBar({
|
||||
<div className="h-[3px]"></div>
|
||||
<div data-tauri-drag-region className="flex gap-2 h-[38px] z-50">
|
||||
<div
|
||||
className="flex px-2 pb-1 mt-3 justify-around z-50"
|
||||
className="flex px-2 py-2 justify-around z-50"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<div className="flex gap-2 mobile:w-5" data-tauri-drag-region>
|
||||
<NavLink
|
||||
to="/"
|
||||
className="flex justify-around flex-col select-all"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<SlimeVRIcon></SlimeVRIcon>
|
||||
</NavLink>
|
||||
{(isTauri || !isMobile) && (
|
||||
<div className="flex gap-2" data-tauri-drag-region>
|
||||
{!config?.decorations && (
|
||||
<NavLink
|
||||
to="/"
|
||||
className="flex justify-around flex-col select-all"
|
||||
data-tauri-drag-region
|
||||
>
|
||||
<SlimeVRIcon></SlimeVRIcon>
|
||||
</NavLink>
|
||||
)}
|
||||
{(isTauri || !isMobile) && !config?.decorations && (
|
||||
<div
|
||||
className={classNames('flex justify-around flex-col')}
|
||||
data-tauri-drag-region
|
||||
@@ -140,7 +152,7 @@ export function TopBar({
|
||||
<Typography>SlimeVR</Typography>
|
||||
</div>
|
||||
)}
|
||||
{!isMobile && (
|
||||
{(!(isMobile && !config?.decorations) || showVersionMobile) && (
|
||||
<>
|
||||
<VersionTag></VersionTag>
|
||||
{doesMatchSettings && (
|
||||
@@ -149,6 +161,7 @@ export function TopBar({
|
||||
'flex justify-around flex-col text-standard-bold text-status-special',
|
||||
'bg-status-special bg-opacity-20 rounded-lg px-3 select-text'
|
||||
)}
|
||||
{...unshowVersionBind}
|
||||
>
|
||||
{localIp || 'unknown local ip'}
|
||||
</div>
|
||||
@@ -192,8 +205,11 @@ export function TopBar({
|
||||
</>
|
||||
)}
|
||||
|
||||
{!isTauri && (
|
||||
<div className="flex flex-row gap-2">
|
||||
{!isTauri && !showVersionMobile && !config?.decorations && (
|
||||
<div
|
||||
className="flex flex-row gap-2"
|
||||
{...(doesMatchSettings ? showVersionBind : {})}
|
||||
>
|
||||
<div
|
||||
className="flex justify-around flex-col xs:hidden"
|
||||
data-tauri-drag-region
|
||||
@@ -230,7 +246,7 @@ export function TopBar({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isTauri && (
|
||||
{isTauri && !config?.decorations && (
|
||||
<>
|
||||
<div
|
||||
className="flex items-center justify-center hover:bg-background-60 rounded-full w-7 h-7"
|
||||
|
||||
@@ -24,6 +24,7 @@ interface InterfaceSettingsForm {
|
||||
showNavbarOnboarding: boolean;
|
||||
textSize: number;
|
||||
fonts: string;
|
||||
decorations: boolean;
|
||||
};
|
||||
notifications: {
|
||||
watchNewDevices: boolean;
|
||||
@@ -48,6 +49,7 @@ export function InterfaceSettings() {
|
||||
config?.showNavbarOnboarding ?? defaultConfig.showNavbarOnboarding,
|
||||
textSize: config?.textSize ?? defaultConfig.textSize,
|
||||
fonts: config?.fonts.join(',') ?? defaultConfig.fonts.join(','),
|
||||
decorations: config?.decorations ?? defaultConfig.decorations,
|
||||
},
|
||||
notifications: {
|
||||
watchNewDevices:
|
||||
@@ -78,6 +80,7 @@ export function InterfaceSettings() {
|
||||
connectedTrackersWarning: values.notifications.connectedTrackersWarning,
|
||||
useTray: values.notifications.useTray,
|
||||
discordPresence: values.notifications.discordPresence,
|
||||
decorations: values.appearance.decorations,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -268,6 +271,28 @@ export function InterfaceSettings() {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Typography bold>
|
||||
{l10n.getString('settings-interface-appearance-decorations')}
|
||||
</Typography>
|
||||
<div className="flex flex-col pt-1 pb-2">
|
||||
<Typography color="secondary">
|
||||
{l10n.getString(
|
||||
'settings-interface-appearance-decorations-description'
|
||||
)}
|
||||
</Typography>
|
||||
</div>
|
||||
<div className="grid sm:grid-cols-2 pb-4">
|
||||
<CheckBox
|
||||
variant="toggle"
|
||||
control={control}
|
||||
outlined
|
||||
name="appearance.decorations"
|
||||
label={l10n.getString(
|
||||
'settings-interface-appearance-decorations-label'
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="pb-4">
|
||||
<Typography bold>
|
||||
{l10n.getString('settings-general-interface-theme')}
|
||||
|
||||
@@ -37,6 +37,7 @@ export interface Config {
|
||||
mirrorView: boolean;
|
||||
assignMode: AssignMode;
|
||||
discordPresence: boolean;
|
||||
decorations: boolean;
|
||||
showNavbarOnboarding: boolean;
|
||||
}
|
||||
|
||||
@@ -63,6 +64,7 @@ export const defaultConfig: Omit<Config, 'devSettings'> = {
|
||||
mirrorView: true,
|
||||
assignMode: AssignMode.Core,
|
||||
discordPresence: false,
|
||||
decorations: false,
|
||||
showNavbarOnboarding: true,
|
||||
};
|
||||
|
||||
|
||||
12
pnpm-lock.yaml
generated
12
pnpm-lock.yaml
generated
@@ -110,6 +110,9 @@ importers:
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
use-double-tap:
|
||||
specifier: ^1.3.6
|
||||
version: 1.3.6(react@18.3.1)
|
||||
devDependencies:
|
||||
'@dword-design/eslint-plugin-import-alias':
|
||||
specifier: ^4.0.9
|
||||
@@ -2955,6 +2958,11 @@ packages:
|
||||
uri-js@4.4.1:
|
||||
resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==}
|
||||
|
||||
use-double-tap@1.3.6:
|
||||
resolution: {integrity: sha512-zWmzlihSTuLJpT+YJqhVUySV8UNvmdmaXokBEIh+FxR4m/vaSk2cS5hlqEPDj64rmkHlL7zfRTrJPw30Jd0OZA==}
|
||||
peerDependencies:
|
||||
react: '>=16.8.0'
|
||||
|
||||
use-sync-external-store@1.2.0:
|
||||
resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==}
|
||||
peerDependencies:
|
||||
@@ -6122,6 +6130,10 @@ snapshots:
|
||||
dependencies:
|
||||
punycode: 2.3.1
|
||||
|
||||
use-double-tap@1.3.6(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
use-sync-external-store@1.2.0(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
|
||||
Reference in New Issue
Block a user