Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add settings profiles #1196

Draft
wants to merge 16 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions gui/public/i18n/en/translation.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ settings-sidebar-utils = Utilities
settings-sidebar-serial = Serial console
settings-sidebar-appearance = Appearance
settings-sidebar-notifications = Notifications
settings-sidebar-profiles = Profiles
settings-sidebar-advanced = Advanced

## SteamVR settings
Expand Down Expand Up @@ -604,6 +605,44 @@ 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

## Profile settings
settings-utils-profiles = Profiles
settings-utils-profiles-description = Manage your settings profiles to quickly switch between settings: GUI, tracking, body proportions, etc.

settings-utils-profiles-default = Default profile

settings-utils-profiles-profile = Current profile
settings-utils-profiles-profile-description = Choose a profile to load or save your settings to.

settings-utils-profiles-new = Create new profile
settings-utils-profiles-new-description = Create a new profile with the defaults or your current settings.
settings-utils-profiles-new-label = Create
settings-utils-profiles-modal =
Would you like to use the default settings or copy your current
settings for your new profile?
settings-utils-profiles-modal-default = Default settings
settings-utils-profiles-modal-copy = Copy settings
settings-utils-profiles-modal-cancel = Cancel

settings-utils-profiles-new-cant =
This profile name contains invalid characters or already exists.
Please choose another name.
settings-utils-profiles-new-cant-ok = OK

settings-utils-profiles-delete = Delete profile
settings-utils-profiles-delete-description = Delete the selected profile.
settings-utils-profiles-delete-label = Delete profile
settings-utils-profiles-delete-warning =
<b>Warning:</b> This will delete the selected profile ({ $name }).
Are you sure you want to do this?
settings-utils-profiles-delete-warning-done = Yes
settings-utils-profiles-delete-warning-cancel = Cancel

settings-utils-profiles-delete-cant =
You cannot delete this profile ({ $name }). Please select
another profile to delete.
settings-utils-profiles-delete-cant-ok = OK

## Advanced settings
settings-utils-advanced = Advanced

Expand Down
12 changes: 7 additions & 5 deletions gui/src-tauri/capabilities/migrated.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@
"core:window:allow-show",
"core:window:allow-set-focus",
"core:window:allow-set-decorations",
"store:default",
"os:allow-os-type",
"dialog:allow-save",
"shell:allow-open",
"store:allow-get",
"store:allow-set",
"store:allow-save",
"fs:allow-write-text-file"
"store:default",
"fs:default",
"fs:allow-config-write-recursive",
{
"identifier": "fs:scope",
"allow": [{ "path": "$APP" }, { "path": "$APP/*" }]
}
]
}
10 changes: 6 additions & 4 deletions gui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 { ProfileSettings } from './components/settings/pages/Profiles';
import { AdvancedSettings } from './components/settings/pages/AdvancedSettings';

export const GH_REPO = 'SlimeVR/SlimeVR-Server';
Expand Down Expand Up @@ -111,6 +112,7 @@ function Layout() {
<Route path="osc/vrchat" element={<VRCOSCSettings />} />
<Route path="osc/vmc" element={<VMCSettings />} />
<Route path="interface" element={<InterfaceSettings />} />
<Route path="profiles" element={<ProfileSettings />} />
<Route path="advanced" element={<AdvancedSettings />} />
</Route>
<Route
Expand Down Expand Up @@ -197,7 +199,7 @@ export default function App() {
setUpdateFound(releases[0].tag_name);
}
}
fetchReleases().catch(() => error('failed to fetch releases'));
fetchReleases().catch((e) => error(`Failed to fetch releases: ${e}`));
}, []);

if (isTauri) {
Expand Down Expand Up @@ -237,11 +239,11 @@ export default function App() {
)
);
} else if (eventType === 'error') {
error('Error: %s', s);
error(`Error: ${s}`);
} else if (eventType === 'terminated') {
error('Server Process Terminated: %s', s);
error(`Server Process Terminated: ${s}`);
} else if (eventType === 'other') {
log('Other process event: %s', s);
log(`Other process event: ${s}`);
}
}
);
Expand Down
2 changes: 1 addition & 1 deletion gui/src/components/commons/Dropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export function Dropdown({
// Works but have a slight delay when resizing, kinda looks laggy
// 2 - We close the dropdown on resize.
// We could consider this as the same as clicking outside of the dropdown
// This is the approach choosen RN
// This is the approach chosen RN
setOpen(false);
};

Expand Down
97 changes: 91 additions & 6 deletions gui/src/components/commons/TipBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ import { BulbIcon } from './icon/BulbIcon';
import { WarningIcon } from './icon/WarningIcon';
import { Typography } from './Typography';
import classNames from 'classnames';
import { QuestionIcon } from './icon/QuestionIcon';

/**
* Enabling "whitespace" will respect the newlines and spacing given in the text.
*/

export function TipBox({
children,
Expand Down Expand Up @@ -30,7 +35,7 @@ export function TipBox({
>
<BulbIcon></BulbIcon>
</div>
<div className="flex flex-col">
<div className="flex flex-col justify-center">
<Typography
color="text-accent-background-10"
whitespace={whitespace ? 'whitespace-pre' : undefined}
Expand All @@ -42,20 +47,100 @@ export function TipBox({
);
}

/**
* Will respect new lines and spacing given in text
*/
export function QuestionBox({
children,
hideIcon = false,
whitespace = false,
className,
}: {
children: ReactNode;
hideIcon?: boolean;
whitespace?: boolean;
className?: string;
}) {
return (
<div
className={classNames(
'flex flex-row gap-4 bg-trans-blue-400 p-4 rounded-md',
className
)}
>
<div
className={classNames(
'stroke-background-90 flex flex-col justify-center',
hideIcon && 'hidden'
)}
>
<QuestionIcon width={whitespace ? 36 : 24}></QuestionIcon>
</div>
<div className="flex flex-col justify-center">
<Typography
color="text-background-90"
whitespace={whitespace ? 'whitespace-pre' : undefined}
>
{children}
</Typography>
</div>
</div>
);
}

export function ErrorBox({
children,
whitespace = true,
hideIcon = false,
className,
}: {
children: ReactNode;
whitespace?: boolean;
hideIcon?: boolean;
className?: string;
}) {
return (
<div
className={classNames(
'flex flex-row gap-4 bg-status-critical p-4 rounded-md',
className
)}
>
<div
className={classNames(
'text-background-90 flex flex-col justify-center',
hideIcon && 'hidden'
)}
>
<WarningIcon></WarningIcon>
</div>
<div className="flex flex-col justify-center">
<Typography
color="text-background-90"
whitespace={whitespace ? 'whitespace-pre-line' : undefined}
>
{children}
</Typography>
</div>
</div>
);
}

export function WarningBox({
children,
whitespace = true,
hideIcon = false,
className,
}: {
children: ReactNode;
whitespace?: boolean;
hideIcon?: boolean;
className?: string;
}) {
return (
<div className="flex flex-row gap-4 bg-status-warning p-4 rounded-md">
<div
className={classNames(
'flex flex-row gap-4 bg-status-warning p-4 rounded-md',
className
)}
>
<div
className={classNames(
'text-background-60 flex flex-col justify-center',
Expand All @@ -64,7 +149,7 @@ export function WarningBox({
>
<WarningIcon></WarningIcon>
</div>
<div className="flex flex-col">
<div className="flex flex-col justify-center">
<Typography
color="text-background-60"
whitespace={whitespace ? 'whitespace-pre-line' : undefined}
Expand Down
10 changes: 8 additions & 2 deletions gui/src/components/commons/icon/QuestionIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
export function QuestionIcon({ width = 23 }: { width?: number }) {
export function QuestionIcon({
width = 23,
strokeWidth = 1.5,
}: {
width?: number;
strokeWidth?: number;
}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
strokeWidth={1.5}
strokeWidth={strokeWidth}
width={width}
>
<path
Expand Down
2 changes: 1 addition & 1 deletion gui/src/components/onboarding/NeckWarningModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export function NeckWarningModal({
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
// neck and we haven't showed this warning yet
return (
<BaseModal
isOpen={isOpen}
Expand Down
2 changes: 0 additions & 2 deletions gui/src/components/onboarding/SkipSetupWarningModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ export function SkipSetupWarningModal({
const { l10n } = useLocalization();
const navigate = useNavigate();

// 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}
Expand Down
65 changes: 65 additions & 0 deletions gui/src/components/settings/CreateProfileModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { Button } from '@/components/commons/Button';
import { QuestionBox } from '@/components/commons/TipBox';
import { Localized, useLocalization } from '@fluent/react';
import { BaseModal } from '@/components/commons/BaseModal';
import ReactModal from 'react-modal';

export function CreateProfileModal({
isOpen = true,
onClose,
primary,
secondary,
...props
}: {
/**
* Is the parent/sibling component opened?
*/
isOpen: boolean;
/**
* Function when closing/rejecting the modal
*/
onClose: () => void;
/**
* Function for primary action
*/
primary: () => void;
/**
* Function for secondary action
*/
secondary: () => void;
} & 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-profiles-modal">
<QuestionBox whitespace>
Should the default settings or your current settings be used for
the new profile?
</QuestionBox>
</Localized>

<div className="flex flex-row gap-3 pt-5 place-content-center">
<Button variant="tertiary" onClick={() => primary()}>
{l10n.getString('settings-utils-profiles-modal-default')}
</Button>
<Button variant="tertiary" onClick={() => secondary()}>
{l10n.getString('settings-utils-profiles-modal-copy')}
</Button>
</div>
<Button variant="primary" onClick={onClose}>
{l10n.getString('settings-utils-profiles-modal-cancel')}
</Button>
</div>
</div>
</BaseModal>
);
}
Loading
Loading