Compare commits

...

84 Commits

Author SHA1 Message Date
Erimel
17d81bb05c Merge branch 'main' into fingertracking 2025-09-26 18:45:45 -04:00
Aed
f2b4d468c2 Added Done button to end of mounting calibration (#1557) 2025-09-23 22:59:22 +02:00
Eiren Rain
1c0f5c381b Update CODEOWNERS (#1558) 2025-09-23 23:54:01 +03:00
lucas lelievre
fb25421ab0 OOPS 2025-09-23 20:23:51 +00:00
lucas lelievre
4890b4a71c Update CODEOWNERS 2025-09-23 22:17:57 +02:00
lucas lelievre
e38732a81c Remove secondary colors usage + improve spacing (#1554) 2025-09-22 21:27:07 +02:00
Eiren Rain
2a78354b17 Disable update prompt on Android (#1547) 2025-09-19 19:55:27 +03:00
Eiren Rain
3fb4347277 Fix Stagered fw update detection (#1544) 2025-09-19 19:55:17 +03:00
Eiren Rain
081e88ead4 Update gui/src/hooks/firmware-update.ts
Co-authored-by: Butterscotch! <bscotchvanilla@gmail.com>
2025-09-18 15:34:56 +03:00
Uriel
73f41f8fc6 Disable update prompt on Android 2025-09-17 19:32:30 -03:00
loucass003
f233f59079 Fix Stagered fw update detection 2025-09-16 23:24:53 +02:00
Eiren Rain
9644b00690 fix: use transaction id in RPC reponses (#1527) 2025-09-16 18:54:12 +03:00
Eiren Rain
543e319c25 HID support on Android (#1532) 2025-09-16 14:57:24 +03:00
Eiren Rain
b7ef70f5c6 Bump actions/setup-java from 4 to 5 (#1522) 2025-09-16 14:25:42 +03:00
Eiren Rain
af171f8812 Fix Android serial support (#1533) 2025-09-16 14:25:11 +03:00
dependabot[bot]
8ec3cade06 Bump actions/setup-java from 4 to 5
Bumps [actions/setup-java](https://github.com/actions/setup-java) from 4 to 5.
- [Release notes](https://github.com/actions/setup-java/releases)
- [Commits](https://github.com/actions/setup-java/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-java
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-16 11:23:12 +00:00
Eiren Rain
bec8be46ca Add folder icon option for the file input (#1536) 2025-09-16 14:22:47 +03:00
Eiren Rain
ac7f809132 Bump actions/setup-node from 4 to 5 (#1540) 2025-09-16 14:22:10 +03:00
Eiren Rain
fcb241fab8 Bump actions/labeler from 5 to 6 (#1541) 2025-09-16 14:21:55 +03:00
Eiren Rain
fbdcf2fa2d Race condition patch for constraints (#1535) 2025-09-16 14:21:13 +03:00
Butterscotch!
73c821e07b Merge remote-tracking branch 'upstream/main' into bscotch/android-serial-fix 2025-09-11 16:07:57 -04:00
Butterscotch!
422ddd7ee8 Write serial directly on Android 2025-09-11 16:07:49 -04:00
Butterscotch!
943ad974ec Limit Android serial buffer to 1024 chars 2025-09-11 16:03:57 -04:00
dependabot[bot]
12a5d59e89 Bump actions/labeler from 5 to 6
Bumps [actions/labeler](https://github.com/actions/labeler) from 5 to 6.
- [Release notes](https://github.com/actions/labeler/releases)
- [Commits](https://github.com/actions/labeler/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/labeler
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 14:22:53 +00:00
dependabot[bot]
85286651dd Bump actions/setup-node from 4 to 5
Bumps [actions/setup-node](https://github.com/actions/setup-node) from 4 to 5.
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](https://github.com/actions/setup-node/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/setup-node
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-09-08 14:22:49 +00:00
Uriel
e9b3efe3d5 Add folder icon option for the file input 2025-09-05 14:13:54 -04:00
Uriel
0f06ac0253 update linux metadata (#1524) 2025-09-04 13:44:17 -03:00
Butterscotch!
75fa1aa1e2 Messy race condition patch for constraints 2025-09-04 06:50:34 -04:00
Butterscotch!
7d642a21f5 Use a read buffer for Android serial
The serial reader on Android does not have a big enough buffer for our serial output, causing issues when parsing it. We can buffer until we reach a newline character to make parsing work.
2025-09-04 06:35:30 -04:00
Butterscotch!
4e1421180c Ensure serial port closure 2025-09-04 04:33:39 -04:00
Butterscotch!
f0a72645d7 Clear request more & update usbReceiver comment 2025-09-04 04:27:20 -04:00
Butterscotch!
86b8e0a904 Fix serial staying open after disconnect 2025-09-04 04:18:52 -04:00
Butterscotch!
789e6a6962 Make ACTION_USB_PERMISSION const 2025-09-04 02:37:52 -04:00
Butterscotch!
f03b300d72 Use val for usbReceiver 2025-09-04 02:26:36 -04:00
Butterscotch!
6b0822c0f6 Rename HID "Service" to "Manager" 2025-09-04 02:26:08 -04:00
Butterscotch!
d9774cab87 Extra requestingPermission handling for new device 2025-09-04 02:24:21 -04:00
Butterscotch!
f07f9f3718 Add comments for USB attach/detach events 2025-09-04 02:22:23 -04:00
Butterscotch!
486be0973b Use USB events for serial & re-request permission 2025-09-04 02:17:28 -04:00
Butterscotch!
9246dd00d3 Additional comments 2025-09-04 01:41:01 -04:00
Butterscotch!
baf515791d Fix HID service comments 2025-09-04 01:37:15 -04:00
Butterscotch!
876450d764 Make Android USB host mode optional 2025-09-04 01:34:22 -04:00
Butterscotch!
44e90e255b Rename HID classes for clarity 2025-09-04 01:34:06 -04:00
Butterscotch!
41026ab851 Move deviceIdLookup to HIDCommon 2025-09-04 01:28:26 -04:00
Butterscotch!
d8509c431d Remove device reattach handling
Events should be good enough :3
2025-09-04 01:05:35 -04:00
Butterscotch!
66df65eb80 Use Android USB events for HID instead of polling 2025-09-04 00:31:43 -04:00
Butterscotch!
30641a5809 Reconnect HID 2025-09-04 00:31:43 -04:00
Butterscotch!
574523daec Persist UsbDeviceConnection 2025-09-04 00:31:43 -04:00
Butterscotch!
1913605d16 De-duplicate HID code 2025-09-04 00:31:42 -04:00
Butterscotch!
8aeecab51f Implement awful reading 2025-09-04 00:29:45 -04:00
Butterscotch!
9fd5d6a187 Initial Android USB HID support 2025-09-04 00:29:45 -04:00
Butterscotch!
4568ebb41a Foot snapping fix (#1519) 2025-09-03 21:11:24 -03:00
Ilia Ki
2777d8af89 Fix endian docs for smol HID (#1520) 2025-09-03 20:03:39 -03:00
peelz
0c09c22306 fix: use transaction id in RPC reponses 2025-09-01 13:46:48 -04:00
Eiren Rain
3f9b997ffa Bump awalsh128/cache-apt-pkgs-action from 1.5.1 to 1.5.3 (#1515) 2025-08-19 21:45:46 +02:00
dependabot[bot]
df379ee234 Bump awalsh128/cache-apt-pkgs-action from 1.5.1 to 1.5.3
Bumps [awalsh128/cache-apt-pkgs-action](https://github.com/awalsh128/cache-apt-pkgs-action) from 1.5.1 to 1.5.3.
- [Release notes](https://github.com/awalsh128/cache-apt-pkgs-action/releases)
- [Commits](https://github.com/awalsh128/cache-apt-pkgs-action/compare/v1.5.1...v1.5.3)

---
updated-dependencies:
- dependency-name: awalsh128/cache-apt-pkgs-action
  dependency-version: 1.5.3
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-19 12:17:12 +00:00
Eiren Rain
acd628637e Bump actions/download-artifact from 4 to 5 (#1516) 2025-08-19 14:14:48 +02:00
dependabot[bot]
155dbfbff1 Bump actions/download-artifact from 4 to 5
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-19 12:13:29 +00:00
Eiren Rain
eda3d74c54 Bump actions/checkout from 4 to 5 (#1517) 2025-08-19 14:12:25 +02:00
dependabot[bot]
4b9f393cee Bump actions/checkout from 4 to 5
Bumps [actions/checkout](https://github.com/actions/checkout) from 4 to 5.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-08-18 22:56:14 +00:00
Erimel
da202e4123 Log when trying to send unsupported input to openvr 2025-08-10 21:53:08 -04:00
Erimel
4e861a58ef Merge branch 'main' into fingertracking 2025-08-10 21:16:51 -04:00
Eiren Rain
069da63d1f fix(gui): export proportions button doesn't work (#1513) 2025-08-01 11:51:31 +03:00
DevMiner
3fbe58b027 fix(gui): export proportions button doesn't work 2025-08-01 02:21:26 +02:00
Eiren Rain
aa6b5ab028 Bring back resetMountingFeet toggle for mounting resets (#1509) 2025-07-31 22:07:30 +03:00
Erimel
b2ee4e0b5e Change icons for new mounting reset buttons 2025-07-29 17:29:25 -04:00
Erimel
34ab0c6252 Bring back resetMountingFeet toggle for mounting resets 2025-07-29 17:14:05 -04:00
Butterscotch!
a8116a7f35 Fix mounting reset not working for feet (#1508) 2025-07-29 16:33:27 -04:00
Eiren Rain
8c65129bb4 New Pontoon translations (#1502) 2025-07-26 06:02:35 +03:00
Nola
acaf6a7679 Pontoon: Update Dutch (nl) localization of GUI
Co-authored-by: Nola <stefsecretdesecret@gmail.com>
Co-authored-by: Vyolex <25586367+Vyolex@users.noreply.github.com>
2025-07-26 05:01:55 +02:00
nekomona
8044a8a824 Pontoon: Update Simplified Chinese (zh-Hans) localization of GUI
Co-authored-by: nekomona <nekomona@163.com>
2025-07-26 05:01:55 +02:00
Yexo
1ec03b83b6 Pontoon: Update Polish (pl) localization of GUI
Co-Authored-By: Yexo <patrykcyranski@gmail.com>
2025-07-26 05:01:55 +02:00
lucas lelievre
44caf24126 FW update + Fix download url 2025-07-26 05:00:37 +02:00
Erimel
072da46a33 Merge branch 'main' into fingertracking 2025-07-22 20:17:57 -04:00
Erimel
c9dac8ebe3 tap inputs 2025-07-22 20:16:44 -04:00
Erimel
a125195695 Pontoon: Update French (fr) localization of GUI
Co-authored-by: Erimel <loukalemire@gmail.com>
2025-07-22 23:08:56 +00:00
Erimel
d27385dfa4 Allow partial/separate resets for feet and fingers (#1441)
Co-authored-by: Uriel <imurx@proton.me>
2025-07-22 19:08:34 -04:00
DevMiner
68bd670d7c fix(gui/wizard): manual calibration reset body proportions's reset button isn't primary (#1503) 2025-07-20 22:26:46 +02:00
Erimel
0221cf3985 Inputs WIP 2025-07-11 22:08:47 -04:00
Erimel
dd676d5cca Remove single tap 2025-07-11 21:13:59 -04:00
Erimel
6d56af3fb3 driver protocol version check and shareable bones 2025-07-03 22:20:02 -04:00
Erimel
365437531b Send finger rotations to driver 2025-06-25 22:21:10 -04:00
Erimel
78b53224a8 WIP getting SlimeVR hand controllers to work in VR 2025-06-21 22:00:45 -04:00
Erimel
166d2b48f1 Add support for fingers protobuf data for the driver 2025-06-21 18:50:12 -04:00
Erimel
878fb42c13 Fix protobuf_update.bat script and update to 4.31.1 2025-06-21 16:56:06 -04:00
133 changed files with 7520 additions and 2704 deletions

32
.github/CODEOWNERS vendored
View File

@@ -2,23 +2,23 @@
* @Eirenliel
# Make everyone be able to approve SolarXR submodule changes
/solarxr-protocol @ButterscotchV @Erimelowo @ImUrX @loucass003
/solarxr-protocol @ButterscotchV @Erimelowo @loucass003
# Make Loucas and Uriel the owners of all GUI stuff
/gui/ @ImUrX @loucass003
/pnpm-lock.yaml @ImUrX @loucass003
/pnpm-workspace.yaml @ImUrX @loucass003
# Make Loucass the owner of all GUI stuff
/gui/ @loucass003
/pnpm-lock.yaml @loucass003
/pnpm-workspace.yaml @loucass003
# Uriel and Erimel responsible for i18n
/gui/public/i18n/ @ImUrX @Erimelowo
/gui/src/i18n/ @ImUrX @Erimelowo
/l10n.toml @ImUrX @Erimelowo
# loucass003 and Erimel responsible for i18n
/gui/public/i18n/ @loucass003 @Erimelowo
/gui/src/i18n/ @loucass003 @Erimelowo
/l10n.toml @loucass003 @Erimelowo
/gui/src/components/settings/ @Erimelowo @ImUrX @loucass003
/gui/src/components/settings/ @Erimelowo @loucass003
# Rust part of the GUI
/gui/src-tauri/ @ImUrX
/Cargo.lock @ImUrX
/gui/src-tauri/ @loucass003
/Cargo.lock @loucass003
# Some server code~
/server/ @ButterscotchV @Eirenliel @Erimelowo
@@ -32,7 +32,7 @@
/server/src/main/java/dev/slimevr/filtering/ @Erimelowo
# Linux files
*.nix @ImUrX
/flake.lock @ImUrX
/dev.slimevr.SlimeVR.metainfo.xml @ImUrX
/.envrc @ImUrX
*.nix @loucass003
/flake.lock @loucass003
/dev.slimevr.SlimeVR.metainfo.xml @loucass003
/.envrc @loucass003

View File

@@ -21,13 +21,13 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -59,13 +59,13 @@ jobs:
BUILD_ARCH: ${{ endsWith(matrix.os, 'arm') && 'aarch64' || 'amd64' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
- if: startsWith(matrix.os, 'ubuntu')
name: Set up Linux dependencies
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
uses: awalsh128/cache-apt-pkgs-action@v1.5.3
with:
packages: libgtk-3-dev webkit2gtk-4.1 libappindicator3-dev librsvg2-dev patchelf
# Increment to invalidate the cache
@@ -85,7 +85,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-22.04
steps:
- uses: actions/setup-node@v4
- uses: actions/setup-node@v5
with:
node-version: '22.x'

View File

@@ -19,7 +19,7 @@ jobs:
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -27,7 +27,7 @@ jobs:
run: git fetch --tags origin --recurse-submodules=no --force
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'adopt'
@@ -48,7 +48,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -56,7 +56,7 @@ jobs:
run: git fetch --tags origin --recurse-submodules=no --force
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'adopt'
@@ -87,7 +87,7 @@ jobs:
bundle-android:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
@@ -95,7 +95,7 @@ jobs:
run: git fetch --tags origin --recurse-submodules=no --force
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: '17'
distribution: 'adopt'
@@ -105,7 +105,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -154,17 +154,17 @@ jobs:
env:
BUILD_ARCH: ${{ endsWith(matrix.os, 'arm') && 'aarch64' || 'amd64' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
name: 'SlimeVR-Server'
path: server/desktop/build/libs/
- name: Set up Linux dependencies
uses: awalsh128/cache-apt-pkgs-action@v1.5.1
uses: awalsh128/cache-apt-pkgs-action@v1.5.3
with:
packages: |
build-essential curl wget file libssl-dev libgtk-3-dev libappindicator3-dev librsvg2-dev
@@ -190,7 +190,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -252,11 +252,11 @@ jobs:
needs: [build, test]
if: contains(fromJSON('["workflow_dispatch", "create"]'), github.event_name)
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
name: 'SlimeVR-Server'
path: server/desktop/build/libs/
@@ -266,7 +266,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'
@@ -332,11 +332,11 @@ jobs:
env:
BUILD_ARCH: ${{ endsWith(matrix.os, 'arm') && 'win-aarch64' || 'win64' }}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
- uses: actions/download-artifact@v4
- uses: actions/download-artifact@v5
with:
name: 'SlimeVR-Server'
path: server/desktop/build/libs/
@@ -351,7 +351,7 @@ jobs:
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version-file: '.node-version'
cache: 'pnpm'

View File

@@ -17,6 +17,6 @@ jobs:
pull-requests: write
steps:
- uses: actions/labeler@v5
- uses: actions/labeler@v6
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -12,7 +12,7 @@ jobs:
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
submodules: recursive
- uses: repo-sync/pull-request@v2

View File

@@ -15,7 +15,7 @@ jobs:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v5
with:
ref: pontoon
submodules: recursive

6
Cargo.lock generated
View File

@@ -2645,7 +2645,7 @@ version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56"
dependencies = [
"proc-macro-crate 1.3.1",
"proc-macro-crate 2.0.0",
"proc-macro2",
"quote",
"syn 2.0.87",
@@ -4539,9 +4539,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-fs"
version = "2.4.0"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c341290d31991dbca38b31d412c73dfbdb070bb11536784f19dd2211d13b778f"
checksum = "8c6ef84ee2f2094ce093e55106d90d763ba343fad57566992962e8f76d113f99"
dependencies = [
"anyhow",
"dunce",

View File

@@ -18,7 +18,7 @@
"@tanstack/react-query": "^5.48.0",
"@tauri-apps/api": "^2.0.2",
"@tauri-apps/plugin-dialog": "^2.0.0",
"@tauri-apps/plugin-fs": "^2.0.0",
"@tauri-apps/plugin-fs": "2.4.1",
"@tauri-apps/plugin-http": "^2.5.0",
"@tauri-apps/plugin-os": "^2.0.0",
"@tauri-apps/plugin-shell": "^2.0.0",

View File

@@ -237,6 +237,8 @@ reset-reset_all_warning_default-v2 =
reset-full = Full Reset
reset-mounting = Reset Mounting
reset-mounting-feet = Reset Feet Mounting
reset-mounting-fingers = Reset Fingers Mounting
reset-yaw = Yaw Reset
## Serial detection stuff
@@ -274,7 +276,7 @@ widget-overlay-is_mirrored_label = Display Overlay as Mirror
widget-drift_compensation-clear = Clear drift compensation
## Widget: Clear Reset Mounting
widget-clear_mounting = Clear reset mounting
widget-clear_mounting = Clear Reset Mounting
## Widget: Developer settings
widget-developer_mode = Developer Mode
@@ -584,8 +586,8 @@ settings-general-fk_settings-leg_tweak-floor_clip-description = Floor-clip can r
settings-general-fk_settings-leg_tweak-toe_snap-description = Toe-snap attempts to guess the rotation of your feet if foot trackers are not in use.
settings-general-fk_settings-leg_tweak-foot_plant-description = Foot-plant rotates your feet to be parallel to the ground when in contact.
settings-general-fk_settings-leg_fk = Leg tracking
settings-general-fk_settings-leg_fk-reset_mounting_feet-description = Enable feet Mounting Reset by tiptoeing.
settings-general-fk_settings-leg_fk-reset_mounting_feet = Feet Mounting Reset
settings-general-fk_settings-leg_fk-reset_mounting_feet-description-v1 = Force feet mounting reset during general mounting resets.
settings-general-fk_settings-leg_fk-reset_mounting_feet-v1 = Force feet mounting reset
settings-general-fk_settings-enforce_joint_constraints = Skeletal Limits
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints = Enforce constraints
settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description = Prevents joints from rotating past their limit
@@ -1123,6 +1125,7 @@ onboarding-automatic_mounting-preparation-v2-step-2 = 3. Hold the position until
onboarding-automatic_mounting-put_trackers_on-title = Put on your trackers
onboarding-automatic_mounting-put_trackers_on-description = To calibrate mounting orientations, we're gonna use the trackers you just assigned. Put on all your trackers, you can see which are which in the figure to the right.
onboarding-automatic_mounting-put_trackers_on-next = I have all my trackers on
onboarding-automatic_mounting-return-home = Done
## Tracker manual proportions setupa
onboarding-manual_proportions-back = Go Back to Reset tutorial

View File

@@ -269,6 +269,7 @@ navbar-settings = Réglages
bvh-start_recording = Enregistrer BVH
bvh-recording = Enregistrement...
bvh-save_title = Sauvegarder lenregistrement BVH
## Tracking pause
@@ -406,6 +407,7 @@ tracker-settings-forget-label = Oublier capteur
tracker-settings-update-unavailable = Ne peut pas être mis à jour (DIY)
tracker-settings-update-low-battery = Mise à jour impossible. Batterie inférieure à 50 %
tracker-settings-update-up_to_date = À jour
tracker-settings-update-blocked = Mise à jour non disponible. Aucune autre version disponible
tracker-settings-update-available = { $versionName } est maintenant disponible
tracker-settings-update = Mettre à jour maintenant
tracker-settings-update-title = Version du micrologiciel
@@ -584,6 +586,7 @@ settings-stay_aligned-relaxed_poses-sitting = Ajuster les capteurs en position a
settings-stay_aligned-relaxed_poses-flat = Ajuster les capteurs en position assise sur le sol ou allongée sur le dos
settings-stay_aligned-relaxed_poses-save_pose = Enregistrer la posture
settings-stay_aligned-relaxed_poses-reset_pose = Réinitialiser la posture
settings-stay_aligned-relaxed_poses-close = Fermer
settings-stay_aligned-debug-label = Débogage
settings-stay_aligned-debug-description = Veuillez inclure vos paramètres lorsque vous signalez des problèmes concernant Garder Aligné.
settings-stay_aligned-debug-copy-label = Copier les paramètres dans le presse-papiers
@@ -744,6 +747,9 @@ settings-interface-behavior-error_tracking-description_v2 =
Pour offrir la meilleure expérience utilisateur possible, nous collectons des rapports d'erreurs anonymisés, des mesures de performance et des informations sur le système d'exploitation. Cela nous aide à détecter les bugs et les problèmes liés à SlimeVR. Ces données sont collectées via Sentry.io.
settings-interface-behavior-error_tracking-label = Envoyer les erreurs aux développeurs
settings-interface-behavior-bvh_directory = Répertoire pour sauvegarder les enregistrements BVH
settings-interface-behavior-bvh_directory-description = Choisissez un répertoire où sauvegarder vos enregistrements BVH au lieu davoir à choisir où les sauvegarder à chaque fois.
settings-interface-behavior-bvh_directory-label = Répertoire où sauvegarder les enregistrements BVH
## Serial settings
@@ -1014,7 +1020,7 @@ onboarding-connect_tracker-next = J'ai connecté tous mes capteurs
onboarding-calibration_tutorial = Tutoriel de calibration IMU
onboarding-calibration_tutorial-subtitle = Ceci vous aidera à réduire la dérive du capteur !
onboarding-calibration_tutorial-description = Chaque fois que vous allumez vos capteurs, ils doivent rester sur une surface plane pour se calibrer. Faisons de même en cliquant sur le bouton « { onboarding-calibration_tutorial-calibrate } ». <b>Ne les déplacez pas !</b>
onboarding-calibration_tutorial-description-v1 = Après avoir allumé vos capteurs, placez-les sur une surface stable pendant un moment pour leur permettre de se calibrer. La calibration peut être effectué n'importe quand lors que les capteurs sont allumés - cette page sert simplement de tutoriel. Pour commencer, cliquez sur le bouton « { onboarding-calibration_tutorial-calibrate } », puis <b>ne déplacez pas vos capteurs !</b>
onboarding-calibration_tutorial-calibrate = J'ai posé mes capteurs sur la table
onboarding-calibration_tutorial-status-waiting = En attente de vous
onboarding-calibration_tutorial-status-calibrating = Calibration...
@@ -1332,13 +1338,13 @@ onboarding-stay_aligned-preparation-title = Préparation
onboarding-stay_aligned-preparation-tip = Assurez-vous de vous tenir droit. Vous devez regarder vers l'avant et vos bras doivent être le long de votre corps.
onboarding-stay_aligned-relaxed_poses-standing-title = Posture debout détendu
onboarding-stay_aligned-relaxed_poses-standing-step-0 = 1. Tenez-vous dans une position confortable. Détendez-vous !
onboarding-stay_aligned-relaxed_poses-standing-step-2 = 3. Appuyez sur le bouton « Enregistrer la posture ».
onboarding-stay_aligned-relaxed_poses-standing-step-1-v2 = 2. Appuyez sur le bouton « Enregistrer la posture ».
onboarding-stay_aligned-relaxed_poses-sitting-title = Posture assis détendu dans une chaise
onboarding-stay_aligned-relaxed_poses-sitting-step-0 = 1. Asseyez-vous dans une position confortable. Détendez-vous !
onboarding-stay_aligned-relaxed_poses-sitting-step-2 = 3. Appuyez sur le bouton « Enregistrer la posture ».
onboarding-stay_aligned-relaxed_poses-sitting-step-1-v2 = 2. Appuyez sur le bouton « Enregistrer la posture ».
onboarding-stay_aligned-relaxed_poses-flat-title = Posture assis détendu sur le sol
onboarding-stay_aligned-relaxed_poses-flat-step-0 = 1. Asseyez-vous sur le sol, les jambes devant. Détendez-vous !
onboarding-stay_aligned-relaxed_poses-flat-step-2 = 3. Appuyez sur le bouton « Enregistrer la posture ».
onboarding-stay_aligned-relaxed_poses-flat-step-1-v2 = 2. Appuyez sur le bouton « Enregistrer la posture ».
onboarding-stay_aligned-relaxed_poses-skip_step = Sauter
onboarding-stay_aligned-done-title = Garder Aligné activé !
onboarding-stay_aligned-done-description = La configuration de Garder Aligné est terminée !

View File

@@ -111,29 +111,122 @@ board_type-GLOVE_IMU_SLIMEVR_DEV = SlimeVR Dev IMU Handschoen
skeleton_bone-NONE = Geen
skeleton_bone-HEAD = Hoofdverschuiving
skeleton_bone-HEAD-desc =
Dit is de afstand tussen je headset en het midden van je hoofd.
Om dit aan te passen, schud je je hoofd naar links en rechts alsof je 'nee' zegt,
pas het aan totdat beweging van de andere trackers te verwaarlozen is.
skeleton_bone-NECK = Neklengte
skeleton_bone-NECK-desc =
Dit is de afstand tussen het midden van je hoofd en de basis van je nek.
Om dit aan te passen, beweeg je je hoofd op en neer alsof je knikt, of kantel je je hoofd
naar links en rechts. Wijzig de positie totdat beweging in andere trackers verwaarloosbaar is.
skeleton_bone-torso_group = Romp lengte
skeleton_bone-torso_group-desc =
Dit is de afstand van je nek tot je heupen.
Om dit aan te passen, ga rechtop staan en pas het aan totdat je virtuele heupen
in lijn zijn met je echte heupen.
skeleton_bone-UPPER_CHEST = Bovenborst Lengte
skeleton_bone-UPPER_CHEST-desc =
Dit is de afstand tussen de basis van je nek en het midden van je borst.
Om dit aan te passen, stel je de torso-lengte correct af en pas je deze aan in verschillende houdingen
(zitten, bukken, liggen, enz.) totdat je virtuele ruggengraat overeenkomt met je echte.
skeleton_bone-CHEST_OFFSET = Borstoffset
skeleton_bone-CHEST_OFFSET-desc =
Dit kan worden aangepast om je virtuele borsttracker omhoog of omlaag te verplaatsen,
om te helpen bij de kalibratie in bepaalde spellen of applicaties die verwachten dat deze hoger of lager staat.
skeleton_bone-CHEST = Borstafstand
skeleton_bone-CHEST-desc =
Dit is de afstand van het midden van je borst tot het midden van je ruggengraat.
Om dit aan te passen, stel je de torso-lengte correct af en pas je deze aan in verschillende houdingen
(zitten, bukken, liggen, enz.) totdat je virtuele ruggengraat overeenkomt met je echte.
skeleton_bone-WAIST = Taille lengte
skeleton_bone-WAIST-desc =
Dit is de afstand van het midden van je ruggengraat tot je navel.
Om dit aan te passen, stel je de torso-lengte correct af en pas je deze aan in verschillende houdingen
(zitten, bukken, liggen, enz.) totdat je virtuele ruggengraat overeenkomt met je echte.
skeleton_bone-HIP = Heuplengte
skeleton_bone-HIP-desc =
Dit is de afstand van je navel tot je heupen.
Om dit aan te passen, stel je de torso-lengte correct in en pas je deze aan in verschillende houdingen
(zitten, bukken, liggen, enz.) totdat je virtuele ruggengraat overeenkomt met je echte.
skeleton_bone-HIP_OFFSET = Heupoffset
skeleton_bone-HIP_OFFSET-desc =
Dit kan worden aangepast om je virtuele heuptracker omhoog of omlaag te verplaatsen,
om te helpen bij de kalibratie in bepaalde spellen of applicaties die mogelijk verwachten dat deze zich rond je middel bevindt.
skeleton_bone-HIPS_WIDTH = Heupbreedte
skeleton_bone-HIPS_WIDTH-desc =
Dit is de afstand tussen het begin van je benen.
Om dit aan te passen, voer je een volledige reset uit met je benen gestrekt en pas je het aan totdat je virtuele benen horizontaal overeenkomen met je echte.
skeleton_bone-leg_group = Beenlengte
skeleton_bone-leg_group-desc =
Dit is de afstand van je heupen tot je voeten.
Om dit aan te passen, pas je je torso-lengte op de juiste manier aan
totdat je virtuele voeten op hetzelfde niveau staan als je echte.
skeleton_bone-UPPER_LEG = Bovenbeenlengte
skeleton_bone-UPPER_LEG-desc =
Dit is de afstand van je heupen tot je knieën.
Om dit aan te passen, pas je je beenlengte op de juiste manier aan
totdat je virtuele knieën op dezelfde hoogte zijn als je echte.
skeleton_bone-LOWER_LEG = Onderbeenlengte
skeleton_bone-LOWER_LEG-desc =
Dit is de afstand van je knieën tot je enkels.
Om dit aan te passen, pas je je beenlengte op de juiste manier aan
totdat je virtuele knieën op dezelfde hoogte zijn als je echte knieën.
skeleton_bone-FOOT_LENGTH = Voetlengte
skeleton_bone-FOOT_LENGTH-desc =
Dit is de afstand van je enkels tot je tenen.
Om dit aan te passen, ga op je tenen staan en pas het aan totdat je virtuele voeten op hun plaats blijven.
skeleton_bone-FOOT_SHIFT = Voetverschuiving
skeleton_bone-FOOT_SHIFT-desc =
Deze waarde is de horizontale afstand van je knie tot je enkel.
Dit houdt rekening met het feit dat je onderbenen naar achteren staan wanneer je rechtop staat.
Om dit aan te passen, stel je de voetlengte in op 0, voer je een volledige reset uit,
en pas je het aan totdat je virtuele voeten op één lijn liggen met het midden van je enkels.
skeleton_bone-SKELETON_OFFSET = Skelet offset
skeleton_bone-SKELETON_OFFSET-desc =
Dit kan worden aangepast om al je trackers naar voren of naar achteren te verschuiven.
Het kan worden gebruikt om te helpen bij de kalibratie in bepaalde spellen of toepassingen
die mogelijk verwachten dat je trackers verder naar voren staan.
skeleton_bone-SHOULDERS_DISTANCE = Schoudersafstand
skeleton_bone-SHOULDERS_DISTANCE-desc =
Dit is de verticale afstand van de basis van je nek tot je schouders.
Om dit aan te passen, stel je de lengte van je bovenarm in op 0 en
pas je deze aan totdat je virtuele elleboogtrackers verticaal uitlijnen met je echte schouders.
skeleton_bone-SHOULDERS_WIDTH = Schouderbreedte
skeleton_bone-SHOULDERS_WIDTH-desc =
Dit is de horizontale afstand van de basis van je nek tot je schouders.
Om dit aan te passen, stel je de lengte van je bovenarm in op 0 en pas je deze aan
totdat je virtuele elleboogtrackers horizontaal uitlijnen met je echte schouders.
skeleton_bone-arm_group = Armlengte
skeleton_bone-arm_group-desc =
Dit is de afstand van je schouders tot je polsen.
Om dit aan te passen, pas je de schouderafstand correct aan, stel je Handafstand Y in op 0,
en pas je deze aan totdat je handtrackers op één lijn liggen met je polsen.
skeleton_bone-UPPER_ARM = Bovenarmlengte
skeleton_bone-UPPER_ARM-desc =
Dit is de afstand van je schouders tot je ellebogen.
Om dit aan te passen, pas je de armlengte correct aan en pas je deze aan
totdat je elleboogtrackers overeenkomen met je echte ellebogen.
skeleton_bone-LOWER_ARM = Onderarmlengte
skeleton_bone-LOWER_ARM-desc =
Dit is de afstand van je ellebogen tot je polsen.
Om dit aan te passen, pas je de armlengte correct aan en pas je deze aan
totdat je elleboogtrackers overeenkomen met je echte ellebogen.
skeleton_bone-HAND_Y = Afstand hand Y
skeleton_bone-HAND_Y-desc =
Dit is de verticale afstand van je polsen tot het midden van je hand.
Om dit aan te passen voor motion capture, pas je de armlengte correct aan
en pas je deze aan totdat je handtrackers verticaal uitgelijnd zijn met het midden van je handen.
Wil je het aanpassen voor elleboogtracking vanaf je controllers,
stel dan de armlengte in op 0 en pas je deze aan totdat je elleboogtrackers verticaal op één lijn liggen met je polsen.
skeleton_bone-HAND_Z = Afstand hand Z
skeleton_bone-HAND_Z-desc =
Dit is de horizontale afstand van je polsen tot het midden van je hand.
Als je dit wilt aanpassen voor motion capture, stel je deze in op 0.
Wil je het aanpassen voor elleboogtracking vanaf je controllers, stel dan de armlengte in op 0
en pas je deze aan totdat je elleboogtrackers horizontaal op één lijn liggen met je polsen.
skeleton_bone-ELBOW_OFFSET = Elleboogoffset
skeleton_bone-ELBOW_OFFSET-desc = Dit kan worden aangepast om je virtuele elleboogtrackers omhoog of omlaag te verplaatsen, zodat wordt voorkomen dat VRChat per ongeluk een elleboogtracker aan de borst koppelt.
## Tracker reset buttons
@@ -148,6 +241,8 @@ reset-reset_all_warning_default-v2 =
Weet je zeker dat je dit wilt doen?
reset-full = Volledige reset
reset-mounting = Reset montage
reset-mounting-feet = Reset voetmontage
reset-mounting-fingers = Reset vingermontage
reset-yaw = Yaw Reset
## Serial detection stuff
@@ -173,6 +268,7 @@ navbar-settings = Instellingen
bvh-start_recording = BVH opnemen
bvh-recording = Opname bezig...
bvh-save_title = Sla BVH-opname op
## Tracking pause
@@ -213,6 +309,7 @@ widget-imu_visualizer-rotation_raw = Rauw
widget-imu_visualizer-rotation_preview = Preview
widget-imu_visualizer-acceleration = Versnelling
widget-imu_visualizer-position = Positie
widget-imu_visualizer-stay_aligned = Blijf in lijn
## Widget: Skeleton Visualizer
@@ -240,6 +337,7 @@ tracker-table-column-temperature = Temp. °C
tracker-table-column-linear-acceleration = Accel. X/Y/Z
tracker-table-column-rotation = Rotatie X/Y/Z
tracker-table-column-position = Positie X/Y/Z
tracker-table-column-stay_aligned = Blijf in lijn
tracker-table-column-url = URL
## Tracker rotation
@@ -305,7 +403,9 @@ tracker-settings-forget = Vergeet tracker
tracker-settings-forget-description = Verwijdert de tracker van de SlimeVR Server en voorkomt dat deze verbinding kan maken totdat de server opnieuw wordt opgestart. De configuratie van de tracker blijft behouden.
tracker-settings-forget-label = Vergeet tracker
tracker-settings-update-unavailable = Kan niet worden bijgewerkt (DIY)
tracker-settings-update-low-battery = Kan niet worden bijgewerkt. Batterij lager dan 50%
tracker-settings-update-up_to_date = Up to date.
tracker-settings-update-blocked = Update is niet beschikbaar. Er zijn geen andere versies beschikbaar.
tracker-settings-update-available = { $versionName } is nu beschikbaar
tracker-settings-update = Werk nu bij.
tracker-settings-update-title = Firmware versie
@@ -375,6 +475,7 @@ mounting_selection_menu-close = Sluiten
settings-sidebar-title = Instellingen
settings-sidebar-general = Algemeen
settings-sidebar-tracker_mechanics = Trackersinstellingen
settings-sidebar-stay_aligned = Blijf in lijn
settings-sidebar-fk_settings = FK-instellingen
settings-sidebar-gesture_control = Tikbediening
settings-sidebar-interface = Interface
@@ -386,6 +487,7 @@ settings-sidebar-appearance = Uiterlijk
settings-sidebar-notifications = Notificaties
settings-sidebar-behavior = Gedrag
settings-sidebar-firmware-tool = DIY Firmware Tool
settings-sidebar-vrc_warnings = VRChat Configuratie-waarschuwingen
settings-sidebar-advanced = Geavanceerd
## SteamVR settings
@@ -443,7 +545,7 @@ settings-general-tracker_mechanics-drift_compensation-prediction = Voorspelling
# This cares about multilines
settings-general-tracker_mechanics-drift_compensation-prediction-description =
Voorspelt compensatie van gierdrift buiten het eerder gemeten bereik.
Schakel dit in als uw trackers continu om de gier-as draaien.
Schakel dit in als jouw trackers continu om de gier-as draaien.
settings-general-tracker_mechanics-drift_compensation-prediction-label = Voorspelling van driftcompensatie
settings-general-tracker_mechanics-drift_compensation_warning =
<b>Waarschuwing:</b> Gebruik alleen driftcompensatie als je heel vaak
@@ -463,6 +565,25 @@ settings-general-tracker_mechanics-use_mag_on_all_trackers-description =
Gebruikt magnetometer op alle trackers die er een compatibele firmware voor hebben, waardoor drift in stabiele magnetische omgevingen wordt verminderd.
Je kan dit per individuele tracker uit zetten in de instellingen van de tracker. <b>Sluit geen van de trackers af terwijl u dit in- en uitschakelt!</b>
settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Gebruik magnetometer op de trackers
settings-stay_aligned = Blijf in lijn
settings-stay_aligned-description = ijf in lijn vermindert drift door je trackers geleidelijk aan te passen zodat ze overeenkomen met je ontspannen houdingen.
settings-stay_aligned-setup-label = Blijf in lijn instellen
settings-stay_aligned-setup-description = Je moet "Blijf in lijn instellen" voltooien om Blijf in lijn te activeren.
settings-stay_aligned-warnings-drift_compensation = ⚠ Schakel Drift Compensation uit! Drift Compensation conflicteert met Blijf in lijn.
settings-stay_aligned-enabled-label = Trackers aanpassen
settings-stay_aligned-hide_yaw_correction-label = Aanpassing verbergen (om te vergelijken zonder Blijf in lijn)
settings-stay_aligned-general-label = Algemeen
settings-stay_aligned-relaxed_poses-label = Ontspannen houdingen
settings-stay_aligned-relaxed_poses-description = Blijf in lijn gebruikt je ontspannen houdingen om je trackers in lijn te houden. Gebruik "Stel Blijf in lijn in" om deze houdingen bij te werken.
settings-stay_aligned-relaxed_poses-standing = Pas trackers aan terwijl je staat
settings-stay_aligned-relaxed_poses-sitting = Pas trackers aan terwijl je op een stoel zit
settings-stay_aligned-relaxed_poses-flat = Pas trackers aan terwijl je op de grond zit of op je rug ligt.
settings-stay_aligned-relaxed_poses-save_pose = Sla houding op
settings-stay_aligned-relaxed_poses-reset_pose = Reset houding
settings-stay_aligned-relaxed_poses-close = Sluiten
settings-stay_aligned-debug-label = Foutopsporing
settings-stay_aligned-debug-description = Voeg je instellingen toe wanneer je problemen met Blijf in lijn rapporteert.
settings-stay_aligned-debug-copy-label = Instellingen naar klembord kopiëren
## FK/Tracking settings
@@ -622,6 +743,9 @@ settings-interface-behavior-error_tracking-description_v2 =
Om de beste gebruikerservaring te bieden, verzamelen we geanonimiseerde foutrapporten, prestatiestatistieken en informatie over het besturingssysteem. Dit helpt ons bij het detecteren van fouten en problemen met SlimeVR. Deze statistieken worden verzameld via Sentry.io.
settings-interface-behavior-error_tracking-label = Stuur fouten naar de ontwikkelaars
settings-interface-behavior-bvh_directory = Map om BVH-opnames op te slaan
settings-interface-behavior-bvh_directory-description = Kies een map om je BVH-opnames op te slaan, zodat je niet elke keer hoeft te kiezen waar je ze opslaat.
settings-interface-behavior-bvh_directory-label = Map voor BVH-opnames
## Serial settings
@@ -861,6 +985,17 @@ onboarding-connect_tracker-connection_status-looking_for_server = Op zoek naar s
onboarding-connect_tracker-connection_status-connection_error = Kan geen verbinding maken met Wi-Fi
onboarding-connect_tracker-connection_status-could_not_find_server = Kan de server niet vinden
onboarding-connect_tracker-connection_status-done = Verbonden met de server
onboarding-connect_tracker-connection_status-no_serial_log = Kon geen logbestanden van de tracker ophalen.
onboarding-connect_tracker-connection_status-no_serial_device_found = Kon geen tracker via USB vinden.
onboarding-connect_serial-error-modal-no_serial_log = Staat de tracker aan?
onboarding-connect_serial-error-modal-no_serial_log-desc = Zorg dat de tracker aan staat en verbonden is met je computer.
onboarding-connect_serial-error-modal-no_serial_device_found = Geen trackers gedetecteerd
onboarding-connect_serial-error-modal-no_serial_device_found-desc =
Sluit een tracker met de meegeleverde USB-kabel aan op je computer en zet de tracker aan.
Als dit niet werkt:
-probeer een andere USB-kabel
-probeer een andere USB-poort
-probeer de SlimeVR-server opnieuw te installeren en selecteer "USB Drivers" in het onderdeelkeuze-menu
# $amount (Number) - Amount of trackers connected (this is a number, but you can use CLDR plural rules for your language)
# More info on https://www.unicode.org/cldr/cldr-aux/charts/22/supplemental/language_plural_rules.html
# English in this case only has 2 plural rules, which are "one" and "other",
@@ -878,7 +1013,7 @@ onboarding-connect_tracker-next = Ik heb al mijn trackers verbonden
onboarding-calibration_tutorial = Handleiding voor IMU-kalibratie
onboarding-calibration_tutorial-subtitle = Helpt met het verminderen van het driften van de trackers!
onboarding-calibration_tutorial-description = Elke keer dat je jouw trackers inschakelt, moeten ze even op een plat oppervlak rusten om te kalibreren. Leg al je trackers op een vlak oppervlak en <b>verplaats ze niet!</b>
onboarding-calibration_tutorial-description-v1 = Zet je trackers aan en leg ze even op een stabiele ondergrond om te kalibreren. Kalibratie kan op elk moment na het inschakelen van de trackers worden uitgevoerd — deze pagina biedt alleen een handleiding. Klik op de knop "{ onboarding-calibration_tutorial-calibrate }" om te beginnen en <b>beweeg je trackers daarna niet meer!</b>
onboarding-calibration_tutorial-calibrate = Al mijn trackers liggen neer
onboarding-calibration_tutorial-status-waiting = Ik wacht op jou
onboarding-calibration_tutorial-status-calibrating = Kalibreren
@@ -1006,7 +1141,7 @@ onboarding-assign_trackers-warning-WAIST =
onboarding-choose_mounting = Welke montagekalibratiemethode moet worden gebruikt?
# Multiline text
onboarding-choose_mounting-description = De oriëntatie van de montage corrigeert de plaatsing van trackers op uw lichaam.
onboarding-choose_mounting-description = De oriëntatie van de montage corrigeert de plaatsing van trackers op je lichaam.
onboarding-choose_mounting-auto_mounting = Automatische bevestiging
# Italicized text
onboarding-choose_mounting-auto_mounting-label-v2 = Aanbevolen
@@ -1044,6 +1179,9 @@ onboarding-automatic_mounting-mounting_reset-title = Montage-reset
onboarding-automatic_mounting-mounting_reset-step-0 = 1. Ga staan in een "skie"-houding met gebogen benen, je bovenlichaam naar voren gekanteld en armen gebogen.
onboarding-automatic_mounting-mounting_reset-step-1 = 2. Druk op de knop "Reset montage" en wacht 3 seconden voordat de montagerichtingen van de trackers opnieuw worden ingesteld.
onboarding-automatic_mounting-preparation-title = Voorbereiding
onboarding-automatic_mounting-preparation-v2-step-0 = 1. Druk op de knop "Volledige reset".
onboarding-automatic_mounting-preparation-v2-step-1 = 2. Ga rechtop staan met je armen langs je zij. Zorg dat je recht vooruit kijkt.
onboarding-automatic_mounting-preparation-v2-step-2 = 3. Houd deze houding aan totdat de timer van 3 seconden is afgelopen.
onboarding-automatic_mounting-put_trackers_on-title = Doe je trackers aan
onboarding-automatic_mounting-put_trackers_on-description = Om montagerichtingen te kalibreren gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts.
onboarding-automatic_mounting-put_trackers_on-next = Ik heb al mijn trackers aan
@@ -1057,6 +1195,11 @@ onboarding-manual_proportions-fine_tuning_button-disabled-tooltip = Sluit een VR
onboarding-manual_proportions-export = Export proporties
onboarding-manual_proportions-import = Importeer proporties
onboarding-manual_proportions-file_type = Lichaamsproporties bestand
onboarding-manual_proportions-normal_increment = Normale verhoging
onboarding-manual_proportions-precise_increment = Nauwkeurige verhoging
onboarding-manual_proportions-grouped_proportions = Gegroepeerde verhoudingen
onboarding-manual_proportions-all_proportions = Alle verhoudingen
onboarding-manual_proportions-estimated_height = Geschatte gebruikerslengte
## Tracker automatic proportions setup
@@ -1074,6 +1217,8 @@ onboarding-automatic_proportions-requirements-descriptionv2 = Je hebt voldaan aa
onboarding-automatic_proportions-requirements-next = Ik heb de vereisten gelezen
onboarding-automatic_proportions-check_height-title-v3 = Meet de hoogte van uw headset
onboarding-automatic_proportions-check_height-description-v2 = De hoogte van uw headset (HMD) moet iets minder zijn dan uw volledige lengte, aangezien headsets uw ooghoogte meten. Deze meting wordt gebruikt als basis voor uw lichaamsverhoudingen.
# All the text is in bold!
onboarding-automatic_proportions-check_height-calculation_warning-v3 = Begin met meten terwijl je <u>rechtop</u> staat om je lengte te meten. Let erop dat je je handen niet hoger dan je headset tilt, want dat kan de meting beïnvloeden!
onboarding-automatic_proportions-check_height-guardian_tip = Als je een losse VR-bril gebruikt, zorg er dan voor dat je guardian/veilige zone is ingeschakeld zodat je lengte correct is gekalibreerd!
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = Onbekend
@@ -1165,6 +1310,37 @@ onboarding-scaled_proportions-done-description = Je lichaamsverhoudingen zouden
## Stay Aligned setup
onboarding-stay_aligned-title = Blijf in lijn
onboarding-stay_aligned-description = Stel Blijf in lijn in om je trackers in lijn te houden.
onboarding-stay_aligned-put_trackers_on-title = Doe je trackers aan
onboarding-stay_aligned-put_trackers_on-description = Om je ontspannen houdingen op te slaan, gebruiken we de trackers die je zojuist hebt toegewezen. Doe al je trackers om; je kunt zien welke welke zijn op de afbeelding rechts.
onboarding-stay_aligned-put_trackers_on-trackers_warning = Je hebt momenteel minder dan 5 trackers aangesloten en toegewezen! Dit is het minimale aantal trackers dat nodig is om Blijf in lijn goed te laten werken.
onboarding-stay_aligned-put_trackers_on-next = Ik heb al mijn trackers aan
onboarding-stay_aligned-verify_mounting-title = Controleer je montage
onboarding-stay_aligned-verify_mounting-step-0 = Blijf in lijn vereist een goede montage. Anders krijg je geen goede ervaring met Blijf in lijn.
onboarding-stay_aligned-verify_mounting-step-1 = 1. Beweeg terwijl je staat.
onboarding-stay_aligned-verify_mounting-step-2 = 2. Ga zitten en beweeg je benen en voeten.
onboarding-stay_aligned-verify_mounting-step-3 = 3. Als je trackers niet op de juiste plek zitten, druk dan op "Montagekalibratie opnieuw uitvoeren".
onboarding-stay_aligned-verify_mounting-redo_mounting = Montagekalibratie opnieuw uitvoeren
onboarding-stay_aligned-preparation-title = Voorbereiding
onboarding-stay_aligned-preparation-tip = Zorg dat je rechtop staat. Blijf recht vooruit kijken en houd je armen langs je zij.
onboarding-stay_aligned-relaxed_poses-standing-title = Ontspannen Staande Houding
onboarding-stay_aligned-relaxed_poses-standing-step-0 = 1. Ga in een comfortabele houding staan. Ontspan!
onboarding-stay_aligned-relaxed_poses-standing-step-1-v2 = 2. Druk op de knop "Houding opslaan".
onboarding-stay_aligned-relaxed_poses-sitting-title = Ontspannen Zittende Houding op Stoel
onboarding-stay_aligned-relaxed_poses-sitting-step-0 = 1. Ga comfortabel zitten. Ontspan!
onboarding-stay_aligned-relaxed_poses-sitting-step-1-v2 = 2. Druk op de knop "Houding opslaan".
onboarding-stay_aligned-relaxed_poses-flat-title = Ontspannen Zittende Houding op de Vloer
onboarding-stay_aligned-relaxed_poses-flat-step-0 = 1. Ga op de vloer zitten met je benen voor je uit. Ontspan!
onboarding-stay_aligned-relaxed_poses-flat-step-1-v2 = 2. Druk op de knop "Houding opslaan".
onboarding-stay_aligned-relaxed_poses-skip_step = Overslaan
onboarding-stay_aligned-done-title = Blijf in lijn ingeschakeld!
onboarding-stay_aligned-done-description = Je Blijf in lijn-instelling is voltooid!
onboarding-stay_aligned-done-description-2 = De setup is voltooid! Je kunt het proces opnieuw starten als je de houdingen opnieuw wilt kalibreren.
onboarding-stay_aligned-previous_step = Vorige
onboarding-stay_aligned-next_step = Volgende
onboarding-stay_aligned-restart = Herstarten
onboarding-stay_aligned-done = Klaar
## Home
@@ -1189,6 +1365,11 @@ status_system-StatusSteamVRDisconnected =
}
status_system-StatusTrackerError = De { $trackerName } tracker heeft een error.
status_system-StatusUnassignedHMD = De VR-headset moet worden toegewezen als hoofdtracker.
status_system-StatusPublicNetwork =
{ $count ->
[one] Je netwerkprofiel staat momenteel ingesteld op Openbaar ({ $adapters }). Dit wordt niet aanbevolen voor een goede werking van SlimeVR. <PublicFixLink>Hier lees je hoe je het kunt oplossen.</PublicFixLink>
*[other] Sommige van je netwerkadapters staan ingesteld op openbaar: { $adapters }. Dit wordt niet aanbevolen voor een goede werking van SlimeVR. <PublicFixLink>Hier lees je hoe je dit kunt oplossen.</PublicFixLink>
}
## Firmware tool globals
@@ -1201,7 +1382,7 @@ firmware_tool-loading = Laden...
## Firmware tool Steps
firmware_tool = DIY firmware-tool
firmware_tool-description = Hiermee kunt u uw DIY-trackers configureren en flashen
firmware_tool-description = Hiermee kan je uw DIY-trackers configureren en flashen
firmware_tool-not_available = Oeps, de firmwaretool is momenteel niet beschikbaar. Kom later terug!
firmware_tool-not_compatible = De firmwaretool is niet compatibel met deze versie van de server. Gelieve te updaten!
firmware_tool-board_step = Selecteer je bord
@@ -1287,6 +1468,7 @@ firmware_tool-build_step = Aan het bouwen
firmware_tool-build_step-description = De firmware wordt gebouwd, even geduld a.u.b.
firmware_tool-flashing_step = Firmware aan het uploaden
firmware_tool-flashing_step-description = Je trackers worden geflashed, volg de instructies op het scherm
firmware_tool-flashing_step-warning-v2 = Koppel de tracker niet los en zet hem niet uit tijdens het uploadproces, tenzij dit wordt aangegeven. Dit kan je apparaat onbruikbaar maken.
firmware_tool-flashing_step-flash_more = Flash meer trackers
firmware_tool-flashing_step-exit = Sluit
@@ -1304,6 +1486,7 @@ firmware_tool-build-ERROR = Kan de firmware niet bouwen
## Firmware update status
firmware_update-status-DOWNLOADING = Firmware wordt gedownload
firmware_update-status-NEED_MANUAL_REBOOT-v2 = Zet je tracker uit en daarna weer aan.
firmware_update-status-AUTHENTICATING = Authenticatie met de mcu
firmware_update-status-UPLOADING = Firmware wordt geüpload
firmware_update-status-SYNCING_WITH_MCU = Synchroniseren met de mcu
@@ -1356,6 +1539,46 @@ unknown_device-modal-title = Er is een nieuwe tracker gevonden!
unknown_device-modal-description = Er is een nieuwe tracker gevonden met MAC-adres <b>{ $deviceId }</b>. Wil je deze verbinden met SlimeVR?
unknown_device-modal-confirm = Tuurlijk!
unknown_device-modal-forget = Negeer het
# VRChat config warnings
vrc_config-page-title = VRChat-configuratie waarschuwingen
vrc_config-page-desc = Deze pagina toont de status van je VRChat-instellingen en welke instellingen niet compatibel zijn met SlimeVR. Het wordt sterk aanbevolen om eventuele waarschuwingen hier te verhelpen voor de beste gebruikservaring met SlimeVR.
vrc_config-page-help = Kan je de instellingen niet finden?
vrc_config-page-help-desc = Bekijk onze <a>documentatie over dit onderwerp!</a>
vrc_config-page-big_menu = Tracking & IK (Hoofdmenu)
vrc_config-page-big_menu-desc = IK-instellingen in het hoofdmenu
vrc_config-page-wrist_menu = Tracking & IK (Polsmenu)
vrc_config-page-wrist_menu-desc = IK-instellingen in het kleine polsmenu
vrc_config-on = Aan
vrc_config-off = Uit
vrc_config-invalid = Je VRChat-instellingen zijn verkeerd geconfigureerd!
vrc_config-show_more = Toon meer
vrc_config-setting_name = Naam van de VRChat-instelling
vrc_config-recommended_value = Aanbevolen waarde
vrc_config-current_value = Huidige waarde
vrc_config-mute = Waarschuwing dempen
vrc_config-mute-btn = Dempen
vrc_config-unmute-btn = Dempen opheffen
vrc_config-legacy_mode = Use Legacy IK Solving
vrc_config-disable_shoulder_tracking = Disable Shoulder Tracking
vrc_config-shoulder_width_compensation = Shoulder Width Compensation
vrc_config-spine_mode = FBT Spine Mode
vrc_config-tracker_model = FBT Tracker Model
vrc_config-avatar_measurement_type = Avatar Measurement
vrc_config-calibration_range = Calibration Range
vrc_config-calibration_visuals = Display Calibration Visuals
vrc_config-user_height = User Real Height
vrc_config-spine_mode-UNKNOWN = Onbekend
vrc_config-spine_mode-LOCK_BOTH = Lock Both
vrc_config-spine_mode-LOCK_HEAD = Lock Head
vrc_config-spine_mode-LOCK_HIP = Lock Hip
vrc_config-tracker_model-UNKNOWN = Onbekend
vrc_config-tracker_model-AXIS = Axis
vrc_config-tracker_model-BOX = Box
vrc_config-tracker_model-SPHERE = Sphere
vrc_config-tracker_model-SYSTEM = Systeem
vrc_config-avatar_measurement_type-UNKNOWN = Onbekend
vrc_config-avatar_measurement_type-HEIGHT = Height
vrc_config-avatar_measurement_type-ARM_SPAN = Arm Span
## Error collection consent modal

View File

@@ -268,6 +268,7 @@ navbar-settings = Ustawienia
bvh-start_recording = Nagraj BVH
bvh-recording = Nagrywanie...
bvh-save_title = Zapisz nagranie BVH
## Tracking pause
@@ -308,6 +309,7 @@ widget-imu_visualizer-rotation_raw = Raw
widget-imu_visualizer-rotation_preview = Podgląd
widget-imu_visualizer-acceleration = Akceleracja
widget-imu_visualizer-position = Pozycja
widget-imu_visualizer-stay_aligned = Wyrównywanie
## Widget: Skeleton Visualizer
@@ -335,6 +337,7 @@ tracker-table-column-temperature = Temp. °C
tracker-table-column-linear-acceleration = Akceleracja X/Y/Z
tracker-table-column-rotation = Rotacja X/Y/Z
tracker-table-column-position = Pozycja X/Y/Z
tracker-table-column-stay_aligned = Wyrównywanie
tracker-table-column-url = URL
## Tracker rotation
@@ -403,6 +406,7 @@ tracker-settings-forget-label = Zapomnij o trackerze
tracker-settings-update-unavailable = Nie można zaktualizować (zrób to sam)
tracker-settings-update-low-battery = Nie można zaktualizować. Bateria poniżej 50%
tracker-settings-update-up_to_date = Aktualny
tracker-settings-update-blocked = Aktualizacja niedostępna. Brak innych wersji
tracker-settings-update-available = Wersja { $versionName } jest już dostępna
tracker-settings-update = Zaktualizuj teraz
tracker-settings-update-title = Wersja oprogramowania
@@ -472,6 +476,7 @@ mounting_selection_menu-close = Zamknij
settings-sidebar-title = Ustawienia
settings-sidebar-general = Ogólne
settings-sidebar-tracker_mechanics = Mechanika trackerów
settings-sidebar-stay_aligned = Wyrównywanie
settings-sidebar-fk_settings = Ustawienia śledzenia
settings-sidebar-gesture_control = Sterowanie gestami
settings-sidebar-interface = Interfejs
@@ -481,7 +486,9 @@ settings-sidebar-utils = Narzędzia
settings-sidebar-serial = Konsola szeregowa
settings-sidebar-appearance = Wygląd
settings-sidebar-notifications = Powiadomienia
settings-sidebar-behavior = Zachowanie
settings-sidebar-firmware-tool = Narzędzie do oprogramowania sprzętowego DIY
settings-sidebar-vrc_warnings = Ostrzeżenia dotyczące konfiguracji VRChat
settings-sidebar-advanced = Zaawansowany
## SteamVR settings
@@ -563,6 +570,25 @@ settings-general-tracker_mechanics-use_mag_on_all_trackers-description =
Wykorzystuje magnetometr we wszystkich trackerach, które mają kompatybilne oprogramowanie sprzętowe, redukując dryf w stabilnych środowiskach magnetycznych.¶
Można wyłączyć dla każdego modułu śledzącego w ustawieniach modułu śledzącego. <b>Proszę nie wyłączać żadnego modułu śledzącego podczas przełączania!</b>
settings-general-tracker_mechanics-use_mag_on_all_trackers-label = Użyj magnetometru na trackerach
settings-stay_aligned = Wyrównywanie
settings-stay_aligned-description = Wyrównywanie zmniejsza efekt driftu, stopniowo dostosowując trackery do twoich zrelaksowanych póz.
settings-stay_aligned-setup-label = Konfiguracja Opcji Wyrównywania
settings-stay_aligned-setup-description = Musisz ukończyć konfigurację, aby włączyć opcję Wyrównywania.
settings-stay_aligned-warnings-drift_compensation = ⚠ Wyłącz kompensację Driftu, będzie ona kolidować z opcją Wyrównywania!
settings-stay_aligned-enabled-label = Dostosuj trackery
settings-stay_aligned-hide_yaw_correction-label = Ukryj dopasowanie (do porównania bez opcji Wyrównywania)
settings-stay_aligned-general-label = Ogólne
settings-stay_aligned-relaxed_poses-label = Zrelaksowane pozy
settings-stay_aligned-relaxed_poses-description = Opcja Wyrównywania wykorzystuje Twoje zrelaksowane pozy, aby utrzymać trackery w jednej linii. Użyj opcji "Konfiguracja Opcji Wyrównywania", aby zaktualizować te pozy.
settings-stay_aligned-relaxed_poses-standing = Dostosuj trackery w pozycji stojącej
settings-stay_aligned-relaxed_poses-sitting = Dostosuj trackery, siedząc na krześle
settings-stay_aligned-relaxed_poses-flat = Dostosuj trackery, siedząc na podłodze lub leżąc na plecach
settings-stay_aligned-relaxed_poses-save_pose = Zapisz pozę
settings-stay_aligned-relaxed_poses-reset_pose = Zresetuj Pozycję
settings-stay_aligned-relaxed_poses-close = Zamknij
settings-stay_aligned-debug-label = Debugowanie
settings-stay_aligned-debug-description = Proszę dołączać ustawienia, podczas zgłaszania problemów z opcją Wyrównywania.
settings-stay_aligned-debug-copy-label = Skopiuj ustawienia do schowka
## FK/Tracking settings
@@ -725,6 +751,9 @@ settings-interface-behavior-error_tracking-description_v2 =
Aby zapewnić jak najlepsze wrażenia użytkownika, gromadzimy anonimowe raporty o błędach, wskaźniki wydajności i informacje o systemie operacyjnym. Pomaga nam to wykrywać błędy i problemy ze SlimeVR. Dane te są zbierane za pomocą Sentry.io.
settings-interface-behavior-error_tracking-label = Wysyłanie błędów do deweloperów
settings-interface-behavior-bvh_directory = Ścieżka do zapisywania nagrań BVH
settings-interface-behavior-bvh_directory-description = Wybierz ścieżkę domyślną, w której chcesz zapisywać nagrania BVH.
settings-interface-behavior-bvh_directory-label = Ścieżka do nagrań BVH
## Serial settings
@@ -788,6 +817,7 @@ settings-osc-vrchat-description-v1 =
settings-osc-vrchat-enable = Zezwól
settings-osc-vrchat-enable-description = Zezwól na wysyłanie i odbieranie danych.
settings-osc-vrchat-enable-label = Zezwól
settings-osc-vrchat-oscqueryEnabled = Włącz OSCQuery
settings-osc-vrchat-oscqueryEnabled-description =
OSCQuery automatycznie wykrywa uruchomione instancje VRChat i wysyła im dane.
Może również reklamować się do nich w celu otrzymania danych HMD i administratora.
@@ -994,7 +1024,7 @@ onboarding-connect_tracker-next = Połączyłem już wszystkie trackery
onboarding-calibration_tutorial = Samouczek kalibracji IMU
onboarding-calibration_tutorial-subtitle = Pomoże to ograniczyć dryf trackera!
onboarding-calibration_tutorial-description = Za każdym razem, gdy włączasz trackery, muszą one chwilę polerzeć na płaskiej powierzchni, aby się skalibrować. Zróbmy to samo, klikając przycisk „Kalibruj”, <b>nie ruszaj ich!</b>
onboarding-calibration_tutorial-description-v1 = Po włączeniu trackerów umieść je na chwilę na stabilnej powierzchni, aby umożliwić kalibrację. Kalibrację można przeprowadzić w dowolnym momencie po włączeniu trackerów - ta strona zawiera po prostu samouczek. Aby rozpocząć, kliknij przycisk "{ onboarding-calibration_tutorial-calibrate }", a następnie <b>nie ruszaj swoich trackerów!</b>
onboarding-calibration_tutorial-calibrate = Położyłem trackery na stole
onboarding-calibration_tutorial-status-waiting = Czekam na Ciebie
onboarding-calibration_tutorial-status-calibrating = Kalibracja
@@ -1165,6 +1195,9 @@ onboarding-automatic_mounting-mounting_reset-title = Kalibracja Pozycji
onboarding-automatic_mounting-mounting_reset-step-0 = 1. Zrób pozycje "na Małysza" z wygiętymi nogami, tułowiem pochylonym do przodu z wygiętymi rękami.
onboarding-automatic_mounting-mounting_reset-step-1 = 2. Naciśnij "Zresetuj Położenie" i poczekaj 3 sekundy zanim trackery się zresetują.
onboarding-automatic_mounting-preparation-title = Przygotowania
onboarding-automatic_mounting-preparation-v2-step-0 = 1. Naciśnij przycisk "Pełny reset".
onboarding-automatic_mounting-preparation-v2-step-1 = 2. Stań prosto z rękami po bokach. Upewnij się, że patrzysz przed siebie.
onboarding-automatic_mounting-preparation-v2-step-2 = 3. Utrzymaj pozycję, aż skończy się 3-sekundowy timer.
onboarding-automatic_mounting-put_trackers_on-title = Załóż trackery
onboarding-automatic_mounting-put_trackers_on-description = Aby skalibrować rotacje, użyjemy trackerów które przypisano przed chwilą. Załóż wszystkie trackery, możesz je odróznić na postaci po prawej.
onboarding-automatic_mounting-put_trackers_on-next = Wszystkie trackery założone
@@ -1298,6 +1331,37 @@ onboarding-scaled_proportions-done-description = Proporcje Twojego ciała powinn
## Stay Aligned setup
onboarding-stay_aligned-title = Wyrównywanie
onboarding-stay_aligned-description = Skonfiguruj opcję Wyrównywania, aby Twoje trackery były wyrównane.
onboarding-stay_aligned-put_trackers_on-title = Załóż trackery
onboarding-stay_aligned-put_trackers_on-description = Aby skalibrować proporcje, użyjemy trackerów które przed chwilą przypisałeś. Załóż wszystkie trackery, będziesz widział który to który na postaci po prawej.
onboarding-stay_aligned-put_trackers_on-trackers_warning = Masz mniej niż 5 trackerów aktualnie podłączonych i przypisanych! Jest to minimalna liczba elementów śledzących wymaganych do prawidłowego działania opcji Wyrównywania.
onboarding-stay_aligned-put_trackers_on-next = Mam wszystkie trackery założone
onboarding-stay_aligned-verify_mounting-title = Sprawdź swój montaż
onboarding-stay_aligned-verify_mounting-step-0 = Opcja Wyrównywania wymaga stabilnego mocowania trackera. W innym przypadku będziesz miał złe rezultaty.
onboarding-stay_aligned-verify_mounting-step-1 = 1. Poruszaj się podczas stania.
onboarding-stay_aligned-verify_mounting-step-2 = 2. Usiądź i poruszaj nogami i stopami.
onboarding-stay_aligned-verify_mounting-step-3 = 3. Jeśli Twoje trackery nie znajdują się we właściwym miejscu, naciśnij "Ponów kalibrację montażu".
onboarding-stay_aligned-verify_mounting-redo_mounting = Ponów kalibrację montażu
onboarding-stay_aligned-preparation-title = Przygotowania
onboarding-stay_aligned-preparation-tip = Upewnij się, że stoisz prosto. Patrz przed siebie z rękami opuszczonymi po bokach.
onboarding-stay_aligned-relaxed_poses-standing-title = Zrelaksowana pozycja stojąca
onboarding-stay_aligned-relaxed_poses-standing-step-0 = 1. Stań w wygodnej pozycji. Zrelaksuj się!
onboarding-stay_aligned-relaxed_poses-standing-step-1-v2 = 2. Naciśnij przycisk "Zapisz pozę".
onboarding-stay_aligned-relaxed_poses-sitting-title = Zrelaksowana pozycja siedząca na krześle
onboarding-stay_aligned-relaxed_poses-sitting-step-0 = 1. Usiądź w wygodnej pozycji. Zrelaksuj się!
onboarding-stay_aligned-relaxed_poses-sitting-step-1-v2 = 2. Naciśnij przycisk "Zapisz pozę".
onboarding-stay_aligned-relaxed_poses-flat-title = Zrelaksowana pozycja siedząca na podłodze
onboarding-stay_aligned-relaxed_poses-flat-step-0 = 1. Usiądź na podłodze z nogami wysuniętymi do przodu. Zrelaksuj się!
onboarding-stay_aligned-relaxed_poses-flat-step-1-v2 = 2. Naciśnij przycisk "Zapisz pozę".
onboarding-stay_aligned-relaxed_poses-skip_step = Pomiń
onboarding-stay_aligned-done-title = Wyrównywanie Włączone!
onboarding-stay_aligned-done-description = Konfiguracja Wyrównywania jest zakończona!
onboarding-stay_aligned-done-description-2 = Konfiguracja została zakończona! Możesz ponownie uruchomić proces, jeśli chcesz ponownie skalibrować pozy.
onboarding-stay_aligned-previous_step = Poprzednie
onboarding-stay_aligned-next_step = Następne
onboarding-stay_aligned-restart = Restart
onboarding-stay_aligned-done = Gotowy
## Home
@@ -1322,6 +1386,12 @@ status_system-StatusSteamVRDisconnected =
}
status_system-StatusTrackerError = Tracker { $trackerName } ma błąd.
status_system-StatusUnassignedHMD = Headset powinien być przypisany do śledzenia głowy.
status_system-StatusPublicNetwork =
{ $count ->
[one] Twoja karta sieciowa jest ustawiona jako publiczna: { $adapters }. Nie jest to zalecane, aby SlimeVR działał poprawnie. <PublicFixLink>Zobacz, jak to naprawić tutaj.</PublicFixLink>
[few] Niektóre karty sieciowe są ustawione jako publiczne: { $adapters }. Nie jest to zalecane, aby SlimeVR działał poprawnie. <PublicFixLink>Zobacz, jak to naprawić tutaj.</PublicFixLink>
*[many] Dużo twoich karty sieciowych jest ustawionych jako publiczne: { $adapters }. Nie jest to zalecane, aby SlimeVR działał poprawnie. <PublicFixLink>Zobacz, jak to naprawić tutaj.</PublicFixLink>
}
## Firmware tool globals
@@ -1423,6 +1493,7 @@ firmware_tool-build_step = Building
firmware_tool-build_step-description = Trwa tworzenie oprogramowania sprzętowego. Proszę czekać
firmware_tool-flashing_step = Flashing
firmware_tool-flashing_step-description = Twoje trackery migają. Postępuj zgodnie z instrukcjami wyświetlanymi na ekranie
firmware_tool-flashing_step-warning-v2 = Nie odłączaj ani nie wyłączaj trackera podczas procesu przesyłania, chyba że zostaniesz o to poproszony, może to spowodować, że twoje urządzenie stanie się bezużyteczne.
firmware_tool-flashing_step-flash_more = Flashuj więcej trackerów
firmware_tool-flashing_step-exit = Wyjście
@@ -1440,6 +1511,7 @@ firmware_tool-build-ERROR = Nie można zbudować oprogramowania sprzętowego
## Firmware update status
firmware_update-status-DOWNLOADING = Pobieranie oprogramowania sprzętowego
firmware_update-status-NEED_MANUAL_REBOOT-v2 = Wyłącz i ponownie włącz swój tracker
firmware_update-status-AUTHENTICATING = Uwierzytelnianie za pomocą MCU
firmware_update-status-UPLOADING = Przesyłanie oprogramowania sprzętowego
firmware_update-status-SYNCING_WITH_MCU = Synchronizacja z MCU
@@ -1510,6 +1582,9 @@ vrc_config-show_more = Pokaż więcej
vrc_config-setting_name = Nazwa ustawienia VRChat
vrc_config-recommended_value = Zalecana wartość
vrc_config-current_value = Bieżąca wartość
vrc_config-mute = Wycisz Ostrzeżenie
vrc_config-mute-btn = Wycisz
vrc_config-unmute-btn = Odcisz
vrc_config-legacy_mode = Korzystanie ze starszego rozwiązywania kinematyki odwrotnej
vrc_config-disable_shoulder_tracking = Wyłącz śledzenie ramienia
vrc_config-shoulder_width_compensation = Kompensacja szerokości barku

View File

@@ -233,6 +233,8 @@ reset-reset_all_warning_default-v2 =
您确定要执行此操作吗?
reset-full = 完整重置
reset-mounting = 重置佩戴
reset-mounting-feet = 重置脚部佩戴
reset-mounting-fingers = 重置手指佩戴
reset-yaw = 重置航向轴
## Serial detection stuff
@@ -258,6 +260,7 @@ navbar-settings = 设置
bvh-start_recording = 录制 BVH 文件
bvh-recording = 录制中...
bvh-save_title = 保存BVH记录
## Tracking pause
@@ -395,6 +398,7 @@ tracker-settings-forget-label = 忘记追踪器
tracker-settings-update-unavailable = 无法升级DIY
tracker-settings-update-low-battery = 无法更新。当前电池电量低于 50%
tracker-settings-update-up_to_date = 已是最新
tracker-settings-update-blocked = 更新不可用。没有其他可用版本
tracker-settings-update-available = { $versionName } 现在可用
tracker-settings-update = 立即更新
tracker-settings-update-title = 固件版本
@@ -573,6 +577,7 @@ settings-stay_aligned-relaxed_poses-sitting = 椅子上放松姿势
settings-stay_aligned-relaxed_poses-flat = 地面/平躺放松姿势
settings-stay_aligned-relaxed_poses-save_pose = 保存姿势
settings-stay_aligned-relaxed_poses-reset_pose = 重置姿势
settings-stay_aligned-relaxed_poses-close = 关闭
settings-stay_aligned-debug-label = 调试
settings-stay_aligned-debug-description = 在报告持续校准相关问题时,请包含您的以下设置信息
settings-stay_aligned-debug-copy-label = 复制设置信息到剪贴板
@@ -727,6 +732,9 @@ settings-interface-behavior-error_tracking-description_v2 =
为了提供最佳用户体验,我们会收集匿名错误报告、性能指标和操作系统信息。这有助于我们检测 SlimeVR 的错误和问题。这些指标将通过 Sentry.io 收集。
settings-interface-behavior-error_tracking-label = 向开发人员发送错误信息
settings-interface-behavior-bvh_directory = BVH记录保存目录
settings-interface-behavior-bvh_directory-description = 选择保存BVH记录文件的目录
settings-interface-behavior-bvh_directory-label = BVH记录保存目录
## Serial settings
@@ -997,7 +1005,7 @@ onboarding-connect_tracker-next = 所有的追踪器都连接好了
onboarding-calibration_tutorial = IMU校准教程
onboarding-calibration_tutorial-subtitle = 这将有助于减少追踪器漂移!
onboarding-calibration_tutorial-description = 每次开启追踪器时,它们都需要在平坦的表面上放置片刻以进行校准。你也可以通过点击“{ onboarding-calibration_tutorial-calibrate }”按钮来手动校准, <b>校准过程中不要移动追踪器!</b>
onboarding-calibration_tutorial-description-v1 = 打开追踪器后,将它们放在稳定的平面上一段时间,以便进行校准。追踪器开机后可随时进行校准 - 本页仅是一个校准教程。首先,点击 “{ onboarding-calibration_tutorial-calibrate }” 按钮,然后 <b>不要移动您的追踪器!</b>
onboarding-calibration_tutorial-calibrate = 我已经把追踪器放在桌子上了
onboarding-calibration_tutorial-status-waiting = 等待你的操作
onboarding-calibration_tutorial-status-calibrating = 校准中
@@ -1301,13 +1309,13 @@ onboarding-stay_aligned-preparation-title = 准备
onboarding-stay_aligned-preparation-tip = 站直并向前看,双臂放在身体两侧。
onboarding-stay_aligned-relaxed_poses-standing-title = 站立放松姿势
onboarding-stay_aligned-relaxed_poses-standing-step-0 = 1. 以舒适的姿势站立并放松。
onboarding-stay_aligned-relaxed_poses-standing-step-2 = 3. 按下“检测姿势”按钮。
onboarding-stay_aligned-relaxed_poses-standing-step-1-v2 = 2. 按下“保存姿势”按钮。
onboarding-stay_aligned-relaxed_poses-sitting-title = 椅子上放松姿势
onboarding-stay_aligned-relaxed_poses-sitting-step-0 = 1. 以舒适的姿势坐下并放松。
onboarding-stay_aligned-relaxed_poses-sitting-step-2 = 3. 按下“检测姿势”按钮。
onboarding-stay_aligned-relaxed_poses-sitting-step-1-v2 = 2. 按下“保存姿势”按钮。
onboarding-stay_aligned-relaxed_poses-flat-title = 地面/平躺放松姿势
onboarding-stay_aligned-relaxed_poses-flat-step-0 = 1. 以舒适的姿势坐或躺在地面上,保持腿在前方并放松。
onboarding-stay_aligned-relaxed_poses-flat-step-2 = 3. 按下“检测姿势”按钮。
onboarding-stay_aligned-relaxed_poses-flat-step-1-v2 = 2. 按下“保存姿势”按钮。
onboarding-stay_aligned-relaxed_poses-skip_step = 跳过
onboarding-stay_aligned-done-title = 持续校准已开启!
onboarding-stay_aligned-done-description = 持续校准已设定完成!

View File

@@ -31,7 +31,7 @@ serde = { version = "1", features = ["derive"] }
tauri = { version = "2.0", features = ["devtools", "tray-icon", "image-png", "rustls-tls"] }
tauri-runtime = "2.0"
tauri-plugin-dialog = "2.0"
tauri-plugin-fs = "2.0"
tauri-plugin-fs = "2.4.1"
tauri-plugin-os = "2.0"
tauri-plugin-shell = "2.0"
tauri-plugin-store = "2.0"

View File

@@ -65,6 +65,10 @@ work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
</provides>
<releases>
<release version="0.16.2" date="2025-08-01"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.2</url></release>
<release version="0.16.1" date="2025-07-27"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.1</url></release>
<release version="0.16.1~rc.2" type="development" date="2025-07-17"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.1-rc.2</url></release>
<release version="0.16.1~rc.1" type="development" date="2025-07-04"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.1-rc.1</url></release>
<release version="0.16.0" date="2025-07-01"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.0</url></release>
<release version="0.16.0~rc.2" type="development" date="2025-06-20"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.0-rc.2</url></release>
<release version="0.16.0~rc.1" type="development" date="2025-05-27"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.16.0-rc.1</url></release>

View File

@@ -206,6 +206,11 @@ export default function App() {
}, []);
useEffect(() => {
// don't show update stuff when on android
if (window.__ANDROID__?.isThere()) {
setUpdateFound('');
return;
}
async function fetchReleases() {
const releases = await fetch(
`https://api.github.com/repos/${GH_REPO}/releases`

View File

@@ -55,10 +55,18 @@ export function WidgetsComponent() {
<ResetButton type={ResetType.Yaw} size="big"></ResetButton>
<ResetButton type={ResetType.Full} size="big"></ResetButton>
<ResetButton type={ResetType.Mounting} size="big"></ResetButton>
<ResetButton
type={ResetType.Mounting}
size="big"
bodyPartsToReset="feet"
></ResetButton>
<ResetButton
type={ResetType.Mounting}
size="big"
bodyPartsToReset="fingers"
></ResetButton>
<ClearMountingButton></ClearMountingButton>
{(typeof __ANDROID__ === 'undefined' || !__ANDROID__?.isThere()) && (
<BVHButton></BVHButton>
)}
{!window.__ANDROID__?.isThere() && <BVHButton></BVHButton>}
<TrackingPauseButton></TrackingPauseButton>
</div>
<div className="w-full">

View File

@@ -28,7 +28,7 @@ export function ArrowLink({
};
return classNames(
variantsMap[variant],
'flex gap-2 hover:fill-background-10 hover:text-background-10 fill-background-30 text-background-30'
'flex gap-2 hover:fill-background-10 fill-background-30 text-background-10'
);
}, [variant]);

View File

@@ -53,7 +53,7 @@ export function CheckBox({
className={classNames(
{
'rounded-lg': outlined,
'text-background-30': !outlined || disabled,
'text-background-10': !outlined || disabled,
'bg-background-60': outlined && color === 'primary',
'bg-background-70': outlined && color === 'secondary',
'bg-background-50': outlined && color === 'tertiary',

View File

@@ -12,6 +12,8 @@ import { FileIcon } from './icon/FileIcon';
import { UploadFileIcon } from './icon/UploadFileIcon';
import { Typography } from './Typography';
import { CloseIcon } from './icon/CloseIcon';
import { FolderIcon } from './icon/FolderIcon';
import { UploadFolderIcon } from './icon/UploadFolderIcon';
interface InputProps {
variant?: 'primary' | 'secondary';
@@ -22,9 +24,11 @@ interface InputProps {
export const FileInputContentBlank = ({
isDragging,
label,
directory = false,
}: {
isDragging: boolean;
label: string;
directory?: boolean;
}) => {
return (
<div
@@ -36,7 +40,11 @@ export const FileInputContentBlank = ({
)}
>
<span className="flex items-center space-x-2 pointer-events-none">
<UploadFileIcon isDragging={isDragging} />
{directory ? (
<UploadFolderIcon isDragging={isDragging} />
) : (
<UploadFileIcon isDragging={isDragging} />
)}
<div>
<Localized
id={label}
@@ -57,10 +65,12 @@ export const FileInputContentBlank = ({
export const FileInputContentFile = ({
importedFileName,
directory = false,
onClearPicker,
}: {
importedFileName: string;
onClearPicker: () => any;
directory?: boolean;
}) => {
return (
<div
@@ -72,7 +82,7 @@ export const FileInputContentFile = ({
>
<div className="flex items-center space-x-2">
<div className="flex items-center space-x-2 px-4">
<FileIcon />
{directory ? <FolderIcon /> : <FileIcon />}
<span>{importedFileName}</span>
</div>
<span className="flex-grow"></span>

View File

@@ -47,19 +47,19 @@ export const InputInside = forwardRef<
const classes = useMemo(() => {
const variantsMap = {
primary: classNames({
'placeholder:text-background-30 bg-background-60 border-background-60':
'placeholder:text-background-10 placeholder:italic bg-background-60 border-background-60':
!disabled,
'text-background-30 placeholder:text-background-30 border-background-70 bg-background-70':
disabled,
}),
secondary: classNames({
'placeholder:text-background-30 bg-background-50 border-background-50':
'placeholder:text-background-10 placeholder:italic bg-background-50 border-background-50':
!disabled,
'text-background-40 placeholder:text-background-40 border-background-70 bg-background-70':
disabled,
}),
tertiary: classNames({
'placeholder:text-background-30 bg-background-40 border-background-40':
'placeholder:text-background-10 placeholder:italic bg-background-40 border-background-40':
!disabled,
'text-background-30 placeholder:text-background-30 border-background-70 bg-background-70':
disabled,

View File

@@ -51,9 +51,7 @@ export function Radio({
<div className="flex flex-col gap-2 pointer-events-none">
{children ? children : <Typography bold>{label}</Typography>}
{description && (
<Typography variant="standard" color="secondary">
{description}
</Typography>
<Typography variant="standard">{description}</Typography>
)}
</div>
</label>

View File

@@ -24,10 +24,11 @@ export function InnerTauriFileInput({
<div ref={ref} onClick={async () => onChange(await open({ directory }))}>
{value !== null
? FileInputContentFile({
directory,
importedFileName: value,
onClearPicker: () => onChange(null),
})
: FileInputContentBlank({ isDragging: false, label })}
: FileInputContentBlank({ isDragging: false, label, directory })}
</div>
);
}

View File

@@ -0,0 +1,12 @@
export function FolderIcon({ width = 24 }: { width?: number }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
width={width}
>
<path d="M19.5 21a3 3 0 0 0 3-3v-4.5a3 3 0 0 0-3-3h-15a3 3 0 0 0-3 3V18a3 3 0 0 0 3 3h15ZM1.5 10.146V6a3 3 0 0 1 3-3h5.379a2.25 2.25 0 0 1 1.59.659l2.122 2.121c.14.141.331.22.53.22H19.5a3 3 0 0 1 3 3v1.146A4.483 4.483 0 0 0 19.5 9h-15a4.483 4.483 0 0 0-3 1.146Z" />
</svg>
);
}

View File

@@ -0,0 +1,25 @@
import classNames from 'classnames';
export function UploadFolderIcon({
width = 24,
isDragging = false,
}: {
width?: number;
isDragging?: boolean;
}) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 5.5499997 4.7600007"
width={width}
fill="currentColor"
className={classNames('transition-transform', isDragging && 'scale-150')}
>
<path
fill-rule="evenodd"
d="m 4.76,4.76 c 0.44,0 0.79,-0.36 0.79,-0.79 v -2.39 c 0,-0.44 -0.36,-0.79 -0.79,-0.79 H 3.34 c -0.05,0 -0.1,-0.02 -0.14,-0.06 L 2.64,0.17 C 2.53,0.06 2.38,0 2.22,0 H 0.79 C 0.35,0 0,0.36 0,0.79 V 3.97 C 0,4.41 0.36,4.76 0.79,4.76 Z M 2.58,3.71 c 0,0.26 0.4,0.26 0.4,0 V 2.6 L 3.44,3.06 C 3.63,3.23 3.89,2.97 3.72,2.78 L 2.93,1.99 c -0.08,-0.08 -0.2,-0.08 -0.28,0 L 1.86,2.78 C 1.65,2.97 1.95,3.26 2.14,3.06 L 2.6,2.6 Z"
clip-rule="evenodd"
/>
</svg>
);
}

View File

@@ -240,7 +240,7 @@ export function AddImusStep({
<>
<div className="flex flex-col w-full">
<div className="flex flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-add_imus_step-description')}
</Typography>
</div>
@@ -297,7 +297,7 @@ export function AddImusStep({
<div className="flex justify-center flex-col items-center gap-3 h-44">
<LoaderIcon slimeState={SlimeState.JUMPY}></LoaderIcon>
<Localized id="firmware_tool-loading">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
)}

View File

@@ -53,7 +53,7 @@ export function BoardPinsStep({
<>
<div className="flex flex-col w-full justify-between text-background-10">
<div className="flex flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-board_pins_step-description')}
</Typography>
</div>
@@ -172,7 +172,7 @@ export function BoardPinsStep({
<div className="flex justify-center flex-col items-center gap-3 h-44">
<LoaderIcon slimeState={SlimeState.JUMPY}></LoaderIcon>
<Localized id="firmware_tool-loading">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
)}

View File

@@ -68,7 +68,7 @@ export function BuildStep({
<>
<div className="flex flex-col w-full">
<div className="flex flex-grow flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-build_step-description')}
</Typography>
</div>
@@ -82,7 +82,7 @@ export function BuildStep({
: SlimeState.SAD
}
></LoaderIcon>
<Typography variant="section-title" color="secondary">
<Typography variant="section-title">
{l10n.getString('firmware_tool-build-' + buildStatus.status)}
</Typography>
</div>
@@ -91,7 +91,7 @@ export function BuildStep({
<div className="flex justify-center flex-col items-center gap-3 h-44">
<LoaderIcon slimeState={SlimeState.JUMPY}></LoaderIcon>
<Localized id="firmware_tool-loading">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
)}

View File

@@ -85,9 +85,7 @@ function FirmwareToolContent() {
.getString('firmware_tool-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>

View File

@@ -22,7 +22,7 @@ export function FlashBtnStep({
<>
<div className="flex flex-col w-full">
<div className="flex flex-grow flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-flashbtn_step-description')}
</Typography>
{defaultConfig?.boardConfig.type ===

View File

@@ -160,7 +160,7 @@ function SerialDevicesList({
</Localized>
{Object.keys(devices).length === 0 ? (
<Localized id="firmware_tool-flash_method_serial-no_devices">
<Typography variant="standard" color="secondary"></Typography>
<Typography variant="standard"></Typography>
</Localized>
) : (
<Dropdown
@@ -274,7 +274,7 @@ function OTADevicesList({
</Localized>
{devices.length === 0 && (
<Localized id="firmware_tool-flash_method_ota-no_devices">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
)}
<div className="grid xs-settings:grid-cols-2 mobile-settings:grid-cols-1 gap-2">
@@ -347,7 +347,7 @@ export function FlashingMethodStep({
<>
<div className="flex flex-col w-full">
<div className="flex flex-grow flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-flash_method_step-description')}
</Typography>
</div>
@@ -416,7 +416,7 @@ export function FlashingMethodStep({
<div className="flex justify-center flex-col items-center gap-3 h-44">
<LoaderIcon slimeState={SlimeState.JUMPY}></LoaderIcon>
<Localized id="firmware_tool-loading">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
)}

View File

@@ -164,7 +164,7 @@ export function FlashingStep({
<>
<div className="flex flex-col w-full">
<div className="flex flex-grow flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-flashing_step-description')}
</Typography>
</div>

View File

@@ -27,7 +27,7 @@ export function SelectBoardStep({
<>
<div className="flex flex-col w-full">
<div className="flex flex-grow flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-board_step-description')}
</Typography>
</div>
@@ -91,7 +91,7 @@ export function SelectBoardStep({
<div className="flex justify-center flex-col items-center gap-3 h-44">
<LoaderIcon slimeState={SlimeState.JUMPY}></LoaderIcon>
<Localized id="firmware_tool-loading">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
)}

View File

@@ -40,7 +40,7 @@ export function SelectFirmwareStep({
<>
<div className="flex flex-col w-full">
<div className="flex justify-between items-center mobile:flex-col gap-4">
<Typography color="secondary">
<Typography>
{l10n.getString('firmware_tool-select_firmware_step-description')}
</Typography>
<div>
@@ -109,7 +109,7 @@ export function SelectFirmwareStep({
<div className="flex justify-center flex-col items-center gap-3 h-44">
<LoaderIcon slimeState={SlimeState.JUMPY}></LoaderIcon>
<Localized id="firmware_tool-loading">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
)}

View File

@@ -320,7 +320,7 @@ export function FirmwareUpdate() {
<Typography variant="section-title"></Typography>
</Localized>
<Localized id="firmware_update-devices-description">
<Typography variant="standard" color="secondary"></Typography>
<Typography variant="standard"></Typography>
</Localized>
<div className="flex flex-col gap-4 overflow-y-auto xs:max-h-[530px]">
{devices.length === 0 &&

View File

@@ -1,6 +1,7 @@
import { useLocalization } from '@fluent/react';
import { useEffect, useMemo, useRef, useState } from 'react';
import {
BodyPart,
ResetRequestT,
ResetType,
RpcMessage,
@@ -22,16 +23,20 @@ import {
} from '@/components/commons/icon/ResetIcon';
import { useStatusContext } from '@/hooks/status-system';
import classNames from 'classnames';
import { FootIcon } from '@/components/commons/icon/FootIcon';
import { FingersIcon } from '@/components/commons/icon/FingersIcon';
export function ResetButton({
type,
size = 'big',
bodyPartsToReset = 'default',
className,
onReseted,
}: {
className?: string;
type: ResetType;
size: 'big' | 'small';
bodyPartsToReset?: 'default' | 'feet' | 'fingers';
onReseted?: () => void;
}) {
const { l10n } = useLocalization();
@@ -50,9 +55,55 @@ export function ResetButton({
[statuses]
);
const feetBodyParts = [BodyPart.LEFT_FOOT, BodyPart.RIGHT_FOOT];
const fingerBodyParts = [
BodyPart.LEFT_THUMB_METACARPAL,
BodyPart.LEFT_THUMB_PROXIMAL,
BodyPart.LEFT_THUMB_DISTAL,
BodyPart.LEFT_INDEX_PROXIMAL,
BodyPart.LEFT_INDEX_INTERMEDIATE,
BodyPart.LEFT_INDEX_DISTAL,
BodyPart.LEFT_MIDDLE_PROXIMAL,
BodyPart.LEFT_MIDDLE_INTERMEDIATE,
BodyPart.LEFT_MIDDLE_DISTAL,
BodyPart.LEFT_RING_PROXIMAL,
BodyPart.LEFT_RING_INTERMEDIATE,
BodyPart.LEFT_RING_DISTAL,
BodyPart.LEFT_LITTLE_PROXIMAL,
BodyPart.LEFT_LITTLE_INTERMEDIATE,
BodyPart.LEFT_LITTLE_DISTAL,
BodyPart.RIGHT_THUMB_METACARPAL,
BodyPart.RIGHT_THUMB_PROXIMAL,
BodyPart.RIGHT_THUMB_DISTAL,
BodyPart.RIGHT_INDEX_PROXIMAL,
BodyPart.RIGHT_INDEX_INTERMEDIATE,
BodyPart.RIGHT_INDEX_DISTAL,
BodyPart.RIGHT_MIDDLE_PROXIMAL,
BodyPart.RIGHT_MIDDLE_INTERMEDIATE,
BodyPart.RIGHT_MIDDLE_DISTAL,
BodyPart.RIGHT_RING_PROXIMAL,
BodyPart.RIGHT_RING_INTERMEDIATE,
BodyPart.RIGHT_RING_DISTAL,
BodyPart.RIGHT_LITTLE_PROXIMAL,
BodyPart.RIGHT_LITTLE_INTERMEDIATE,
BodyPart.RIGHT_LITTLE_DISTAL,
];
const reset = () => {
const req = new ResetRequestT();
req.resetType = type;
switch (bodyPartsToReset) {
case 'default':
// Server handles it. Usually all body parts except fingers.
req.bodyParts = [];
break;
case 'feet':
req.bodyParts = feetBodyParts;
break;
case 'fingers':
req.bodyParts = fingerBodyParts;
break;
}
sendRPCPacket(RpcMessage.ResetRequest, req);
};
@@ -75,20 +126,36 @@ export function ResetButton({
const text = useMemo(() => {
switch (type) {
case ResetType.Yaw:
return l10n.getString('reset-yaw');
return l10n.getString(
'reset-yaw' +
(bodyPartsToReset !== 'default' ? '-' + bodyPartsToReset : '')
);
case ResetType.Mounting:
return l10n.getString('reset-mounting');
return l10n.getString(
'reset-mounting' +
(bodyPartsToReset !== 'default' ? '-' + bodyPartsToReset : '')
);
case ResetType.Full:
return l10n.getString('reset-full');
return l10n.getString(
'reset-full' +
(bodyPartsToReset !== 'default' ? '-' + bodyPartsToReset : '')
);
}
}, [type]);
}, [type, bodyPartsToReset]);
const getIcon = () => {
switch (type) {
case ResetType.Yaw:
return <YawResetIcon width={20} />;
case ResetType.Mounting:
return <MountingResetIcon width={20} />;
switch (bodyPartsToReset) {
case 'default':
return <MountingResetIcon width={20} />;
case 'feet':
return <FootIcon width={30} />;
case 'fingers':
return <FingersIcon width={20} />;
}
}
return <FullResetIcon width={20} />;
};

View File

@@ -28,8 +28,8 @@ export function SkipSetupButton({
<button
type="button"
className={classNames(
'text-background-40 hover:text-background-30',
'stroke-background-40 hover:stroke-background-30',
'text-background-10 hover:text-background-20',
'stroke-background-10 hover:stroke-background-20',
'absolute xs:-top-10 xs:right-4 mobile:top-0 mobile:right-0'
)}
onClick={onClick}

View File

@@ -132,9 +132,7 @@ export function CalibrationTutorialPage() {
id="onboarding-calibration_tutorial-description-v1"
elems={{ b: <b></b> }}
>
<Typography color="secondary">
Description on calibration of IMU
</Typography>
<Typography>Description on calibration of IMU</Typography>
</Localized>
<div>
<div className="xs:hidden flex flex-row justify-center">

View File

@@ -221,10 +221,10 @@ export function ConnectTrackersPage() {
<Typography variant="main-title">
{l10n.getString('onboarding-connect_tracker-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-connect_tracker-description-p0-v1')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-connect_tracker-description-p1-v1')}
</Typography>
<div className="flex flex-col gap-2 py-5">
@@ -281,7 +281,7 @@ export function ConnectTrackersPage() {
{l10n.getString('onboarding-connect_tracker-usb')}
</Typography>
<div className="flex fill-background-10 gap-1">
<Typography color="secondary">
<Typography>
{l10n.getString(statusLabelMap[provisioningStatus])}
</Typography>
</div>
@@ -319,7 +319,7 @@ export function ConnectTrackersPage() {
</div>
</div>
<div style={{ gridArea: 't' }} className="flex items-center px-5">
<Typography color="secondary" bold>
<Typography bold>
{l10n.getString('onboarding-connect_tracker-connected_trackers', {
amount: connectedIMUTrackers.length,
})}

View File

@@ -20,7 +20,7 @@ export function DonePage() {
{l10n.getString('onboarding-done-title')}
</Typography>
<div className="flex flex-col items-center">
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-done-description')}
</Typography>
</div>

View File

@@ -22,7 +22,7 @@ export function EnterVRPage() {
<Typography variant="main-title">
{l10n.getString('onboarding-enter_vr-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-enter_vr-description')}
</Typography>
</div>

View File

@@ -125,7 +125,7 @@ export function ResetTutorialPage() {
<Typography variant="main-title">
{l10n.getString('onboarding-reset_tutorial')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-reset_tutorial-explanation')}
</Typography>
<div className="flex">
@@ -165,7 +165,7 @@ export function ResetTutorialPage() {
curIndex >= order.length && 'hidden'
)}
>
<Typography whitespace="whitespace-pre-line" color="secondary">
<Typography whitespace="whitespace-pre-line">
{l10n.getString(`onboarding-reset_tutorial-${curIndex}`, {
taps: tapSettings[curIndex],
})}
@@ -184,7 +184,7 @@ export function ResetTutorialPage() {
curIndex >= order.length && 'hidden'
)}
>
<Typography whitespace="whitespace-pre-line" color="secondary">
<Typography whitespace="whitespace-pre-line">
{l10n.getString(`onboarding-reset_tutorial-${curIndex}`, {
taps: tapSettings[curIndex],
})}

View File

@@ -35,9 +35,7 @@ export function WifiCredsPage() {
.getString('onboarding-wifi_creds-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
{!state.alonePage && (

View File

@@ -32,7 +32,7 @@ export function AutomaticProportionsPage() {
{l10n.getString('onboarding-automatic_proportions-title')}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-description'
)}

View File

@@ -52,7 +52,7 @@ export function ScaledProportionsPage() {
{l10n.getString('onboarding-scaled_proportions-title')}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-scaled_proportions-description')}
</Typography>
</div>

View File

@@ -72,7 +72,7 @@ export function CheckFloorHeightStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-check_floor_height-description'
)}
@@ -81,7 +81,7 @@ export function CheckFloorHeightStep({
id="onboarding-automatic_proportions-check_floor_height-calculation_warning-v2"
elems={{ u: <span className="underline"></span> }}
>
<Typography color="secondary" bold>
<Typography bold>
Press the button to get your height!
</Typography>
</Localized>

View File

@@ -60,7 +60,7 @@ export function CheckHeightStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-check_height-description-v2'
)}
@@ -69,7 +69,7 @@ export function CheckHeightStep({
id="onboarding-automatic_proportions-check_height-calculation_warning-v3"
elems={{ u: <span className="underline"></span> }}
>
<Typography color="secondary" bold>
<Typography bold>
Press the button to get your height!
</Typography>
</Localized>

View File

@@ -12,7 +12,7 @@ export function DoneStep({ variant }: { variant: 'onboarding' | 'alone' }) {
<Typography variant="section-title">
{l10n.getString('onboarding-automatic_proportions-done-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-automatic_proportions-done-description')}
</Typography>
</div>

View File

@@ -26,13 +26,13 @@ export function PreparationStep({
</Typography>
<div>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-0">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-1">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-2">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
</div>

View File

@@ -28,7 +28,7 @@ export function PutTrackersOnStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-put_trackers_on-description'
)}

View File

@@ -97,7 +97,7 @@ export function Recording({
'onboarding-automatic_proportions-recording-description-p0'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-recording-description-p1'
)}
@@ -110,7 +110,7 @@ export function Recording({
.split('\n')
.map((line, i) => (
<li key={i}>
<Typography color="secondary">{line}</Typography>
<Typography>{line}</Typography>
</li>
))}
</>
@@ -137,7 +137,7 @@ export function Recording({
)
.otherwise(() => undefined)}
></ProgressBar>
<Typography color="secondary">
<Typography>
{match([hasCalibration, hasRecording])
.returnType<ReactNode>()
.with([ProcessStatus.PENDING, ProcessStatus.FULFILLED], () =>

View File

@@ -31,7 +31,7 @@ export function RequirementsStep({
.split('\n')
.map((line, i) => (
<li key={i}>
<Typography color="secondary">{line}</Typography>
<Typography>{line}</Typography>
</li>
))}
</>

View File

@@ -63,7 +63,7 @@ export function StartRecording({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-start_recording-description'
)}
@@ -76,7 +76,7 @@ export function StartRecording({
.split('\n')
.map((line, i) => (
<li key={i}>
<Typography color="secondary">{line}</Typography>
<Typography>{line}</Typography>
</li>
))}
</>

View File

@@ -42,7 +42,7 @@ export function VerifyResultsStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_proportions-verify_results-description'
)}
@@ -65,7 +65,7 @@ export function VerifyResultsStep({
>
{bodyParts?.map(({ bone, label, value }) => (
<div className="flex justify-between" key={bone}>
<Typography color="secondary">{label}</Typography>
<Typography>{label}</Typography>
<Typography bold sentryMask>
{(value * 100).toFixed(2)} CM
</Typography>

View File

@@ -12,7 +12,7 @@ export function DoneStep({ variant }: { variant: 'onboarding' | 'alone' }) {
<Typography variant="section-title">
{l10n.getString('onboarding-scaled_proportions-done-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-scaled_proportions-done-description')}
</Typography>
</div>

View File

@@ -90,7 +90,7 @@ export function ManualHeightStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-scaled_proportions-manual_height-description-v2'
)}

View File

@@ -1,8 +1,8 @@
import { RpcMessage, SkeletonResetAllRequestT } from 'solarxr-protocol';
import { Button } from '@/components/commons/Button';
import { Typography } from '@/components/commons/Typography';
import { useLocalization } from '@fluent/react';
import { useWebsocketAPI } from '@/hooks/websocket-api';
import { useLocalization } from '@fluent/react';
import { RpcMessage, SkeletonResetAllRequestT } from 'solarxr-protocol';
export function ResetProportionsStep({
nextStep,
@@ -26,7 +26,7 @@ export function ResetProportionsStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-scaled_proportions-reset_proportion-description'
)}
@@ -43,7 +43,7 @@ export function ResetProportionsStep({
{l10n.getString('onboarding-automatic_proportions-prev_step')}
</Button>
<Button
variant="secondary"
variant="primary"
onClick={() => {
sendRPCPacket(
RpcMessage.SkeletonResetAllRequest,

View File

@@ -33,7 +33,7 @@ export function AutomaticMountingPage() {
<Typography variant="main-title">
{l10n.getString('onboarding-automatic_mounting-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-automatic_mounting-description')}
</Typography>
</div>

View File

@@ -99,7 +99,7 @@ export function ManualMountingPage() {
<Typography variant="main-title">
{l10n.getString('onboarding-manual_mounting')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-manual_mounting-description')}
</Typography>
<TipBox>{l10n.getString('tips-find_tracker')}</TipBox>

View File

@@ -17,16 +17,12 @@ export function MountingChoose() {
return (
<>
<div className="flex flex-col gap-5 h-full items-center w-full xs:justify-center relative overflow-y-auto px-4 pb-4">
<div className="flex flex-col gap-4 justify-center">
<div className="flex flex-col gap-8 justify-center">
<div className="xs:w-10/12 xs:max-w-[666px]">
<Typography variant="main-title">
{l10n.getString('onboarding-choose_mounting')}
</Typography>
<Typography
variant="standard"
color="secondary"
whitespace="whitespace-pre-line"
>
<Typography variant="standard" whitespace="whitespace-pre-line">
{l10n.getString('onboarding-choose_mounting-description')}
</Typography>
</div>
@@ -37,12 +33,19 @@ export function MountingChoose() {
>
<div
className={classNames(
'rounded-lg p-4 flex',
'rounded-lg p-4 flex relative',
!state.alonePage && 'bg-background-70',
state.alonePage && 'bg-background-60'
)}
>
<div className="flex flex-col gap-4">
<div className="bg-accent-background-30 absolute -left-4 -top-5 p-1.5 rounded-lg">
<Typography variant="vr-accessible" italic>
{l10n.getString(
'onboarding-choose_mounting-auto_mounting-label-v2'
)}
</Typography>
</div>
<div className="flex flex-col gap-4 ">
<div className="flex flex-grow flex-col gap-4 max-w-sm">
<div>
<Typography variant="main-title" bold>
@@ -50,14 +53,9 @@ export function MountingChoose() {
'onboarding-choose_mounting-auto_mounting'
)}
</Typography>
<Typography variant="vr-accessible" italic>
{l10n.getString(
'onboarding-choose_mounting-auto_mounting-label-v2'
)}
</Typography>
</div>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-choose_mounting-auto_mounting-description'
)}
@@ -98,14 +96,9 @@ export function MountingChoose() {
'onboarding-choose_mounting-manual_mounting'
)}
</Typography>
<Typography variant="vr-accessible" italic>
{l10n.getString(
'onboarding-choose_mounting-manual_mounting-label-v2'
)}
</Typography>
</div>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-choose_mounting-manual_mounting-description'
)}

View File

@@ -20,7 +20,7 @@ export function DoneStep({
<Typography variant="section-title">
{l10n.getString('onboarding-automatic_mounting-done-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-automatic_mounting-done-description')}
</Typography>
</div>
@@ -38,6 +38,11 @@ export function DoneStep({
{l10n.getString('onboarding-automatic_mounting-next')}
</Button>
)}
{variant === 'alone' && (
<Button className="flex gap-3" variant="primary" to="/">
{l10n.getString('onboarding-automatic_mounting-return-home')}
</Button>
)}
</div>
<SkeletonVisualizerWidget />

View File

@@ -27,12 +27,12 @@ export function MountingResetStep({
)}
</Typography>
<div className="flex flex-col gap-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_mounting-mounting_reset-step-0'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_mounting-mounting_reset-step-1'
)}

View File

@@ -26,13 +26,13 @@ export function PreparationStep({
</Typography>
<div>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-0">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-1">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-2">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
</div>

View File

@@ -28,7 +28,7 @@ export function PutTrackersOnStep({
)}
</Typography>
<div>
<Typography color="secondary">
<Typography>
{l10n.getString(
'onboarding-automatic_mounting-put_trackers_on-description'
)}

View File

@@ -136,7 +136,7 @@ export function StayAlignedSetup() {
<Typography variant="main-title">
{l10n.getString('onboarding-stay_aligned-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-stay_aligned-description')}
</Typography>
</div>

View File

@@ -11,7 +11,7 @@ export function DoneStep({ goTo }: VerticalStepComponentProps) {
<Typography variant="main-title"></Typography>
</Localized>
<Localized id="onboarding-stay_aligned-done-description-2">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
<div className="flex gap-3 justify-between">

View File

@@ -16,13 +16,13 @@ export function PreparationStep({
<div className="flex flex-col flex-grow justify-between py-2 gap-2">
<div className="flex flex-col gap-1">
<Localized id="onboarding-automatic_mounting-preparation-v2-step-0">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-1">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
<Localized id="onboarding-automatic_mounting-preparation-v2-step-2">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
<Localized id="onboarding-stay_aligned-preparation-tip">

View File

@@ -19,7 +19,7 @@ export function PutTrackersOnStep({ nextStep }: VerticalStepComponentProps) {
<div className="flex flex-grow flex-col gap-4">
<div>
<Localized id="onboarding-stay_aligned-put_trackers_on-description">
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
<div className="flex">

View File

@@ -30,9 +30,7 @@ function PosePage({
<div className="flex flex-col py-2">
<div className="flex flex-col gap-2">
{descriptionKeys.map((descriptionKey) => (
<Typography color="secondary">
{l10n.getString(descriptionKey)}
</Typography>
<Typography>{l10n.getString(descriptionKey)}</Typography>
))}
</div>
<div className="flex pt-1 items-center fill-background-50 justify-center px-12">

View File

@@ -11,16 +11,16 @@ export function VerifyMountingStep({
<div className="flex flex-grow flex-col gap-4 py-2">
<div className="flex flex-col gap-2">
<Localized id="onboarding-stay_aligned-verify_mounting-step-0">
<Typography color="secondary" />
<Typography />
</Localized>
<Localized id="onboarding-stay_aligned-verify_mounting-step-1">
<Typography color="secondary" />
<Typography />
</Localized>
<Localized id="onboarding-stay_aligned-verify_mounting-step-2">
<Typography color="secondary" />
<Typography />
</Localized>
<Localized id="onboarding-stay_aligned-verify_mounting-step-3">
<Typography color="secondary" />
<Typography />
</Localized>
</div>
<div className="flex gap-3 justify-between">

View File

@@ -43,7 +43,7 @@ const ItemContent = ({
mode,
})}
</Typography>
<Typography variant="standard" color="secondary">
<Typography variant="standard">
{l10n.getString('onboarding-assign_trackers-option-description', {
mode,
})}

View File

@@ -284,11 +284,11 @@ export function TrackersAssignPage() {
<Typography variant="main-title">
{l10n.getString('onboarding-assign_trackers-title')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-assign_trackers-description')}
</Typography>
<div className="flex gap-1">
<Typography color="secondary">
<Typography>
{l10n.getString('onboarding-assign_trackers-assigned', {
assigned: assignedTrackers.length,
trackers: trackers.length,

View File

@@ -63,11 +63,11 @@ export function AdvancedSettings() {
<div className="grid gap-4">
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-utils-advanced-reset-gui')}
</Typography>
<div className="flex flex-col">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-utils-advanced-reset-gui-description'
)}
@@ -95,11 +95,11 @@ export function AdvancedSettings() {
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-utils-advanced-reset-server')}
</Typography>
<div className="flex flex-col">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-utils-advanced-reset-server-description'
)}
@@ -132,11 +132,11 @@ export function AdvancedSettings() {
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-utils-advanced-reset-all')}
</Typography>
<div className="flex flex-col">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-utils-advanced-reset-all-description'
)}
@@ -168,11 +168,11 @@ export function AdvancedSettings() {
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-utils-advanced-open_data-v1')}
</Typography>
<div className="flex flex-col">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-utils-advanced-open_data-description-v1'
)}
@@ -188,11 +188,11 @@ export function AdvancedSettings() {
<div className="sm:grid sm:grid-cols-[1.75fr,_1fr] items-center">
<div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-utils-advanced-open_logs')}
</Typography>
<div className="flex flex-col">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-utils-advanced-open_logs-description'
)}

View File

@@ -459,7 +459,7 @@ export function GeneralSettings() {
<Typography variant="main-title">
{l10n.getString('settings-general-steamvr')}
</Typography>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-steamvr-subtitle')}
</Typography>
<div className="flex flex-col py-2">
@@ -467,13 +467,11 @@ export function GeneralSettings() {
.getString('settings-general-steamvr-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</div>
<div className="flex flex-col pt-4"></div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-steamvr-trackers-tracker_toggling'
)}
@@ -485,9 +483,7 @@ export function GeneralSettings() {
)
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</div>
<CheckBox
@@ -608,7 +604,7 @@ export function GeneralSettings() {
<Typography variant="main-title">
{l10n.getString('settings-general-tracker_mechanics')}
</Typography>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-tracker_mechanics-filtering')}
</Typography>
<div className="flex flex-col pt-2 pb-4">
@@ -618,9 +614,7 @@ export function GeneralSettings() {
)
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</div>
<Typography>
@@ -690,7 +684,7 @@ export function GeneralSettings() {
/>
</div>
<div className="flex flex-col pt-5 pb-3">
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-tracker_mechanics-save_mounting_reset'
)}
@@ -699,7 +693,7 @@ export function GeneralSettings() {
id="settings-general-tracker_mechanics-save_mounting_reset-description"
elems={{ b: <b></b> }}
>
<Typography color="secondary"></Typography>
<Typography></Typography>
</Localized>
</div>
<CheckBox
@@ -725,19 +719,19 @@ export function GeneralSettings() {
<Typography variant="main-title">
{l10n.getString('settings-general-fk_settings')}
</Typography>
<div className="flex flex-col pt-2 pb-4">
<Typography bold>
<div className="flex flex-col pt-2 pb-4 gap-2">
<Typography variant="section-title">
{l10n.getString(
'settings-general-fk_settings-leg_tweak-skating_correction'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-leg_tweak-skating_correction-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-4">
<div className="grid sm:grid-cols-1 gap-2 pb-4">
<CheckBox
variant="toggle"
outlined
@@ -761,18 +755,18 @@ export function GeneralSettings() {
</div>
<div className="flex flex-col pt-2 pb-2">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-fk_settings-leg_fk')}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-leg_tweak-floor_clip-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<div className="grid sm:grid-cols-1 gap-2 pb-3">
<CheckBox
variant="toggle"
outlined
@@ -784,7 +778,7 @@ export function GeneralSettings() {
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-leg_tweak-foot_plant-description'
)}
@@ -802,7 +796,7 @@ export function GeneralSettings() {
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-leg_tweak-toe_snap-description'
)}
@@ -821,10 +815,10 @@ export function GeneralSettings() {
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-fk_settings-arm_fk')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-arm_fk-description'
)}
@@ -843,110 +837,114 @@ export function GeneralSettings() {
</div>
<div className="flex flex-col pt-2">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-fk_settings-reset_settings')}
</Typography>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-reset_settings-reset_hmd_pitch-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetHmdPitch"
label={l10n.getString(
'settings-general-fk_settings-reset_settings-reset_hmd_pitch'
)}
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetMountingFeet"
label={l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet'
)}
/>
<div className="grid grid-cols-2 gap-2">
<div className="flex flex-col gap-2">
<Typography>
{l10n.getString(
'settings-general-fk_settings-reset_settings-reset_hmd_pitch-description'
)}
</Typography>
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetHmdPitch"
label={l10n.getString(
'settings-general-fk_settings-reset_settings-reset_hmd_pitch'
)}
/>
</div>
<div className="flex flex-col gap-2 justify-end">
<Typography>
{l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet-description-v1'
)}
</Typography>
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetMountingFeet"
label={l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet-v1'
)}
/>
</div>
</div>
</div>
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-arm_fk-reset_mode-description'
)}
</Typography>
<div className="grid md:grid-cols-2 flex-col gap-3 pt-2 pb-3">
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-back'
<div>
<Typography>
{l10n.getString(
'settings-general-fk_settings-arm_fk-reset_mode-description'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-back-description'
)}
value={'0'}
></Radio>
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-forward'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-forward-description'
)}
value={'1'}
></Radio>
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_up'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_up-description'
)}
value={'2'}
></Radio>
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_down'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_down-description'
)}
value={'3'}
></Radio>
</Typography>
<div className="grid md:grid-cols-2 flex-col gap-3 pt-2 pb-3">
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-back'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-back-description'
)}
value={'0'}
></Radio>
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-forward'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-forward-description'
)}
value={'1'}
></Radio>
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_up'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_up-description'
)}
value={'2'}
></Radio>
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
label={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_down'
)}
description={l10n.getString(
'settings-general-fk_settings-arm_fk-tpose_down-description'
)}
value={'3'}
></Radio>
</div>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography bold>
<div className="flex flex-col pt-2 pb-1">
<Typography variant="section-title">
{l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints'
)}
</Typography>
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description'
)}
</Typography>
<div className="pt-2">
<Typography>
{l10n.getString(
'settings-general-fk_settings-enforce_joint_constraints-enforce_constraints-description'
)}
</Typography>
</div>
</div>
<div className="grid sm:grid-cols-1 pb-3">
<CheckBox
@@ -963,12 +961,12 @@ export function GeneralSettings() {
{config?.debug && (
<>
<div className="flex flex-col pt-2 pb-3">
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-fk_settings-skeleton_settings-toggles'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-skeleton_settings-description'
)}
@@ -1003,14 +1001,14 @@ export function GeneralSettings() {
)}
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<div className="flex flex-col pt-2 pb-3">
<Typography bold>
<div className="flex flex-col">
<div className="flex flex-col pt-2 pb-3 gap-2">
<Typography variant="section-title">
{l10n.getString(
'settings-general-fk_settings-skeleton_settings-ratios'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-skeleton_settings-ratios-description'
)}
@@ -1112,12 +1110,12 @@ export function GeneralSettings() {
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-fk_settings-self_localization-title'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-fk_settings-self_localization-description'
)}
@@ -1147,11 +1145,12 @@ export function GeneralSettings() {
<Typography variant="main-title">
{l10n.getString('settings-general-gesture_control')}
</Typography>
<Typography bold>
{l10n.getString('settings-general-gesture_control-subtitle')}
</Typography>
<div className="flex flex-col pt-2 pb-4">
<Typography color="secondary">
<div className="flex flex-col pt-2 pb-4 gap-2">
<Typography variant="section-title">
{l10n.getString('settings-general-gesture_control-subtitle')}
</Typography>
<Typography>
{l10n.getString('settings-general-gesture_control-description')}
</Typography>
</div>
@@ -1267,12 +1266,12 @@ export function GeneralSettings() {
/>
</div>
<div className="grid sm:grid-cols-1 gap-2 pt-2">
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-gesture_control-numberTrackersOverThreshold'
)}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-gesture_control-numberTrackersOverThreshold-description'
)}

View File

@@ -130,11 +130,14 @@ export function InterfaceSettings() {
{l10n.getString('settings-interface-notifications')}
</Typography>
<Typography bold>
{l10n.getString('settings-general-interface-serial_detection')}
</Typography>
<div className="pt-2">
<Typography variant="section-title">
{l10n.getString('settings-general-interface-serial_detection')}
</Typography>
</div>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-interface-serial_detection-description'
)}
@@ -152,11 +155,11 @@ export function InterfaceSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-interface-feedback_sound')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-interface-feedback_sound-description'
)}
@@ -187,13 +190,13 @@ export function InterfaceSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-interface-connected_trackers_warning'
)}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-interface-connected_trackers_warning-description'
)}
@@ -221,130 +224,134 @@ export function InterfaceSettings() {
<Typography variant="main-title">
{l10n.getString('settings-interface-behavior')}
</Typography>
<div className="pt-2">
{isTrayAvailable && (
<>
<Typography variant="section-title">
{l10n.getString('settings-general-interface-use_tray')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography>
{l10n.getString(
'settings-general-interface-use_tray-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.useTray"
label={l10n.getString(
'settings-general-interface-use_tray-label'
)}
/>
</div>
</>
)}
{isTrayAvailable && (
<>
<Typography bold>
{l10n.getString('settings-general-interface-use_tray')}
<Typography variant="section-title">
{l10n.getString('settings-general-interface-discord_presence')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography>
{l10n.getString(
'settings-general-interface-discord_presence-description'
)}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.discordPresence"
label={l10n.getString(
'settings-general-interface-discord_presence-label'
)}
/>
</div>
<Typography variant="section-title">
{l10n.getString('settings-general-interface-dev_mode')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography>
{l10n.getString(
'settings-general-interface-dev_mode-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.devmode"
label={l10n.getString(
'settings-general-interface-dev_mode-label'
)}
/>
</div>
<Typography variant="section-title">
{l10n.getString('settings-interface-behavior-error_tracking')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Localized
id={
'settings-interface-behavior-error_tracking-description_v2'
}
elems={{
b: <b></b>,
}}
>
<Typography whitespace="whitespace-pre-line"></Typography>
</Localized>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.errorTracking"
label={l10n.getString(
'settings-interface-behavior-error_tracking-label'
)}
/>
</div>
{isTauri() && (
<>
<Typography variant="section-title">
{l10n.getString(
'settings-general-interface-use_tray-description'
'settings-interface-behavior-bvh_directory'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.useTray"
label={l10n.getString(
'settings-general-interface-use_tray-label'
)}
/>
</div>
</>
)}
<Typography bold>
{l10n.getString('settings-general-interface-discord_presence')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
{l10n.getString(
'settings-general-interface-discord_presence-description'
)}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Localized
id={
'settings-interface-behavior-bvh_directory-description'
}
>
<Typography></Typography>
</Localized>
</div>
<div className="grid gap-3 pb-5">
<TauriFileInput
name="behavior.bvhDirectory"
rules={{
required: false,
}}
control={control}
label="settings-interface-behavior-bvh_directory-label"
directory
/>
</div>
</>
)}
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.discordPresence"
label={l10n.getString(
'settings-general-interface-discord_presence-label'
)}
/>
</div>
<Typography bold>
{l10n.getString('settings-general-interface-dev_mode')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
{l10n.getString(
'settings-general-interface-dev_mode-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.devmode"
label={l10n.getString(
'settings-general-interface-dev_mode-label'
)}
/>
</div>
<Typography bold>
{l10n.getString('settings-interface-behavior-error_tracking')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Localized
id={'settings-interface-behavior-error_tracking-description_v2'}
elems={{
b: <b></b>,
}}
>
<Typography
color="secondary"
whitespace="whitespace-pre-line"
></Typography>
</Localized>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="behavior.errorTracking"
label={l10n.getString(
'settings-interface-behavior-error_tracking-label'
)}
/>
</div>
{isTauri() && (
<>
<Typography bold>
{l10n.getString('settings-interface-behavior-bvh_directory')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Localized
id={'settings-interface-behavior-bvh_directory-description'}
>
<Typography color="secondary"></Typography>
</Localized>
</div>
<div className="grid gap-3 pb-5">
<TauriFileInput
name="behavior.bvhDirectory"
rules={{
required: false,
}}
control={control}
label="settings-interface-behavior-bvh_directory-label"
directory
/>
</div>
</>
)}
</>
</SettingsPagePaneLayout>
@@ -356,11 +363,13 @@ export function InterfaceSettings() {
<Typography variant="main-title">
{l10n.getString('settings-interface-appearance')}
</Typography>
<Typography bold>
{l10n.getString('settings-interface-appearance-decorations')}
</Typography>
<div className="pt-2">
<Typography variant="section-title">
{l10n.getString('settings-interface-appearance-decorations')}
</Typography>
</div>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-interface-appearance-decorations-description'
)}
@@ -379,7 +388,7 @@ export function InterfaceSettings() {
</div>
<div className="pb-4">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-interface-theme')}
</Typography>
<div className="flex flex-wrap gap-3 pt-2">
@@ -440,13 +449,13 @@ export function InterfaceSettings() {
</div>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-interface-show-navbar-onboarding'
)}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-general-interface-show-navbar-onboarding-description'
)}
@@ -464,11 +473,11 @@ export function InterfaceSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-interface-appearance-font')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-interface-appearance-font-description'
)}
@@ -513,11 +522,11 @@ export function InterfaceSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-interface-appearance-font_size')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-interface-appearance-font_size-description'
)}
@@ -541,11 +550,11 @@ export function InterfaceSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-general-interface-lang')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-general-interface-lang-description')}
</Typography>
</div>

View File

@@ -95,7 +95,7 @@ export function MagnetometerToggleSetting({
return settingType === 'general' ? (
<>
<div className="flex flex-col pt-5 pb-3" id={id}>
<Typography bold>
<Typography variant="section-title">
{l10n.getString(
'settings-general-tracker_mechanics-use_mag_on_all_trackers'
)}
@@ -104,10 +104,7 @@ export function MagnetometerToggleSetting({
id="settings-general-tracker_mechanics-use_mag_on_all_trackers-description"
elems={{ b: <b></b> }}
>
<Typography
color="secondary"
whitespace="whitespace-pre-line"
></Typography>
<Typography whitespace="whitespace-pre-line"></Typography>
</Localized>
</div>
<CheckBox
@@ -139,10 +136,7 @@ export function MagnetometerToggleSetting({
),
}}
>
<Typography
color="secondary"
whitespace="whitespace-pre-line"
></Typography>
<Typography whitespace="whitespace-pre-line"></Typography>
</Localized>
<div className="flex">
<CheckBox

View File

@@ -110,17 +110,15 @@ export function OSCRouterSettings() {
.getString('settings-osc-router-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-router-enable')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-router-enable-description')}
</Typography>
</div>
@@ -133,7 +131,7 @@ export function OSCRouterSettings() {
label={l10n.getString('settings-osc-router-enable-label')}
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-router-network')}
</Typography>
<div className="flex flex-col pb-2">
@@ -142,9 +140,7 @@ export function OSCRouterSettings() {
.getString('settings-osc-router-network-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>
@@ -176,11 +172,11 @@ export function OSCRouterSettings() {
></Input>
</Localized>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-router-network-address')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-osc-router-network-address-description'
)}

View File

@@ -240,9 +240,7 @@ export function Serial() {
.getString('settings-serial-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>

View File

@@ -137,17 +137,15 @@ export function VMCSettings() {
.getString('settings-osc-vmc-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vmc-enable')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vmc-enable-description')}
</Typography>
</div>
@@ -160,7 +158,7 @@ export function VMCSettings() {
label={l10n.getString('settings-osc-vmc-enable-label')}
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vmc-network')}
</Typography>
<div className="flex flex-col pb-2">
@@ -169,9 +167,7 @@ export function VMCSettings() {
.getString('settings-osc-vmc-network-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>
@@ -203,11 +199,11 @@ export function VMCSettings() {
></Input>
</Localized>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vmc-network-address')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vmc-network-address-description')}
</Typography>
</div>
@@ -227,11 +223,11 @@ export function VMCSettings() {
label=""
></Input>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vmc-vrm')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vmc-vrm-description')}
</Typography>
</div>
@@ -254,11 +250,11 @@ export function VMCSettings() {
></FileInput>
{/* For some reason, linux (GNOME) is detecting the VRM file is a VRML */}
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vmc-anchor_hip')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vmc-anchor_hip-description')}
</Typography>
</div>
@@ -271,11 +267,11 @@ export function VMCSettings() {
label={l10n.getString('settings-osc-vmc-anchor_hip-label')}
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vmc-mirror_tracking')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vmc-mirror_tracking-description')}
</Typography>
</div>

View File

@@ -140,17 +140,15 @@ export function VRCOSCSettings() {
.getString('settings-osc-vrchat-description-v1')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vrchat-enable')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vrchat-enable-description')}
</Typography>
</div>
@@ -164,18 +162,16 @@ export function VRCOSCSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vrchat-oscqueryEnabled')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n
.getString('settings-osc-vrchat-oscqueryEnabled-description')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
{line}
</Typography>
<Typography key={i}>{line}</Typography>
))}
</Typography>
</div>
@@ -191,11 +187,11 @@ export function VRCOSCSettings() {
/>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vrchat-network')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-osc-vrchat-network-description-v1')}
</Typography>
</div>
@@ -227,11 +223,11 @@ export function VRCOSCSettings() {
></Input>
</Localized>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vrchat-network-address')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-osc-vrchat-network-address-description-v1'
)}
@@ -253,11 +249,11 @@ export function VRCOSCSettings() {
label=""
></Input>
</div>
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-osc-vrchat-network-trackers')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-osc-vrchat-network-trackers-description'
)}

View File

@@ -40,9 +40,7 @@ function StaAlignedPoseModal({
</div>
<div className="flex flex-col gap-1">
{descriptionKeys.map((descriptionKey) => (
<Typography color="secondary">
{l10n.getString(descriptionKey)}
</Typography>
<Typography>{l10n.getString(descriptionKey)}</Typography>
))}
</div>
<div className="flex pt-1 items-center fill-background-50 justify-center px-12">

View File

@@ -182,10 +182,10 @@ export function StayAlignedSettings({
{l10n.getString('settings-stay_aligned')}
</Typography>
<div className="mt-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-stay_aligned-description')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('settings-stay_aligned-setup-description')}
</Typography>
<div className="flex mt-2">
@@ -199,7 +199,7 @@ export function StayAlignedSettings({
</div>
</div>
<div className="mt-6">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-stay_aligned-general-label')}
</Typography>
<div className="grid sm:grid-cols-2 gap-3 mt-2">
@@ -224,11 +224,11 @@ export function StayAlignedSettings({
</div>
</div>
<div className="mt-6">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-stay_aligned-relaxed_poses-label')}
</Typography>
<div className="mt-2">
<Typography color="secondary">
<Typography>
{l10n.getString(
'settings-stay_aligned-relaxed_poses-description'
)}
@@ -305,11 +305,11 @@ export function StayAlignedSettings({
</div>
</div>
<div className="mt-6">
<Typography bold>
<Typography variant="section-title">
{l10n.getString('settings-stay_aligned-debug-label')}
</Typography>
<div className="mt-2">
<Typography color="secondary">
<Typography>
{l10n.getString('settings-stay_aligned-debug-description')}
</Typography>
</div>

View File

@@ -49,7 +49,7 @@ export function SingleTrackerBodyAssignmentMenu({
<Typography variant="mobile-title" bold>
{l10n.getString('body_assignment_menu')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('body_assignment_menu-description')}
</Typography>
<div className="flex">

View File

@@ -7,7 +7,7 @@ export function TrackerBattery({
value,
voltage,
disabled,
textColor = 'secondary',
textColor = 'primary',
}: {
/**
* a [0, 1] value range is expected

View File

@@ -99,7 +99,7 @@ export function TrackerPartCard({
<WarningIcon></WarningIcon>
</div>
)}
<Typography color="secondary">
<Typography variant="section-title">
{l10n.getString('body_part-' + BodyPart[role])}
</Typography>
{td?.map(({ tracker }, index) => (
@@ -110,7 +110,7 @@ export function TrackerPartCard({
/>
))}
{!td && (
<Typography>
<Typography color="text-background-30">
{l10n.getString('tracker-part_card-unassigned')}
</Typography>
)}

View File

@@ -211,10 +211,10 @@ export function TrackerSettingsPage() {
</Typography>
</Localized>
<div className="flex gap-2">
<Typography color="secondary">
<Typography>
v{tracker?.device?.hardwareInfo?.firmwareVersion}
</Typography>
<Typography color="secondary">-</Typography>
<Typography>-</Typography>
{updateUnavailable && (
<Localized id="tracker-settings-update-unavailable">
<Typography>Cannot be updated (DIY)</Typography>
@@ -272,7 +272,7 @@ export function TrackerSettingsPage() {
<div className="flex flex-col bg-background-70 p-3 rounded-lg gap-2 overflow-x-auto">
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-manufacturer')}
</Typography>
<Typography>
@@ -280,13 +280,13 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-display_name')}
</Typography>
<Typography>{tracker?.tracker.info?.displayName}</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-custom_name')}
</Typography>
<Typography sentry-mask>
@@ -294,9 +294,7 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
{l10n.getString('tracker-infos-url')}
</Typography>
<Typography>{l10n.getString('tracker-infos-url')}</Typography>
<Typography>
udp://
{IPv4.fromNumber(
@@ -305,7 +303,7 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-hardware_identifier')}
</Typography>
<Typography>
@@ -313,7 +311,7 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-data_support')}
</Typography>
<Typography>
@@ -323,9 +321,7 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
{l10n.getString('tracker-infos-imu')}
</Typography>
<Typography>{l10n.getString('tracker-infos-imu')}</Typography>
<Typography>
{tracker?.tracker.info?.imuType
? ImuType[tracker?.tracker.info?.imuType]
@@ -333,13 +329,13 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-board_type')}
</Typography>
<Typography>{boardType}</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-magnetometer')}
</Typography>
<Typography>
@@ -352,7 +348,7 @@ export function TrackerSettingsPage() {
</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-network_version')}
</Typography>
<Typography>
@@ -377,7 +373,7 @@ export function TrackerSettingsPage() {
<Typography variant="section-title">
{l10n.getString('tracker-settings-assignment_section')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'tracker-settings-assignment_section-description'
)}
@@ -419,7 +415,7 @@ export function TrackerSettingsPage() {
<Typography variant="section-title">
{l10n.getString('tracker-settings-mounting_section')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString(
'tracker-settings-mounting_section-description'
)}
@@ -468,7 +464,7 @@ export function TrackerSettingsPage() {
<Typography variant="section-title">
{l10n.getString('tracker-settings-name_section')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-settings-name_section-description')}
</Typography>
<Input
@@ -488,7 +484,7 @@ export function TrackerSettingsPage() {
<Typography variant="section-title">
{l10n.getString('tracker-settings-forget')}
</Typography>
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-settings-forget-description')}
</Typography>
<Button

View File

@@ -35,7 +35,7 @@ export function TrackerStatus({ status }: { status: number }) {
<div className="flex flex-col justify-center">
<div className={classNames('w-2 h-2 rounded-full', statusClass)}></div>
</div>
<Typography color="secondary" whitespace="whitespace-nowrap">
<Typography whitespace="whitespace-nowrap">
{l10n.getString(statusLabel)}
</Typography>
</div>

View File

@@ -130,7 +130,7 @@ export function VRCWarningsPage() {
<Typography variant="main-title" />
</Localized>
<Localized id={'vrc_config-page-desc'}>
<Typography variant="standard" color="secondary" />
<Typography variant="standard" />
</Localized>
</div>
<div className="w-full mt-4 gap-2 flex flex-col">
@@ -142,7 +142,7 @@ export function VRCWarningsPage() {
<Typography variant="section-title" />
</Localized>
<Localized id="vrc_config-page-big_menu-desc">
<Typography color="secondary" />
<Typography />
</Localized>
<Table>
<SettingRow
@@ -248,7 +248,7 @@ export function VRCWarningsPage() {
<Typography variant="section-title" />
</Localized>
<Localized id="vrc_config-page-wrist_menu-desc">
<Typography color="secondary" />
<Typography />
</Localized>
<Table>
<SettingRow
@@ -304,7 +304,7 @@ export function VRCWarningsPage() {
a: <A href="https://docs.slimevr.dev/tools/vrchat-config.html"></A>,
}}
>
<Typography color="secondary" />
<Typography />
</Localized>
</div>
</div>

View File

@@ -75,9 +75,7 @@ export function DeveloperModeWidget() {
return (
<form className="bg-background-60 flex flex-col w-full rounded-md px-2">
<div className="mt-2 px-1">
<Typography color="secondary">
{l10n.getString('widget-developer_mode')}
</Typography>
<Typography>{l10n.getString('widget-developer_mode')}</Typography>
</div>
{Object.entries(toggles).map(makeToggle)}
</form>

View File

@@ -128,7 +128,7 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) {
{tracker.position && (
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('widget-imu_visualizer-position')}
</Typography>
<Typography>{formatVector3(tracker.position, 2)}</Typography>
@@ -136,14 +136,14 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) {
)}
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('widget-imu_visualizer-rotation_raw')}
</Typography>
<Typography>{formatVector3(rotationRaw, 2)}</Typography>
</div>
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('widget-imu_visualizer-rotation_preview')}
</Typography>
<Typography>{formatVector3(rotationIdent, 2)}</Typography>
@@ -151,7 +151,7 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) {
{tracker.linearAcceleration && (
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('widget-imu_visualizer-acceleration')}
</Typography>
<Typography>
@@ -162,7 +162,7 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) {
{tracker.rawMagneticVector && (
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('tracker-infos-magnetometer')}
</Typography>
<Typography>{formatVector3(tracker.rawMagneticVector, 1)}</Typography>
@@ -171,7 +171,7 @@ export function IMUVisualizerWidget({ tracker }: { tracker: TrackerDataT }) {
{!!tracker.stayAligned && (
<div className="flex justify-between">
<Typography color="secondary">
<Typography>
{l10n.getString('widget-imu_visualizer-stay_aligned')}
</Typography>
<StayAlignedInfo color="primary" tracker={tracker} />

View File

@@ -68,9 +68,7 @@ export function OverlayWidget() {
return !loading ? (
<form className="bg-background-60 flex flex-col w-full rounded-md px-2">
<div className="mt-2 px-1">
<Typography color="secondary">
{l10n.getString('widget-overlay')}
</Typography>
<Typography>{l10n.getString('widget-overlay')}</Typography>
</div>
<CheckBox
control={control}

View File

@@ -27,6 +27,14 @@ const hash = (str: string) => {
const firstAsset = (assets: any[], name: string) =>
assets.find((asset: any) => asset.name === name && asset.browser_download_url);
const todaysRange = (deployData: [number, Date][]): number => {
let maxRange = 0;
for (const [range, date] of deployData) {
if (Date.now() >= date.getTime()) maxRange = range;
}
return maxRange;
};
const checkUserCanUpdate = async (url: string, fwVersion: string) => {
if (!url) return true;
const deployDataJson = JSON.parse(
@@ -57,11 +65,7 @@ const checkUserCanUpdate = async (url: string, fwVersion: string) => {
)
return false; // Dates in the wrong order / cancel
const todayUpdateRange = deployData.find(([, date], index) => {
if (index === 0 && Date.now() < date.getTime()) return true;
return Date.now() >= date.getTime();
})?.[0];
const todayUpdateRange = todaysRange(deployData);
if (!todayUpdateRange) return false;
const uniqueUserKey = `${await hostname()}-${await locale()}-${platform()}-${version()}`;
@@ -101,7 +105,7 @@ export async function fetchCurrentFirmwareRelease(): Promise<FirmwareRelease | n
name: release.name,
version,
changelog: release.body,
firmwareFile: fwAsset,
firmwareFile: fwAsset.browser_download_url,
userCanUpdate,
});

10
gui/src/vite-env.d.ts vendored
View File

@@ -4,14 +4,14 @@
declare const __COMMIT_HASH__: string;
declare const __VERSION_TAG__: string;
declare const __GIT_CLEAN__: boolean;
declare const __ANDROID__:
| {
isThere: () => boolean;
}
| undefined;
interface Window {
readonly isTauri: boolean;
readonly __ANDROID__:
| {
isThere: () => boolean;
}
| undefined;
}
declare module 'tailwind-gradient-mask-image';

12
pnpm-lock.yaml generated
View File

@@ -60,8 +60,8 @@ importers:
specifier: ^2.0.0
version: 2.0.0
'@tauri-apps/plugin-fs':
specifier: ^2.0.0
version: 2.0.0
specifier: 2.4.1
version: 2.4.1
'@tauri-apps/plugin-http':
specifier: ^2.5.0
version: 2.5.0
@@ -1254,8 +1254,8 @@ packages:
'@tauri-apps/plugin-dialog@2.0.0':
resolution: {integrity: sha512-ApNkejXP2jpPBSifznPPcHTXxu9/YaRW+eJ+8+nYwqp0lLUtebFHG4QhxitM43wwReHE81WAV1DQ/b+2VBftOA==}
'@tauri-apps/plugin-fs@2.0.0':
resolution: {integrity: sha512-BNEeQQ5aH8J5SwYuWgRszVyItsmquRuzK2QRkVj8Z0sCsLnSvJFYI3JHRzzr3ltZGq1nMPtblrlZzuKqVzRawA==}
'@tauri-apps/plugin-fs@2.4.1':
resolution: {integrity: sha512-vJlKZVGF3UAFGoIEVT6Oq5L4HGDCD78WmA4uhzitToqYiBKWAvZR61M6zAyQzHqLs0ADemkE4RSy/5sCmZm6ZQ==}
'@tauri-apps/plugin-http@2.5.0':
resolution: {integrity: sha512-l4M2DUIsOBIMrbj4dJZwrB4mJiB7OA/2Tj3gEbX2fjq5MOpETklJPKfDvzUTDwuq4lIKCKKykz8E8tpOgvi0EQ==}
@@ -5464,9 +5464,9 @@ snapshots:
dependencies:
'@tauri-apps/api': 2.0.2
'@tauri-apps/plugin-fs@2.0.0':
'@tauri-apps/plugin-fs@2.4.1':
dependencies:
'@tauri-apps/api': 2.0.2
'@tauri-apps/api': 2.6.0
'@tauri-apps/plugin-http@2.5.0':
dependencies:

View File

@@ -2,6 +2,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE" />
@@ -26,7 +28,11 @@
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/device_filter" />
</activity>
<service

View File

@@ -8,6 +8,8 @@ import androidx.appcompat.app.AppCompatActivity
import dev.slimevr.Keybinding
import dev.slimevr.VRServer
import dev.slimevr.android.serial.AndroidSerialHandler
import dev.slimevr.android.tracking.trackers.hid.AndroidHIDManager
import dev.slimevr.tracking.trackers.Tracker
import io.eiren.util.logging.LogManager
import io.ktor.http.CacheControl
import io.ktor.http.CacheControl.Visibility
@@ -60,6 +62,15 @@ fun main(activity: AppCompatActivity) {
},
)
vrServer.start()
// Start service for USB HID trackers
val androidHidManager = AndroidHIDManager(
"Sensors HID service",
{ tracker: Tracker -> vrServer.registerTracker(tracker) },
activity,
)
androidHidManager.start()
Keybinding(vrServer)
vrServer.join()
LogManager.closeLogger()

View File

@@ -1,10 +1,13 @@
package dev.slimevr.android.serial
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import com.hoho.android.usbserial.driver.UsbSerialDriver
import com.hoho.android.usbserial.driver.UsbSerialPort
import com.hoho.android.usbserial.driver.UsbSerialProber
@@ -15,10 +18,8 @@ import io.eiren.util.logging.LogManager
import java.io.IOException
import java.nio.ByteBuffer
import java.nio.charset.StandardCharsets
import java.util.*
import java.util.concurrent.CopyOnWriteArrayList
import java.util.stream.Stream
import kotlin.concurrent.timerTask
import kotlin.streams.asSequence
import kotlin.streams.asStream
import dev.slimevr.serial.SerialPort as SlimeSerialPort
@@ -43,12 +44,11 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
private var usbIoManager: SerialInputOutputManager? = null
private val listeners: MutableList<SerialListener> = CopyOnWriteArrayList()
private val getDevicesTimer = Timer("GetDevicesTimer")
private var watchingNewDevices = false
private var lastKnownPorts = setOf<SerialPortWrapper>()
private val manager = activity.getSystemService(Context.USB_SERVICE) as UsbManager
private var currentPort: SerialPortWrapper? = null
private var requestingPermission: String = ""
private var readBuffer: StringBuilder = StringBuilder(1024)
override val isConnected: Boolean
get() = currentPort?.port?.isOpen ?: false
@@ -60,37 +60,70 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
.filter { isKnownBoard(it) }
.asStream()
val usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
UsbManager.ACTION_USB_DEVICE_ATTACHED, UsbManager.ACTION_USB_DEVICE_DETACHED -> {
// Use device from `UsbManager.EXTRA_DEVICE` if this is a problem
detectNewPorts()
}
ACTION_USB_PERMISSION -> {
// TODO: We can probably receive this event in the server to avoid
// polling, but for now we can just ignore it. (Note: This event is
// not currently registered, so it will never fire.)
}
}
}
}
init {
startWatchingNewDevices()
val intentFilter = IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED)
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
// Listen for USB device attach/detach
ContextCompat.registerReceiver(
activity,
usbReceiver,
intentFilter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
// Detect initial serial ports
detectNewPorts()
}
private fun getPorts(): List<UsbSerialDriver> = UsbSerialProber.getDefaultProber().findAllDrivers(manager)
private fun startWatchingNewDevices() {
if (watchingNewDevices) return
watchingNewDevices = true
getDevicesTimer.scheduleAtFixedRate(
timerTask {
try {
detectNewPorts()
} catch (t: Throwable) {
LogManager.severe(
"[SerialHandler] Error while watching for new devices, cancelling the \"getDevicesTimer\".",
t,
)
getDevicesTimer.cancel()
}
},
0,
3000,
)
}
private fun onNewDevice(port: SerialPortWrapper) {
// If we missed clearing this on disconnect/close, clear it on discovery
if (requestingPermission == port.portLocation) {
requestingPermission = ""
}
LogManager.info("[SerialHandler] Device added: ${port.descriptivePortName}")
listeners.forEach { it.onNewSerialDevice(port) }
}
private fun onDeviceDel(port: SerialPortWrapper) {
// Remove permission request on disconnect so reconnecting re-requests
if (requestingPermission == port.portLocation) {
requestingPermission = ""
}
// If we're currently using this port, close it
currentPort?.portLocation.let { currentPortLocation ->
if (currentPortLocation == port.portLocation) {
closeSerial()
}
}
// If this port is still open for whatever reason, close it
if (port.port.isOpen) {
port.port.close()
}
LogManager.info("[SerialHandler] Device removed: ${port.descriptivePortName}")
listeners.forEach { it.onSerialDeviceDeleted(port) }
}
@@ -154,9 +187,11 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
flags,
)
if (requestingPermission != newPort.portLocation) {
println("Requesting permission for ${newPort.portLocation}")
LogManager.info("[SerialHandler] Requesting permission for ${newPort.portLocation}")
manager.requestPermission(newPort.port.device, usbPermissionIntent)
requestingPermission = newPort.portLocation
} else {
LogManager.info("[SerialHandler] Already requested permission for ${newPort.portLocation}, skipping")
}
LogManager.warning(
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, invalid permissions",
@@ -164,11 +199,13 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
return false
}
// If we have permission, we aren't requesting anymore
requestingPermission = ""
val connection = manager.openDevice(newPort.port.device)
if (connection == null) {
LogManager.warning(
"[SerialHandler] Can't open serial port ${newPort.descriptivePortName}, connection failed",
)
return false
}
@@ -186,7 +223,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
@Synchronized
private fun writeSerial(serialText: String, print: Boolean = false) {
try {
usbIoManager?.writeAsync("${serialText}\n".toByteArray())
currentPort?.port?.write("${serialText}\n".toByteArray(), 0)
if (print) {
addLog("-> $serialText\n")
}
@@ -224,6 +261,8 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
usbIoManager?.stop()
usbIoManager = null
currentPort = null
requestingPermission = ""
readBuffer.clear()
} catch (e: Exception) {
LogManager.warning(
"[SerialHandler] Error closing port ${currentPort?.descriptivePortName}",
@@ -233,7 +272,7 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
}
override fun write(buff: ByteArray) {
usbIoManager?.writeAsync(buff)
currentPort?.port?.write(buff, 0)
}
@Synchronized
@@ -251,14 +290,21 @@ class AndroidSerialHandler(val activity: AppCompatActivity) :
override fun onNewData(data: ByteArray?) {
if (data != null) {
val s = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(data)).toString()
addLog(s, false)
// Collect serial in a buffer until newline (or character limit)
// This is somewhat of a workaround for Android serial buffer being smaller
// than on desktop, so we don't read full lines and it causes parsing issues
readBuffer.append(StandardCharsets.UTF_8.decode(ByteBuffer.wrap(data)))
if (readBuffer.contains('\n') || readBuffer.length >= 1024) {
addLog(readBuffer.toString(), false)
readBuffer.clear()
}
}
}
override fun onRunError(e: java.lang.Exception?) {}
companion object {
private val ACTION_USB_PERMISSION = "dev.slimevr.USB_PERMISSION"
private const val ACTION_USB_PERMISSION = "dev.slimevr.USB_PERMISSION"
}
}

View File

@@ -0,0 +1,93 @@
package dev.slimevr.android.tracking.trackers.hid
import android.hardware.usb.UsbConstants
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbDeviceConnection
import android.hardware.usb.UsbEndpoint
import android.hardware.usb.UsbInterface
import android.hardware.usb.UsbManager
import java.io.Closeable
/**
* A wrapper over Android's [UsbDevice] for HID devices.
*/
class AndroidHIDDevice(hidDevice: UsbDevice, usbManager: UsbManager) : Closeable {
val deviceName = hidDevice.deviceName
val serialNumber = hidDevice.serialNumber
val manufacturerName = hidDevice.manufacturerName
val productName = hidDevice.productName
val hidInterface: UsbInterface
val endpointIn: UsbEndpoint
val endpointOut: UsbEndpoint?
val deviceConnection: UsbDeviceConnection
init {
hidInterface = findHidInterface(hidDevice)!!
val (endpointIn, endpointOut) = findHidIO(hidInterface)
this.endpointIn = endpointIn!!
this.endpointOut = endpointOut
deviceConnection = usbManager.openDevice(hidDevice)!!
deviceConnection.claimInterface(hidInterface, true)
}
override fun close() {
deviceConnection.releaseInterface(hidInterface)
deviceConnection.close()
}
companion object {
/**
* Find the HID interface.
*
* @return
* Return the HID interface if found, otherwise null.
*/
private fun findHidInterface(usbDevice: UsbDevice): UsbInterface? {
val interfaceCount: Int = usbDevice.interfaceCount
for (interfaceIndex in 0 until interfaceCount) {
val usbInterface = usbDevice.getInterface(interfaceIndex)
if (usbInterface.interfaceClass == UsbConstants.USB_CLASS_HID) {
return usbInterface
}
}
return null
}
/**
* Find the HID endpoints.
*
* @return
* Return the HID endpoints if found, otherwise null.
*/
private fun findHidIO(usbInterface: UsbInterface): Pair<UsbEndpoint?, UsbEndpoint?> {
val endpointCount: Int = usbInterface.endpointCount
var usbEndpointIn: UsbEndpoint? = null
var usbEndpointOut: UsbEndpoint? = null
for (endpointIndex in 0 until endpointCount) {
val usbEndpoint = usbInterface.getEndpoint(endpointIndex)
if (usbEndpoint.type == UsbConstants.USB_ENDPOINT_XFER_INT) {
if (usbEndpoint.direction == UsbConstants.USB_DIR_OUT) {
usbEndpointOut = usbEndpoint
} else {
usbEndpointIn = usbEndpoint
}
}
}
return Pair(usbEndpointIn, usbEndpointOut)
}
}
}

View File

@@ -0,0 +1,254 @@
package dev.slimevr.android.tracking.trackers.hid
import android.app.PendingIntent
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.hardware.usb.UsbDevice
import android.hardware.usb.UsbManager
import androidx.core.content.ContextCompat
import dev.slimevr.tracking.trackers.Device
import dev.slimevr.tracking.trackers.Tracker
import dev.slimevr.tracking.trackers.TrackerStatus
import dev.slimevr.tracking.trackers.hid.HIDCommon
import dev.slimevr.tracking.trackers.hid.HIDCommon.Companion.HID_TRACKER_RECEIVER_PID
import dev.slimevr.tracking.trackers.hid.HIDCommon.Companion.HID_TRACKER_RECEIVER_VID
import dev.slimevr.tracking.trackers.hid.HIDCommon.Companion.PACKET_SIZE
import dev.slimevr.tracking.trackers.hid.HIDDevice
import io.eiren.util.logging.LogManager
import java.nio.ByteBuffer
import java.util.function.Consumer
const val ACTION_USB_PERMISSION = "dev.slimevr.USB_PERMISSION"
/**
* Handles Android USB Host HID dongles and receives tracker data from them.
*/
class AndroidHIDManager(
name: String,
private val trackersConsumer: Consumer<Tracker>,
private val context: Context,
) : Thread(name) {
private val devices: MutableList<HIDDevice> = mutableListOf()
private val devicesBySerial: MutableMap<String, MutableList<Int>> = HashMap()
private val devicesByHID: MutableMap<UsbDevice, MutableList<Int>> = HashMap()
private val connByHID: MutableMap<UsbDevice, AndroidHIDDevice> = HashMap()
private val lastDataByHID: MutableMap<UsbDevice, Int> = HashMap()
private val usbManager: UsbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager
val usbReceiver: BroadcastReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
when (intent.action) {
UsbManager.ACTION_USB_DEVICE_ATTACHED -> {
(intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) as UsbDevice?)?.let {
checkConfigureDevice(it, requestPermission = true)
}
}
UsbManager.ACTION_USB_DEVICE_DETACHED -> {
(intent.getParcelableExtra(UsbManager.EXTRA_DEVICE) as UsbDevice?)?.let {
removeDevice(it)
}
}
ACTION_USB_PERMISSION -> {
deviceEnumerate(false)
}
}
}
}
private fun proceedWithDeviceConfiguration(hidDevice: UsbDevice) {
// This is the original logic from checkConfigureDevice after permission is confirmed
LogManager.info("[TrackerServer] USB Permission granted for ${hidDevice.deviceName}. Proceeding with configuration.")
// Close any existing connection (do we still have one?)
this.connByHID[hidDevice]?.close()
// Open new HID connection with USB device
this.connByHID[hidDevice] = AndroidHIDDevice(hidDevice, usbManager)
val serial = hidDevice.serialNumber ?: "Unknown USB Device ${hidDevice.deviceId}"
this.devicesBySerial[serial]?.let {
this.devicesByHID[hidDevice] = it
synchronized(this.devices) {
for (id in it) {
val device = this.devices[id]
for (value in device.trackers.values) {
if (value.status == TrackerStatus.DISCONNECTED) value.status = TrackerStatus.OK
}
}
}
LogManager.info("[TrackerServer] Linked HID device reattached: $serial")
return
}
val list: MutableList<Int> = mutableListOf()
this.devicesBySerial[serial] = list
this.devicesByHID[hidDevice] = list
this.lastDataByHID[hidDevice] = 0 // initialize last data received
LogManager.info("[TrackerServer] (Probably) Compatible HID device detected: $serial")
}
fun checkConfigureDevice(usbDevice: UsbDevice, requestPermission: Boolean = false) {
if (usbDevice.vendorId == HID_TRACKER_RECEIVER_VID && usbDevice.productId == HID_TRACKER_RECEIVER_PID) {
if (usbManager.hasPermission(usbDevice)) {
LogManager.info("[TrackerServer] Already have permission for ${usbDevice.deviceName}")
proceedWithDeviceConfiguration(usbDevice)
} else if (requestPermission) {
LogManager.info("[TrackerServer] Requesting permission for ${usbDevice.deviceName}")
val permissionIntent = PendingIntent.getBroadcast(
context,
0,
Intent(ACTION_USB_PERMISSION).apply { setPackage(context.packageName) }, // Explicitly set package
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT,
)
usbManager.requestPermission(usbDevice, permissionIntent)
}
}
}
private fun removeDevice(hidDevice: UsbDevice) {
this.devicesByHID[hidDevice]?.let {
synchronized(this.devices) {
for (id in it) {
val device = this.devices[id]
for (value in device.trackers.values) {
if (value.status == TrackerStatus.OK) {
value.status =
TrackerStatus.DISCONNECTED
}
}
}
}
this.devicesByHID.remove(hidDevice)
val oldConn = this.connByHID.remove(hidDevice)
val serial = oldConn?.serialNumber ?: "Unknown"
oldConn?.close()
LogManager.info("[TrackerServer] Linked HID device removed: $serial")
}
}
private fun dataRead() {
synchronized(devicesByHID) {
var devicesPresent = false
var devicesDataReceived = false
val q = intArrayOf(0, 0, 0, 0)
val a = intArrayOf(0, 0, 0)
val m = intArrayOf(0, 0, 0)
for ((hidDevice, deviceList) in devicesByHID) {
val dataReceived = ByteArray(64)
val conn = connByHID[hidDevice]!!
val dataRead = conn.deviceConnection.bulkTransfer(conn.endpointIn, dataReceived, dataReceived.size, 0)
// LogManager.info("[TrackerServer] HID data read ($dataRead bytes): ${dataReceived.contentToString()}")
devicesPresent = true // Even if the device has no data
if (dataRead > 0) {
// Process data
// The data is always received as 64 bytes, this check no longer works
if (dataRead % PACKET_SIZE != 0) {
LogManager.info("[TrackerServer] Malformed HID packet, ignoring")
continue // Don't continue with this data
}
devicesDataReceived = true // Data is received and is valid (not malformed)
lastDataByHID[hidDevice] = 0 // reset last data received
val packetCount = dataRead / PACKET_SIZE
var i = 0
while (i < packetCount * PACKET_SIZE) {
// Common packet data
val packetType = dataReceived[i].toUByte().toInt()
val id = dataReceived[i + 1].toUByte().toInt()
val deviceId = id
// Register device
if (packetType == 255) { // device register packet from receiver
val buffer = ByteBuffer.wrap(dataReceived, i + 2, 8)
buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN)
val addr = buffer.getLong() and 0xFFFFFFFFFFFF
val deviceName = String.format("%012X", addr)
HIDCommon.deviceIdLookup(devices, hidDevice.serialNumber, deviceId, deviceName, deviceList) // register device
// server wants tracker to be unique, so use combination of hid serial and full id
i += PACKET_SIZE
continue
}
val device: HIDDevice? = HIDCommon.deviceIdLookup(devices, hidDevice.serialNumber, deviceId, null, deviceList)
if (device == null) { // not registered yet
i += PACKET_SIZE
continue
}
HIDCommon.processPacket(dataReceived, i, packetType, device, q, a, m, trackersConsumer)
i += PACKET_SIZE
}
// LogManager.info("[TrackerServer] HID received $packetCount tracker packets")
} else {
lastDataByHID[hidDevice] = lastDataByHID[hidDevice]!! + 1 // increment last data received
}
}
if (!devicesPresent) {
sleep(10) // No hid device, "empty loop" so sleep to save the poor cpu
} else if (!devicesDataReceived) {
sleep(1) // read has no timeout, no data also causes an "empty loop"
}
}
}
private fun deviceEnumerate(requestPermission: Boolean = false) {
val hidDeviceList: MutableList<UsbDevice> = usbManager.deviceList.values.filter {
it.vendorId == HID_TRACKER_RECEIVER_VID && it.productId == HID_TRACKER_RECEIVER_PID
}.toMutableList()
synchronized(devicesByHID) {
// Work on devicesByHid and add/remove as necessary
val removeList: MutableList<UsbDevice> = devicesByHID.keys.toMutableList()
removeList.removeAll(hidDeviceList)
for (device in removeList) {
removeDevice(device)
}
hidDeviceList.removeAll(devicesByHID.keys) // addList
for (device in hidDeviceList) {
// This will handle permission check/request
checkConfigureDevice(device, requestPermission)
}
}
}
override fun run() {
val intentFilter = IntentFilter(UsbManager.ACTION_USB_DEVICE_ATTACHED)
intentFilter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED)
intentFilter.addAction(ACTION_USB_PERMISSION)
// Listen for USB device attach/detach
ContextCompat.registerReceiver(
context,
usbReceiver,
intentFilter,
ContextCompat.RECEIVER_NOT_EXPORTED,
)
// Enumerate existing devices
deviceEnumerate(true)
// Data read loop
while (true) {
try {
sleep(0) // Possible performance impact
} catch (e: InterruptedException) {
currentThread().interrupt()
break
}
dataRead() // not in try catch?
}
}
fun getDevices(): List<Device> = devices
companion object {
private const val resetSourceName = "TrackerServer"
}
}

Some files were not shown because too many files have changed in this diff Show More