Update to latest GUI dependencies (#905)

This commit is contained in:
Uriel
2024-04-04 16:22:51 -03:00
committed by GitHub
parent be9166881a
commit 78caab1cd4
35 changed files with 4621 additions and 2640 deletions

View File

@@ -79,6 +79,11 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'
# Tauri has a broken cache issue in windows, let's clean it for now
- name: Clean cache in Windows (Fixes tauri-apps/tauri#9045)
if: matrix.os == 'windows-latest'
run: cargo clean
- name: Build
run: |
pnpm i

View File

@@ -320,6 +320,10 @@ jobs:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Clean cache in Windows (Fixes tauri-apps/tauri#9045)
if: matrix.os == 'windows-latest'
run: cargo clean
- name: Build
run: |
pnpm i

2551
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,9 +9,8 @@ members = ["gui/src-tauri"]
[workspace.package]
edition = "2021"
license = "MIT OR Apache-2.0"
rust-version = "1.65" # This version stabilized GATs and let-else
rust-version = "1.75" # This version stabilized GATs and let-else
repository = "https://github.com/SlimeVR/SlimeVR-Server"
[profile.release]
lto = "thin"
strip = "debuginfo" # Only affects Unix binaries with DWARF

View File

@@ -117,7 +117,7 @@
enable = true;
toolchain = fenixpkgs.fromToolchainName {
name = rust_toolchain.toolchain.channel;
sha256 = "sha256-rLP8+fTxnPHoR96ZJiCa/5Ans1OojI7MLsmSqR2ip8o=";
sha256 = "sha256-3St/9/UKo/6lz2Kfq2VmlzHyufduALpiIKaaKX4Pq0g=";
};
components = rust_toolchain.toolchain.components;
};

View File

@@ -3,53 +3,51 @@
"version": "0.5.1",
"private": true,
"dependencies": {
"@fluent/bundle": "^0.17.1",
"@fluent/react": "^0.14.1",
"@fontsource/poppins": "^4.5.8",
"@formatjs/intl-localematcher": "^0.2.32",
"@react-three/drei": "^9.80.3",
"@react-three/fiber": "^8.13.6",
"@tauri-apps/api": "=2.0.0-alpha.8",
"@tauri-apps/plugin-app": "=2.0.0-alpha.1",
"@tauri-apps/plugin-dialog": "=2.0.0-alpha.1",
"@tauri-apps/plugin-fs": "=2.0.0-alpha.1",
"@tauri-apps/plugin-os": "=2.0.0-alpha.2",
"@tauri-apps/plugin-shell": "=2.0.0-alpha.1",
"@tauri-apps/plugin-store": "=2.0.0-alpha.1",
"@tauri-apps/plugin-window": "=2.0.0-alpha.1",
"@vitejs/plugin-react": "^3.0.0",
"browser-fs-access": "^0.34.1",
"browserslist": "^4.18.1",
"classnames": "^2.3.1",
"eslint-config-react-app": "^7.0.0",
"@fluent/bundle": "^0.18.0",
"@fluent/react": "^0.15.2",
"@fontsource/poppins": "^5.0.12",
"@formatjs/intl-localematcher": "^0.5.4",
"@react-three/drei": "^9.97.0",
"@react-three/fiber": "^8.15.16",
"@tauri-apps/api": "=2.0.0-beta.7",
"@tauri-apps/plugin-dialog": "=2.0.0-beta.2",
"@tauri-apps/plugin-fs": "=2.0.0-beta.2",
"@tauri-apps/plugin-os": "=2.0.0-beta.2",
"@tauri-apps/plugin-shell": "=2.0.0-beta.2",
"@tauri-apps/plugin-store": "=2.0.0-beta.2",
"@vitejs/plugin-react": "^4.2.1",
"browser-fs-access": "^0.35.0",
"browserslist": "^4.23.0",
"classnames": "^2.5.1",
"eslint-config-react-app": "^7.0.1",
"flatbuffers": "^22.10.26",
"identity-obj-proxy": "^3.0.0",
"intl-pluralrules": "^1.3.1",
"ip-num": "^1.4.1",
"intl-pluralrules": "^2.0.1",
"ip-num": "^1.5.1",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^7.0.1",
"postcss-preset-env": "^9.5.2",
"prompts": "^2.4.2",
"react": "^18.0.0",
"react-dev-utils": "^12.0.0",
"react-dom": "^18.0.0",
"react-error-boundary": "^4.0.12",
"react": "^18.2.0",
"react-dev-utils": "^12.0.1",
"react-dom": "^18.2.0",
"react-error-boundary": "^4.0.13",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.29.0",
"react-modal": "^3.15.1",
"react-responsive": "^9.0.2",
"react-router-dom": "^6.2.2",
"semver": "^7.5.3",
"react-hook-form": "^7.51.0",
"react-modal": "^3.16.1",
"react-responsive": "^10.0.0",
"react-router-dom": "^6.22.3",
"semver": "^7.6.0",
"solarxr-protocol": "file:../solarxr-protocol",
"three": "^0.155.0",
"ts-pattern": "^5.0.1",
"typescript": "^5.1.6"
"three": "^0.161.0",
"ts-pattern": "^5.0.8",
"typescript": "^5.4.3"
},
"scripts": {
"start": "vite --force",
"build": "vite build",
"dev": "tauri dev",
"skipbundler": "tauri build -b none",
"skipbundler": "tauri build --no-bundle",
"tauri": "tauri",
"lint": "tsc --noEmit && eslint --max-warnings=0 \"src/**/*.{js,jsx,ts,tsx,json}\" && prettier --check \"src/**/*.{js,jsx,ts,tsx,css,md,json}\"",
"lint:fix": "tsc --noEmit && eslint --fix --max-warnings=0 \"src/**/*.{js,jsx,ts,tsx,json}\" && pnpm run format",
@@ -75,33 +73,33 @@
]
},
"devDependencies": {
"@dword-design/eslint-plugin-import-alias": "^4.0.8",
"@tailwindcss/forms": "^0.5.3",
"@tauri-apps/cli": "=2.0.0-alpha.17",
"@types/file-saver": "^2.0.5",
"@types/react": "^18.0.25",
"@types/react-dom": "^18.0.5",
"@types/react-helmet": "^6.1.6",
"@types/react-modal": "3.13.1",
"@types/semver": "^7.5.4",
"@types/three": "^0.155.0",
"@typescript-eslint/eslint-plugin": "^5.60.1",
"@typescript-eslint/parser": "^5.60.1",
"autoprefixer": "^10.4.4",
"@dword-design/eslint-plugin-import-alias": "^4.0.9",
"@tailwindcss/forms": "^0.5.7",
"@tauri-apps/cli": "=2.0.0-beta.12",
"@types/file-saver": "^2.0.7",
"@types/react": "^18.2.73",
"@types/react-dom": "^18.2.23",
"@types/react-helmet": "^6.1.11",
"@types/react-modal": "3.16.3",
"@types/semver": "^7.5.8",
"@types/three": "^0.163.0",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"autoprefixer": "^10.4.19",
"cross-env": "^7.0.3",
"eslint": "^8.44.0",
"eslint": "^8.57.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-import-resolver-typescript": "^3.5.5",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.2",
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.31",
"prettier": "^2.8.8",
"pretty-quick": "^3.1.3",
"rollup-plugin-visualizer": "^5.9.2",
"tailwind-gradient-mask-image": "^1.0.0",
"tailwindcss": "^3.3.2",
"vite": "^4.3.9"
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"pretty-quick": "^4.0.0",
"rollup-plugin-visualizer": "^5.12.0",
"tailwind-gradient-mask-image": "^1.2.0",
"tailwindcss": "^3.4.3",
"vite": "^5.2.7"
}
}

View File

@@ -3,3 +3,4 @@
/target/
WixTools
src/JavaVersion.class
/gen/schemas

View File

@@ -21,38 +21,37 @@ default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
[build-dependencies]
tauri-build = { version = "2.0.0-alpha", features = [] }
cfg_aliases = "0.1"
shadow-rs = "0.23"
tauri-build = { version = "=2.0.0-beta.11", features = [] }
cfg_aliases = "0.2"
shadow-rs = "0.27"
[dependencies]
serde_json = "1"
serde = { version = "1", features = ["derive"] }
tauri = { version = "2.0.0-alpha", features = ["tray-icon", "devtools", "icon-png"] }
tauri-runtime = "1.0.0-alpha"
tauri-plugin-dialog = "2.0.0-alpha"
tauri-plugin-fs = "2.0.0-alpha"
tauri-plugin-os = "2.0.0-alpha"
tauri-plugin-shell = "2.0.0-alpha"
tauri-plugin-store = "=2.0.0-alpha.1"
tauri-plugin-window = { version = "2.0.0-alpha", features = ["devtools"] }
flexi_logger = "0.25"
tauri = { version = "=2.0.0-beta.14", features = ["devtools", "tray-icon", "image-png"] }
tauri-runtime = "=2.0.0-beta.11"
tauri-plugin-dialog = "=2.0.0-beta.4"
tauri-plugin-fs = "=2.0.0-beta.4"
tauri-plugin-os = "=2.0.0-beta.3"
tauri-plugin-shell = "=2.0.0-beta.3"
tauri-plugin-store = "=2.0.0-beta.4"
flexi_logger = "0.28"
log-panics = { version = "2", features = ["with-backtrace"] }
log = "0.4"
clap = { version = "4.0.29", features = ["derive"] }
clap-verbosity-flag = "2"
rand = "0.8.5"
tempfile = "3"
which = "4.3"
which = "6.0"
glob = "0.3"
open = "5"
shadow-rs = { version = "0.23", default-features = false }
shadow-rs = { version = "0.27", default-features = false }
const_format = "0.2.30"
cfg-if = "1"
color-eyre = "0.6"
rfd = "0.11.4"
rfd = { version = "0.14", features = ["gtk3"], default-features = false }
dirs-next = "2.0.0"
[target.'cfg(windows)'.dependencies]
win32job = "1"
winreg = "0.50"
winreg = "0.52"

View File

@@ -0,0 +1,28 @@
{
"identifier": "migrated",
"description": "permissions that were migrated from v1",
"local": true,
"windows": [
"main"
],
"permissions": [
"path:default",
"event:default",
"window:default",
"app:default",
"resources:default",
"menu:default",
"tray:default",
"store:default",
"os:allow-os-type",
"webview:default",
"dialog:allow-save",
"window:allow-close",
"window:allow-toggle-maximize",
"window:allow-minimize",
"window:allow-start-dragging",
"shell:allow-open",
"store:allow-get",
"store:allow-set"
]
}

View File

@@ -70,20 +70,19 @@ fn main() -> Result<()> {
use flexi_logger::{
Age, Cleanup, Criterion, Duplicate, FileSpec, Logger, Naming, WriteMode,
};
use tauri::path::Error;
use tauri::Error;
// Based on https://docs.rs/tauri/2.0.0-alpha.10/src/tauri/path/desktop.rs.html#238-256
#[cfg(target_os = "macos")]
let path = dirs_next::home_dir().ok_or(Error::UnknownPath).map(|dir| {
dir.join("Library/Logs")
.join(&tauri_context.config().tauri.bundle.identifier)
.join(&tauri_context.config().identifier)
});
#[cfg(not(target_os = "macos"))]
let path = dirs_next::data_dir().ok_or(Error::UnknownPath).map(|dir| {
dir.join(&tauri_context.config().tauri.bundle.identifier)
.join("logs")
});
let path = dirs_next::data_dir()
.ok_or(Error::UnknownPath)
.map(|dir| dir.join(&tauri_context.config().identifier).join("logs"));
Logger::try_with_env_or_str("info")?
.log_to_file(
@@ -121,7 +120,9 @@ fn main() -> Result<()> {
if !webview2_exists() {
// This makes a dialog appear which let's you press Ok or Cancel
// If you press Ok it will open the SlimeVR installer documentation
use rfd::{MessageButtons, MessageDialog, MessageLevel};
use rfd::{
MessageButtons, MessageDialog, MessageDialogResult, MessageLevel,
};
let confirm = MessageDialog::new()
.set_title("SlimeVR")
@@ -129,7 +130,7 @@ fn main() -> Result<()> {
.set_buttons(MessageButtons::OkCancel)
.set_level(MessageLevel::Error)
.show();
if confirm {
if confirm == MessageDialogResult::Ok {
open::that("https://docs.slimevr.dev/server-setup/installing-and-connecting.html#install-the-latest-slimevr-installer").unwrap();
}
return Ok(());
@@ -170,7 +171,6 @@ fn main() -> Result<()> {
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_store::Builder::default().build())
.plugin(tauri_plugin_window::init())
.invoke_handler(tauri::generate_handler![
update_window_state,
logging,
@@ -184,10 +184,10 @@ fn main() -> Result<()> {
WindowState::open_state(app.path().app_config_dir().unwrap())
.unwrap_or_default();
let window = tauri::WindowBuilder::new(
let window = tauri::WebviewWindowBuilder::new(
app,
"main",
tauri::WindowUrl::App("index.html".into()),
tauri::WebviewUrl::App("index.html".into()),
)
.title("SlimeVR")
.inner_size(1289.0, 709.0)
@@ -196,10 +196,9 @@ fn main() -> Result<()> {
.visible(true)
.decorations(false)
.fullscreen(false)
.disable_file_drop_handler()
.build()?;
if window_state.is_old() {
window_state.update_window(&window, false)?;
window_state.update_window(&window.as_ref().window(), false)?;
}
#[cfg(desktop)]
@@ -244,21 +243,21 @@ fn main() -> Result<()> {
_ => ("other", "".to_string()),
};
app_handle
.emit_all("server-status", emit_me)
.emit("server-status", emit_me)
.expect("Check server log files. \nFailed to emit");
}
log::error!("Java server receiver died");
app_handle
.emit_all("server-status", ("other", "receiver cancelled"))
.emit("server-status", ("other", "receiver cancelled"))
.expect("Failed to emit");
});
}
Ok(())
})
.on_window_event(|e| match e.event() {
.on_window_event(|w, e| match e {
WindowEvent::CloseRequested { .. } => {
let window_state = e.window().state::<Mutex<WindowState>>();
if let Err(e) = update_window_state(e.window().clone(), window_state) {
let window_state = w.state::<Mutex<WindowState>>();
if let Err(e) = update_window_state(w.clone(), window_state) {
log::error!("failed to update window state {}", e)
}
}
@@ -306,7 +305,9 @@ fn main() -> Result<()> {
// I should log this anyways, don't want to dig a grave by not logging the error.
log::error!("CreateWebview error {}", error);
use rfd::{MessageButtons, MessageDialog, MessageLevel};
use rfd::{
MessageButtons, MessageDialog, MessageDialogResult, MessageLevel,
};
let confirm = MessageDialog::new()
.set_title("SlimeVR")
@@ -314,7 +315,7 @@ fn main() -> Result<()> {
.set_buttons(MessageButtons::OkCancel)
.set_level(MessageLevel::Error)
.show();
if confirm {
if confirm == MessageDialogResult::Ok {
open::that("https://docs.slimevr.dev/common-issues.html#webview2-is-missing--slimevr-gui-crashes-immediately--panicked-at--webview2error").unwrap();
}
}

View File

@@ -1,9 +1,10 @@
use std::{collections::HashMap, sync::Mutex};
use tauri::{
menu::{Menu, MenuItem, MenuItemKind},
image::Image,
menu::{Menu, MenuBuilder, MenuItemBuilder, MenuItemKind},
tray::{ClickType, TrayIconBuilder},
AppHandle, Icon, Manager, Runtime, State,
AppHandle, Manager, Runtime, State,
};
pub struct TrayMenu<R: Runtime>(Menu<R>);
@@ -46,7 +47,7 @@ pub fn update_tray_text<R: Runtime>(
menu: State<TrayMenu<R>>,
) -> color_eyre::Result<(), String> {
if let Some((window, MenuItemKind::MenuItem(toggle_i))) =
app.get_window("main").zip(menu.0.get("toggle"))
app.get_webview_window("main").zip(menu.0.get("toggle"))
{
let new_title = if window.is_visible().unwrap_or_default() {
i18n.get("tray_menu-hide")
@@ -66,9 +67,9 @@ pub fn update_tray_text<R: Runtime>(
}
pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
let toggle_i = MenuItem::with_id(app, "toggle", "Hide", true, None);
let quit_i = MenuItem::with_id(app, "quit", "Quit", true, None);
let menu1 = Menu::with_items(app, &[&toggle_i, &quit_i])?;
let toggle_i = MenuItemBuilder::with_id("toggle", "Hide").build(app)?;
let quit_i = MenuItemBuilder::with_id("quit", "Quit").build(app)?;
let menu1 = MenuBuilder::new(app).items(&[&toggle_i, &quit_i]).build()?;
let _ = TrayIconBuilder::with_id("tray-1")
.menu(&menu1)
@@ -77,15 +78,15 @@ pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
.icon_as_template(true)
.menu_on_left_click(false)
.icon(if cfg!(target_os = "macos") {
Icon::Raw(include_bytes!("../icons/appleTrayIcon.png").to_vec())
Image::from_bytes(include_bytes!("../icons/appleTrayIcon.png"))
} else {
Icon::Raw(include_bytes!("../icons/128x128.png").to_vec())
})
Image::from_bytes(include_bytes!("../icons/128x128.png"))
}?)
.on_menu_event(move |app, event| match event.id.as_ref() {
"quit" => app.emit_all("try-close", "tray").unwrap(),
"quit" => app.emit("try-close", "tray").unwrap(),
"toggle" => {
let i18n = app.state::<TrayTranslations>();
if let Some(window) = app.get_window("main") {
if let Some(window) = app.get_webview_window("main") {
let new_title = if window.is_visible().unwrap_or_default() {
let _ = window.hide();
i18n.get("tray_menu-show")
@@ -99,10 +100,10 @@ pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
}
_ => {}
})
.on_tray_event(|tray, event| {
.on_tray_icon_event(|tray, event| {
if event.click_type == ClickType::Left {
let app = tray.app_handle();
if let Some(window) = app.get_window("main") {
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}

View File

@@ -95,17 +95,17 @@ pub fn spawn_java(java: &OsStr, java_version: &OsStr) -> std::io::Result<Child>
#[cfg(desktop)]
pub fn show_error(text: &str) -> bool {
use rand::{seq::SliceRandom, thread_rng};
use rfd::{MessageButtons, MessageDialog, MessageLevel};
use rfd::{MessageButtons, MessageDialog, MessageDialogResult, MessageLevel};
MessageDialog::new()
.set_title(&format!(
.set_title(format!(
"SlimeVR GUI crashed - {}",
POSSIBLE_TITLES.choose(&mut thread_rng()).unwrap()
))
.set_description(text)
.set_buttons(MessageButtons::Ok)
.set_level(MessageLevel::Error)
.show()
.show() == MessageDialogResult::Ok
}
#[cfg(mobile)]

View File

@@ -1,87 +1,85 @@
{
"package": {
"productName": "slimevr",
"version": "../package.json"
},
"build": {
"distDir": "../dist",
"devPath": "http://localhost:5173",
"beforeBuildCommand": "pnpm run build",
"beforeDevCommand": "pnpm run start",
"beforeBuildCommand": "pnpm run build"
"frontendDist": "../dist",
"devUrl": "http://localhost:5173"
},
"plugins": {
"shell": {
"open": true
},
"fs": {
"scope": ["$APP/*", "$APP"],
"all": true
},
"os": {
"all": true
},
"window": {
"setResizable": true,
"setTitle": true,
"maximize": true,
"unmaximize": true,
"minimize": true,
"unminimize": true,
"close": true,
"startDragging": true,
"setSize": true
}
},
"tauri": {
"bundle": {
"active": true,
"targets": "all",
"identifier": "dev.slimevr.SlimeVR",
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"resources": [],
"externalBin": [],
"copyright": "",
"category": "DeveloperTool",
"shortDescription": "",
"longDescription": "",
"bundle": {
"active": true,
"linux": {
"deb": {
"depends": ["openjdk-17-jre-headless"],
"depends": [
"openjdk-17-jre-headless"
],
"files": {
"/usr/share/slimevr/slimevr.jar": "../../server/desktop/build/libs/slimevr.jar"
}
},
"appimage": {
"bundleMediaFramework": true
},
"macOS": {
"frameworks": [],
"exceptionDomain": "localhost",
"signingIdentity": null,
"providerShortName": null,
"entitlements": null,
"license": "../../LICENSE-MIT"
},
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"security": {
"csp": null,
"dangerousRemoteDomainIpcAccess": [
{
"domain": "tauri.localhost",
"windows": ["main"],
"plugins": ["dialog", "fs", "os", "shell", "window"]
}
"category": "DeveloperTool",
"copyright": "",
"targets": "all",
"externalBin": [],
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
],
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
},
"longDescription": "",
"macOS": {
"entitlements": null,
"exceptionDomain": "localhost",
"frameworks": [],
"signingIdentity": null,
"providerShortName": null
},
"resources": [],
"shortDescription": "",
"licenseFile": "../../LICENSE-MIT"
},
"plugins": {
"fs": {
"all": true,
"scope": [
"$APP/*",
"$APP"
]
},
"os": {
"all": true
},
"shell": {
"open": true
},
"window": {
"close": true,
"maximize": true,
"minimize": true,
"setResizable": true,
"setSize": true,
"setTitle": true,
"startDragging": true,
"unmaximize": true,
"unminimize": true
}
},
"productName": "slimevr",
"version": "../package.json",
"identifier": "dev.slimevr.SlimeVR",
"app": {
"security": {
"csp": null
}
}
}

View File

@@ -47,7 +47,7 @@ import { CalibrationTutorialPage } from './components/onboarding/pages/Calibrati
import { AssignmentTutorialPage } from './components/onboarding/pages/assignment-preparation/AssignmentTutorial';
import { open } from '@tauri-apps/plugin-shell';
import semver from 'semver';
import { useBreakpoint } from './hooks/breakpoint';
import { useBreakpoint, useIsTauri } from './hooks/breakpoint';
import { VRModePage } from './components/vr-mode/VRModePage';
import { InterfaceSettings } from './components/settings/pages/InterfaceSettings';
import { error, log } from './utils/logging';
@@ -159,6 +159,7 @@ export default function App() {
const websocketAPI = useProvideWebsocketApi();
const { l10n } = useLocalization();
const [updateFound, setUpdateFound] = useState('');
const isTauri = useIsTauri();
useEffect(() => {
async function fetchReleases() {
const releases = await fetch(
@@ -178,7 +179,7 @@ export default function App() {
fetchReleases().catch(() => error('failed to fetch releases'));
}, []);
if (window.__TAURI_METADATA__) {
if (isTauri) {
useEffect(() => {
os.type()
.then((type) => document.body.classList.add(type.toLowerCase()))
@@ -192,7 +193,7 @@ export default function App() {
}, []);
}
if (window.__TAURI_METADATA__) {
if (isTauri) {
useEffect(() => {
const unlisten = listen(
'server-status',

View File

@@ -1,4 +1,4 @@
import { getCurrent } from '@tauri-apps/plugin-window';
import { getCurrent } from '@tauri-apps/api/webviewWindow';
import { ReactNode, useContext, useEffect, useState } from 'react';
import { NavLink, useMatch } from 'react-router-dom';
import {
@@ -21,7 +21,7 @@ import classNames from 'classnames';
import { QuestionIcon } from './commons/icon/QuestionIcon';
import { useBreakpoint, useIsTauri } from '@/hooks/breakpoint';
import { GearIcon } from './commons/icon/GearIcon';
import { invoke } from '@tauri-apps/api';
import { invoke } from '@tauri-apps/api/core';
import { useTrackers } from '@/hooks/tracker';
import { TrackersStillOnModal } from './TrackersStillOnModal';
import { useConfig } from '@/hooks/config';

View File

@@ -78,8 +78,8 @@ export const InputInside = forwardRef<
const computedValue = disabled
? placeholder
: value !== undefined
? value
: '';
? value
: '';
return (
<label className="flex flex-col gap-1">

View File

@@ -102,8 +102,8 @@ export function CalibrationTutorialPage() {
isCounting
? (IMU_CALIBRATION_TIME - timer) / IMU_CALIBRATION_TIME
: calibrationStatus === CalibrationStatus.SUCCESS
? 1
: 0
? 1
: 0
}
height={14}
animated={true}

View File

@@ -234,8 +234,8 @@ export function ConnectTrackersPage() {
state.alonePage
? '/'
: bnoExists
? '/onboarding/calibration-tutorial'
: '/onboarding/assign-tutorial'
? '/onboarding/calibration-tutorial'
: '/onboarding/assign-tutorial'
}
className="ml-auto"
>

View File

@@ -53,13 +53,15 @@ export function ManualProportionsPage() {
const savedValue = useMemo(() => localStorage.getItem('ratioMode'), []);
const defaultValues = { precise: false, ratio: savedValue !== 'false' };
const { control, watch } = useForm<{ precise: boolean; ratio: boolean }>({
defaultValues: { precise: false, ratio: savedValue !== 'false' },
defaultValues,
});
const { precise, ratio } = watch();
useEffect(() => {
localStorage.setItem('ratioMode', ratio.toString());
localStorage.setItem('ratioMode', ratio?.toString() ?? 'true');
}, [ratio]);
return (
@@ -94,7 +96,7 @@ export function ManualProportionsPage() {
</div>
<div className="w-full px-2">
<BodyProportions
precise={precise}
precise={precise ?? defaultValues.precise}
type={ratio ? 'ratio' : 'linear'}
variant={state.alonePage ? 'alone' : 'onboarding'}
></BodyProportions>

View File

@@ -53,16 +53,14 @@ export function TrackersAssignPage() {
const { useAssignedTrackers, trackers } = useTrackers();
const { applyProgress, state } = useOnboarding();
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
const defaultValues = {
advanced: config?.advancedAssign ?? false,
mirrorView: config?.mirrorView ?? true,
};
const { control, watch } = useForm<{
advanced: boolean;
mirrorView: boolean;
}>({
defaultValues: {
advanced: config?.advancedAssign ?? false,
mirrorView: config?.mirrorView ?? true,
},
});
}>({ defaultValues });
const { advanced, mirrorView } = watch();
const [selectedRole, setSelectRole] = useState<BodyPart>(BodyPart.NONE);
const assignedTrackers = useAssignedTrackers();
@@ -344,8 +342,8 @@ export function TrackersAssignPage() {
onlyAssigned={false}
highlightedRoles={firstError?.affectedRoles || []}
rolesWithErrors={rolesWithErrors}
advanced={advanced}
mirror={mirrorView}
advanced={advanced ?? defaultValues.advanced}
mirror={mirrorView ?? defaultValues.mirrorView}
onRoleSelected={tryOpenChokerWarning}
></BodyAssignment>
</div>

View File

@@ -171,7 +171,7 @@ export function GeneralSettings() {
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
const { reset, control, watch, handleSubmit, getValues, setValue } =
useForm<SettingsForm>({
defaultValues: defaultValues,
defaultValues,
});
const {
trackers: { automaticTrackerToggle, hands: steamVrHands },

View File

@@ -52,8 +52,9 @@ export function Serial() {
const [tryFactoryReset, setTryFactoryReset] = useState(false);
const defaultValues = { port: 'Auto' };
const { control, watch, handleSubmit, reset } = useForm<SerialForm>({
defaultValues: { port: 'Auto' },
defaultValues,
});
const { port } = watch();
@@ -128,7 +129,7 @@ export function Serial() {
useEffect(() => {
const id = setInterval(() => {
if (!isSerialOpen) {
openSerial(port);
openSerial(port ?? defaultValues.port);
} else {
clearInterval(id);
}

View File

@@ -59,7 +59,7 @@ export function VMCSettings() {
};
const { reset, control, watch, handleSubmit } = useForm<VMCSettingsForm>({
defaultValues: defaultValues,
defaultValues,
});
const onSubmit = async (values: VMCSettingsForm) => {

View File

@@ -65,7 +65,7 @@ export function VRCOSCSettings() {
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
const { reset, control, watch, handleSubmit } = useForm<VRCOSCSettingsForm>({
defaultValues: defaultValues,
defaultValues,
});
const onSubmit = (values: VRCOSCSettingsForm) => {

View File

@@ -24,9 +24,8 @@ export function SingleTrackerBodyAssignmentMenu({
const { isMobile } = useBreakpoint('mobile');
const { l10n } = useLocalization();
const { config } = useConfig();
const { control, watch } = useForm<{ advanced: boolean }>({
defaultValues: { advanced: false },
});
const defaultValues = { advanced: false };
const { control, watch } = useForm<{ advanced: boolean }>({ defaultValues });
const { advanced } = watch();
const { closeChokerWarning, tryOpenChokerWarning, shouldShowChokerWarn } =
@@ -80,7 +79,7 @@ export function SingleTrackerBodyAssignmentMenu({
mirror={config?.mirrorView ?? defaultConfig.mirrorView}
width={isMobile ? 160 : undefined}
onlyAssigned={false}
advanced={advanced}
advanced={advanced ?? defaultValues.advanced}
onRoleSelected={tryOpenChokerWarning}
></BodyAssignment>
<div className="flex justify-center">

View File

@@ -117,7 +117,7 @@ export function TrackerSettingsPage() {
? MountingOrientationDegreesToQuatT(currRotation)
: null;
assignreq.displayName = trackerName;
assignreq.displayName = trackerName ?? null;
assignreq.trackerId = tracker?.tracker.trackerId;
assignreq.allowDriftCompensation = allowDriftCompensation;
sendRPCPacket(RpcMessage.AssignTrackerRequest, assignreq);

View File

@@ -24,5 +24,9 @@ export function useBreakpoint<K extends BreakpointKey>(breakpointKey: K) {
}
export function useIsTauri() {
return !!window.__TAURI_METADATA__;
if ('__TAURI_INTERNALS__' in window) {
return true;
} else {
return false;
}
}

View File

@@ -96,18 +96,33 @@ export function useConfigProvider(): ConfigContext {
} as Config)
: null
);
await waitUntil(
() => {
const newConfig: Partial<Config> = JSON.parse(
localStorage.getItem('config.json') ?? '{}'
);
return Object.entries(config).every(
([key, value]) => newConfig[key as keyof Config] === value
);
},
100,
10
);
if (tauri) {
await waitUntil(
async () => {
const newConfig: Partial<Config> = JSON.parse(
(await store.get('config.json')) ?? '{}'
);
return Object.entries(config).every(
([key, value]) => newConfig[key as keyof Config] === value
);
},
100,
10
);
} else {
await waitUntil(
() => {
const newConfig: Partial<Config> = JSON.parse(
localStorage.getItem('config.json') ?? '{}'
);
return Object.entries(config).every(
([key, value]) => newConfig[key as keyof Config] === value
);
},
100,
10
);
}
};
return {

View File

@@ -148,8 +148,8 @@ export function parseStatusToLocale(
const name = tracker.tracker.info?.customName
? tracker.tracker.info?.customName
: tracker.tracker.info?.bodyPart
? l10n.getString('body_part-' + BodyPart[tracker.tracker.info?.bodyPart])
: tracker.tracker.info?.displayName || 'unknown';
? l10n.getString('body_part-' + BodyPart[tracker.tracker.info?.bodyPart])
: tracker.tracker.info?.displayName || 'unknown';
if (typeof name !== 'string') {
return {
trackerName: new TextDecoder().decode(name),

View File

@@ -11,7 +11,7 @@ import {
} from 'react';
import { exists, readTextFile, BaseDirectory } from '@tauri-apps/plugin-fs';
import { error } from '@/utils/logging';
import { invoke } from '@tauri-apps/api';
import { invoke } from '@tauri-apps/api/core';
export const defaultNS = 'translation';
export const DEFAULT_LOCALE = 'en';
@@ -172,7 +172,7 @@ export function AppLocalizationProvider(props: AppLocalizationProviderProps) {
? [
currentLocale,
await readTextFile(OVERRIDE_FILENAME, {
dir: BaseDirectory.AppConfig,
baseDir: BaseDirectory.AppConfig,
}),
]
: await fetchMessages(currentLocale);

View File

@@ -1,3 +1,5 @@
import { error } from './logging';
export function a11yClick(event: React.KeyboardEvent | React.MouseEvent) {
if (event.type === 'click') {
return true;
@@ -8,18 +10,30 @@ export function a11yClick(event: React.KeyboardEvent | React.MouseEvent) {
}
export function waitUntil(
condition: () => boolean,
condition: (() => boolean) | (() => Promise<boolean>),
time: number,
tries?: number
): Promise<void> {
return new Promise((resolve) => {
return new Promise((resolve, rej) => {
const isPromise = typeof condition() === 'boolean';
const interval = setInterval(() => {
if (tries && --tries === 0) {
error(new Error('waitUntil ran out of tries'));
clearInterval(interval);
}
if (condition()) {
resolve();
}
const boolPromise = condition();
if (!isPromise && boolPromise) {
clearInterval(interval);
resolve();
} else if (isPromise) {
(boolPromise as Promise<boolean>)
.then((bool) => {
if (!bool) return;
clearInterval(interval);
resolve();
})
.catch(rej);
}
}, time);
});

View File

@@ -1,4 +1,4 @@
import { invoke } from '@tauri-apps/api';
import { invoke } from '@tauri-apps/api/core';
export function log(...msgs: any[]) {
console.log(...msgs);

View File

@@ -2,7 +2,7 @@
"name": "slimevr-ui",
"version": "0.5.1",
"private": true,
"packageManager": "pnpm@8.10.5",
"packageManager": "pnpm@8.15.5",
"workspaces": [
"solarxr-protocol",
"gui"
@@ -18,6 +18,6 @@
},
"devDependencies": {
"husky": "^8.0.3",
"lint-staged": "^13.2.3"
"lint-staged": "^13.3.0"
}
}

4156
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +1,4 @@
[toolchain]
channel = "1.73"
channel = "1.77.1"
profile = "default"
components = ["rust-analyzer", "rust-src"]