mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Update to latest GUI dependencies (#905)
This commit is contained in:
5
.github/workflows/build-gui.yml
vendored
5
.github/workflows/build-gui.yml
vendored
@@ -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
|
||||
|
||||
4
.github/workflows/gradle.yaml
vendored
4
.github/workflows/gradle.yaml
vendored
@@ -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
2551
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
118
gui/package.json
118
gui/package.json
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
1
gui/src-tauri/.gitignore
vendored
1
gui/src-tauri/.gitignore
vendored
@@ -3,3 +3,4 @@
|
||||
/target/
|
||||
WixTools
|
||||
src/JavaVersion.class
|
||||
/gen/schemas
|
||||
|
||||
@@ -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"
|
||||
|
||||
28
gui/src-tauri/capabilities/migrated.json
Normal file
28
gui/src-tauri/capabilities/migrated.json
Normal 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"
|
||||
]
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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';
|
||||
|
||||
@@ -78,8 +78,8 @@ export const InputInside = forwardRef<
|
||||
const computedValue = disabled
|
||||
? placeholder
|
||||
: value !== undefined
|
||||
? value
|
||||
: '';
|
||||
? value
|
||||
: '';
|
||||
|
||||
return (
|
||||
<label className="flex flex-col gap-1">
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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"
|
||||
>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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 },
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ export function VMCSettings() {
|
||||
};
|
||||
|
||||
const { reset, control, watch, handleSubmit } = useForm<VMCSettingsForm>({
|
||||
defaultValues: defaultValues,
|
||||
defaultValues,
|
||||
});
|
||||
|
||||
const onSubmit = async (values: VMCSettingsForm) => {
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
4156
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,4 @@
|
||||
[toolchain]
|
||||
channel = "1.73"
|
||||
channel = "1.77.1"
|
||||
profile = "default"
|
||||
components = ["rust-analyzer", "rust-src"]
|
||||
|
||||
Reference in New Issue
Block a user