Add settings reset & advanced section (#1154)

Co-authored-by: Uriel <imurx@proton.me>
Co-authored-by: Butterscotch! <5095026+ButterscotchV@users.noreply.github.com>
Co-authored-by: lucas lelievre <loucass003@gmail.com>
This commit is contained in:
JovannMC
2024-10-09 16:09:06 +00:00
committed by GitHub
parent ca13ca5fb4
commit a2d842d8cc
14 changed files with 349 additions and 18 deletions

View File

@@ -280,6 +280,7 @@ settings-sidebar-utils = Utilities
settings-sidebar-serial = Serial console
settings-sidebar-appearance = Appearance
settings-sidebar-notifications = Notifications
settings-sidebar-advanced = Advanced
## SteamVR settings
settings-general-steamvr = SteamVR
@@ -603,6 +604,32 @@ settings-osc-vmc-mirror_tracking = Mirror tracking
settings-osc-vmc-mirror_tracking-description = Mirror the tracking horizontally.
settings-osc-vmc-mirror_tracking-label = Mirror tracking
## Advanced settings
settings-utils-advanced = Advanced
settings-utils-advanced-reset-gui = Reset GUI settings
settings-utils-advanced-reset-gui-description = Restore the default settings for the interface.
settings-utils-advanced-reset-gui-label = Reset GUI
settings-utils-advanced-reset-server = Reset tracking settings
settings-utils-advanced-reset-server-description = Restore the default settings for the tracking.
settings-utils-advanced-reset-server-label = Reset tracking
settings-utils-advanced-reset-all = Reset all settings
settings-utils-advanced-reset-all-description = Restore the default settings for both the interface and tracking.
settings-utils-advanced-reset-all-label = Reset all
settings-utils-advanced-reset_warning =
<b>Warning:</b> This will reset { $type ->
[gui] your GUI
[server] your tracking
*[all] all your
} settings to the defaults.
Are you sure you want to do this?
settings-utils-advanced-reset_warning-reset = Reset settings
settings-utils-advanced-reset_warning-cancel = Cancel
settings-utils-advanced-open_data = Data folder
settings-utils-advanced-open_data-description = Open SlimeVR's data folder in file explorer, containing config and log files.
settings-utils-advanced-open_data-label = Open folder
## Setup/onboarding menu
onboarding-skip = Skip setup
onboarding-continue = Continue
@@ -810,11 +837,11 @@ onboarding-choose_mounting = What mounting calibration method to use?
# Multiline text
onboarding-choose_mounting-description = Mounting orientation corrects for the placement of trackers on your body.
onboarding-choose_mounting-auto_mounting = Automatic mounting
# Italized text
# Italicized text
onboarding-choose_mounting-auto_mounting-label-v2 = Recommended
onboarding-choose_mounting-auto_mounting-description = This will automatically detect the mounting orientations for all of your trackers from 2 poses
onboarding-choose_mounting-manual_mounting = Manual mounting
# Italized text
# Italicized text
onboarding-choose_mounting-manual_mounting-label-v2 = Might not be precise enough
onboarding-choose_mounting-manual_mounting-description = This will let you choose the mounting orientation manually for each tracker
# Multiline text
@@ -858,14 +885,14 @@ onboarding-choose_proportions-description-v1 = Body proportions are used to know
When proportions of your body don't match the ones saved, your tracking precision will be worse and you will notice things like skating or sliding, or your body not matching your avatar well.
<b>You only need to measure your body once!</b> Unless they are wrong or your body has changed, then you don't need to do them again.
onboarding-choose_proportions-auto_proportions = Automatic proportions
# Italized text
# Italicized text
onboarding-choose_proportions-auto_proportions-subtitle = Recommended
onboarding-choose_proportions-auto_proportions-descriptionv3 =
This will guess your proportions by recording a sample of your movements and passing it through an algorithm.
<b>This requires having your headset (HMD) connected to SlimeVR and on your head!</b>
onboarding-choose_proportions-manual_proportions = Manual proportions
# Italized text
# Italicized text
onboarding-choose_proportions-manual_proportions-subtitle = For small touches
onboarding-choose_proportions-manual_proportions-description = This will let you adjust your proportions manually by modifying them directly
onboarding-choose_proportions-export = Export proportions

View File

@@ -73,7 +73,7 @@
"all": true
},
"shell": {
"open": true
"open": "^((https?://\\w+)|(file://)).+"
},
"window": {
"close": true,

View File

@@ -55,6 +55,7 @@ import { AppLayout } from './AppLayout';
import { Preload } from './components/Preload';
import { UnknownDeviceModal } from './components/UnknownDeviceModal';
import { useDiscordPresence } from './hooks/discord-presence';
import { AdvancedSettings } from './components/settings/pages/AdvancedSettings';
export const GH_REPO = 'SlimeVR/SlimeVR-Server';
export const VersionContext = createContext('');
@@ -110,6 +111,7 @@ function Layout() {
<Route path="osc/vrchat" element={<VRCOSCSettings />} />
<Route path="osc/vmc" element={<VMCSettings />} />
<Route path="interface" element={<InterfaceSettings />} />
<Route path="advanced" element={<AdvancedSettings />} />
</Route>
<Route
path="/onboarding"

View File

@@ -0,0 +1,16 @@
export function BugIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="size-6"
>
<path
fillRule="evenodd"
d="M8.478 1.6a.75.75 0 0 1 .273 1.026 3.72 3.72 0 0 0-.425 1.121c.058.058.118.114.18.168A4.491 4.491 0 0 1 12 2.25c1.413 0 2.673.651 3.497 1.668.06-.054.12-.11.178-.167a3.717 3.717 0 0 0-.426-1.125.75.75 0 1 1 1.298-.752 5.22 5.22 0 0 1 .671 2.046.75.75 0 0 1-.187.582c-.241.27-.505.52-.787.749a4.494 4.494 0 0 1 .216 2.1c-.106.792-.753 1.295-1.417 1.403-.182.03-.364.057-.547.081.152.227.273.476.359.742a23.122 23.122 0 0 0 3.832-.803 23.241 23.241 0 0 0-.345-2.634.75.75 0 0 1 1.474-.28c.21 1.115.348 2.256.404 3.418a.75.75 0 0 1-.516.75c-1.527.499-3.119.854-4.76 1.049-.074.38-.22.735-.423 1.05 2.066.209 4.058.672 5.943 1.358a.75.75 0 0 1 .492.75 24.665 24.665 0 0 1-1.189 6.25.75.75 0 0 1-1.425-.47 23.14 23.14 0 0 0 1.077-5.306c-.5-.169-1.009-.32-1.524-.455.068.234.104.484.104.746 0 3.956-2.521 7.5-6 7.5-3.478 0-6-3.544-6-7.5 0-.262.037-.511.104-.746-.514.135-1.022.286-1.522.455.154 1.838.52 3.616 1.077 5.307a.75.75 0 1 1-1.425.468 24.662 24.662 0 0 1-1.19-6.25.75.75 0 0 1 .493-.749 24.586 24.586 0 0 1 4.964-1.24h.01c.321-.046.644-.085.969-.118a2.983 2.983 0 0 1-.424-1.05 24.614 24.614 0 0 1-4.76-1.05.75.75 0 0 1-.516-.75c.057-1.16.194-2.302.405-3.417a.75.75 0 0 1 1.474.28c-.164.862-.28 1.74-.345 2.634 1.237.371 2.517.642 3.832.803.085-.266.207-.515.359-.742a18.698 18.698 0 0 1-.547-.08c-.664-.11-1.311-.612-1.417-1.404a4.535 4.535 0 0 1 .217-2.103 6.788 6.788 0 0 1-.788-.751.75.75 0 0 1-.187-.583 5.22 5.22 0 0 1 .67-2.04.75.75 0 0 1 1.026-.273Z"
clipRule="evenodd"
/>
</svg>
);
}

View File

@@ -19,14 +19,12 @@ export function HandsWarningModal({
*/
onClose: () => void;
/**
* Function when you press `i understand`
* Function when you press `Yes`
*/
accept: () => void;
} & ReactModal.Props) {
const { l10n } = useLocalization();
// isOpen is checked by checking if the parent modal is opened + our bodyPart is the
// neck and we havent showed this warning yet
return (
<BaseModal
isOpen={isOpen}

View File

@@ -40,6 +40,10 @@ export function SettingSelectorMobile() {
label: l10n.getString('settings-sidebar-serial'),
value: { url: '/settings/serial' },
},
{
label: l10n.getString('settings-sidebar-advanced'),
value: { url: '/settings/advanced' },
},
];
const { control, watch, handleSubmit, setValue } = useForm<{

View File

@@ -0,0 +1,73 @@
import { Button } from '@/components/commons/Button';
import { WarningBox } from '@/components/commons/TipBox';
import { Localized, useLocalization } from '@fluent/react';
import { BaseModal } from '@/components/commons/BaseModal';
import ReactModal from 'react-modal';
export function SettingsResetModal({
isOpen = true,
onClose,
accept,
variant,
...props
}: {
/**
* Is the parent/sibling component opened?
*/
isOpen: boolean;
/**
* Function to trigger when the warning hasn't been accepted
*/
onClose: () => void;
/**
* Function when you press `Reset settings`
*/
accept: () => void;
/**
* Type of reset
*/
variant: 'gui' | 'server' | 'all';
} & ReactModal.Props) {
const { l10n } = useLocalization();
return (
<BaseModal
isOpen={isOpen}
shouldCloseOnOverlayClick
onRequestClose={onClose}
className={props.className}
overlayClassName={props.overlayClassName}
>
<div className="flex w-full h-full flex-col ">
<div className="flex flex-col flex-grow items-center gap-3">
<Localized
id="settings-utils-advanced-reset_warning"
elems={{ b: <b></b> }}
vars={{ type: variant }}
>
<WarningBox>
<b>Warning:</b> This will reset your {variant} settings to the
defaults.
<br />
Are you sure you want to do this?
</WarningBox>
</Localized>
<div className="flex flex-row gap-3 pt-5 place-content-center">
<Button variant="primary" onClick={onClose}>
{l10n.getString('settings-utils-advanced-reset_warning-cancel')}
</Button>
<Button
variant="tertiary"
onClick={() => {
accept();
}}
>
{l10n.getString('settings-utils-advanced-reset_warning-reset')}
</Button>
</div>
</div>
</div>
</BaseModal>
);
}

View File

@@ -41,6 +41,7 @@ export function SettingsLink({
export function SettingsSidebar() {
const { l10n } = useLocalization();
return (
<div className="flex flex-col px-5 py-5 gap-3 overflow-y-auto bg-background-70 rounded-lg h-full">
<Typography variant="main-title">
@@ -100,6 +101,11 @@ export function SettingsSidebar() {
{l10n.getString('settings-sidebar-serial')}
</SettingsLink>
</div>
<div className="flex flex-col gap-2">
<SettingsLink to="/settings/advanced">
{l10n.getString('settings-sidebar-advanced')}
</SettingsLink>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,190 @@
import { useLocalization } from '@fluent/react';
import { useState } from 'react';
import { Typography } from '@/components/commons/Typography';
import {
SettingsPageLayout,
SettingsPagePaneLayout,
} from '@/components/settings/SettingsPageLayout';
import { BugIcon } from '@/components/commons/icon/BugIcon';
import { Button } from '@/components/commons/Button';
import { SettingsResetModal } from '@/components/settings/SettingsResetModal';
import { open } from '@tauri-apps/plugin-shell';
import { error } from '@/utils/logging';
import { appConfigDir } from '@tauri-apps/api/path';
import { defaultConfig as defaultGUIConfig, useConfig } from '@/hooks/config';
import { defaultValues as defaultDevConfig } from '@/components/widgets/DeveloperModeWidget';
import { RpcMessage, SettingsResetRequestT } from 'solarxr-protocol';
import { useWebsocketAPI } from '@/hooks/websocket-api';
function guiDefaults() {
// Destructure the properties to exclude "lang"
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { lang, ...guiDefaults } = defaultGUIConfig;
// Include "devSettings" which has all the properties of "defaultDevConfig"
// @ts-expect-error "devSettings" is not in the "guiDefaults" object but we want to include it (from "defaultDevConfig")
guiDefaults.devSettings = defaultDevConfig;
return guiDefaults;
}
export function AdvancedSettings() {
const { l10n } = useLocalization();
const { setConfig } = useConfig();
const [showWarningGUI, setShowWarningGUI] = useState(false);
const [showWarningServer, setShowWarningServer] = useState(false);
const [showWarningAll, setShowWarningAll] = useState(false);
const { sendRPCPacket } = useWebsocketAPI();
const openConfigFolder = async () => {
try {
const configPath = await appConfigDir();
await open('file://' + configPath);
} catch (err) {
error('Failed to open config folder:', err);
}
};
return (
<SettingsPageLayout>
<form className="flex flex-col gap-2 w-full">
<SettingsPagePaneLayout icon={<BugIcon></BugIcon>} id="advanced">
<>
<Typography variant="main-title">
{l10n.getString('settings-utils-advanced')}
</Typography>
<div className="grid gap-4 mobile:gap-6">
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
{l10n.getString('settings-utils-advanced-reset-gui')}
</Typography>
<div className="flex flex-col pt-1">
<Typography color="secondary">
{l10n.getString(
'settings-utils-advanced-reset-gui-description'
)}
</Typography>
</div>
</div>
<div className="flex flex-col">
<Button
variant="secondary"
onClick={() => setShowWarningGUI(true)}
>
{l10n.getString('settings-utils-advanced-reset-gui-label')}
</Button>
<SettingsResetModal
accept={() => {
setConfig(guiDefaults());
setShowWarningGUI(false);
}}
onClose={() => setShowWarningGUI(false)}
isOpen={showWarningGUI}
variant="gui"
></SettingsResetModal>
</div>
</div>
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
{l10n.getString('settings-utils-advanced-reset-server')}
</Typography>
<div className="flex flex-col pt-1">
<Typography color="secondary">
{l10n.getString(
'settings-utils-advanced-reset-server-description'
)}
</Typography>
</div>
</div>
<div className="flex flex-col">
<Button
variant="secondary"
onClick={() => setShowWarningServer(true)}
>
{l10n.getString(
'settings-utils-advanced-reset-server-label'
)}
</Button>
<SettingsResetModal
accept={() => {
sendRPCPacket(
RpcMessage.SettingsResetRequest,
new SettingsResetRequestT()
);
setShowWarningServer(false);
}}
onClose={() => setShowWarningServer(false)}
isOpen={showWarningServer}
variant="server"
></SettingsResetModal>
</div>
</div>
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
{l10n.getString('settings-utils-advanced-reset-all')}
</Typography>
<div className="flex flex-col pt-1">
<Typography color="secondary">
{l10n.getString(
'settings-utils-advanced-reset-all-description'
)}
</Typography>
</div>
</div>
<div className="flex flex-col">
<Button
variant="secondary"
onClick={() => setShowWarningAll(true)}
>
{l10n.getString('settings-utils-advanced-reset-all-label')}
</Button>
<SettingsResetModal
accept={() => {
sendRPCPacket(
RpcMessage.SettingsResetRequest,
new SettingsResetRequestT()
);
setConfig(guiDefaults());
setShowWarningAll(false);
}}
onClose={() => setShowWarningAll(false)}
isOpen={showWarningAll}
variant="all"
></SettingsResetModal>
</div>
</div>
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
{l10n.getString('settings-utils-advanced-open_data')}
</Typography>
<div className="flex flex-col pt-1">
<Typography color="secondary">
{l10n.getString(
'settings-utils-advanced-open_data-description'
)}
</Typography>
</div>
</div>
<div className="flex flex-col">
<Button variant="secondary" onClick={openConfigFolder}>
{l10n.getString('settings-utils-advanced-open_data-label')}
</Button>
</div>
</div>
</div>
</>
</SettingsPagePaneLayout>
</form>
</SettingsPageLayout>
);
}

View File

@@ -98,6 +98,7 @@ export function InterfaceSettings() {
<SettingsPageLayout>
<form
className="flex flex-col gap-2 w-full"
// Don't resize the font size for this page because you have access to font resizing on it and we don't want to break the layout just in case
style={
{
'--font-size': '12rem',

View File

@@ -16,6 +16,16 @@ export interface DeveloperModeWidgetForm {
moreInfo: boolean;
}
export const defaultValues: DeveloperModeWidgetForm = {
highContrast: false,
preciseRotation: false,
fastDataFeed: false,
filterSlimesAndHMD: false,
sortByName: false,
rawSlimeRotation: false,
moreInfo: false,
};
export function DeveloperModeWidget() {
const { l10n } = useLocalization();
const { config, setConfig } = useConfig();
@@ -23,15 +33,7 @@ export function DeveloperModeWidget() {
const { reset, control, handleSubmit, watch } =
useForm<DeveloperModeWidgetForm>({
defaultValues: {
highContrast: false,
preciseRotation: false,
fastDataFeed: false,
filterSlimesAndHMD: false,
sortByName: false,
rawSlimeRotation: false,
moreInfo: false,
},
defaultValues: defaultValues,
});
useEffect(() => {

View File

@@ -139,6 +139,11 @@ public class ConfigManager {
}
}
public void resetConfig() {
this.vrConfig = new VRConfig();
saveConfig();
}
public VRConfig getVrConfig() {
return vrConfig;
}

View File

@@ -33,6 +33,9 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) {
messageHeader,
)
}
rpcHandler.registerPacketListener(RpcMessage.SettingsResetRequest) { conn: GenericConnection, messageHeader: RpcMessageHeader? ->
this.onSettingsResetRequest(conn, messageHeader)
}
}
fun onSettingsRequest(conn: GenericConnection, messageHeader: RpcMessageHeader?) {
@@ -345,6 +348,10 @@ class RPCSettingsHandler(var rpcHandler: RPCHandler, var api: ProtocolAPI) {
api.server.configManager.saveConfig()
}
fun onSettingsResetRequest(conn: GenericConnection, messageHeader: RpcMessageHeader?) {
api.server.configManager.resetConfig()
}
companion object {
fun sendSteamVRUpdatedSettings(api: ProtocolAPI, rpcHandler: RPCHandler) {
val fbb = FlatBufferBuilder(32)