Compare commits

...

599 Commits

Author SHA1 Message Date
Eiren Rain
18aae19573 Bump versison to 0.4.0 2022-11-24 23:28:17 +02:00
lucas lelievre
def3da6580 Fix/Optimize OSC IP address saving (#300) 2022-11-25 00:12:39 +03:00
Butterscotch!
b5f12b46e0 Fix Windows bridge exceptions on other OSes and handle serial exceptions better (#297) 2022-11-25 00:05:19 +03:00
Butterscotch!
5c59c4e385 Linux GUI CI and run GUI CI when workflow file is changed (#294) 2022-11-25 00:00:53 +03:00
Erimel
7fd94c36f5 remove excssive osc logging (#299) 2022-11-25 00:00:42 +03:00
lucas lelievre
bb4861635d Fix/gui reset all (#298) 2022-11-24 23:59:50 +03:00
Erimel
0a2d5674f7 GUI: Fix filtering not being clamped properly (#296) 2022-11-24 23:32:38 +03:00
lucas lelievre
1ac0a380db Feature/gui osc implem (#290) 2022-11-24 22:54:34 +03:00
Erimel
171877ee49 update java 17 download link in run.bat (#292) 2022-11-24 22:02:22 +03:00
Butterscotch!
e45da2b979 appDir() causes GUI config to not be loaded :c (#295) 2022-11-24 22:02:05 +03:00
Eiren Rain
46fedc2d3a Update build-gui.yml 2022-11-23 04:21:02 +03:00
Eiren Rain
6f8037f9f9 Don't crash on unrecognized arguments (#287) 2022-11-23 04:15:09 +03:00
lucas lelievre
9d63191ff3 Fix osc settings (#289) 2022-11-23 04:15:01 +03:00
lucas lelievre
1bcf8467a6 Fix typo (#288) 2022-11-23 04:14:31 +03:00
Eiren Rain
eb55a3e1d4 Fix CI artifact upload (#286) 2022-11-22 23:11:52 +03:00
Eiren Rain
57e220ac34 Merge pull request #285 from SlimeVR/old-gui-cleanup
Old gui cleanup
2022-11-22 19:01:39 +03:00
Eiren Rain
584f3b6afe Fix line endings. Thanks github.dev! 2022-11-22 18:06:07 +03:00
Eiren Rain
b959ac56af Post-merge fixes 2022-11-22 16:01:49 +01:00
Eiren Rain
32a3a010cf Fix keybindings class 2022-11-22 15:50:21 +01:00
Eiren Rain
1624ed3282 Update solarxr-protocol 2022-11-22 15:34:14 +01:00
Eiren Rain
1b27ea6940 Delete old gui, cleanup after new gui merge, bump version to 0.3.1 2022-11-22 17:30:08 +03:00
Eiren Rain
70fb9b4a5a Merge pull request #268 from SlimeVR/merge-gui-and-server
Merge gui and server
2022-11-22 17:20:10 +03:00
Eiren Rain
c0229e107b Merge branch 'main' of https://github.com/SlimeVR/SlimeVR-Server into merge-gui-and-server 2022-11-22 15:09:35 +01:00
Erimel
45d11ba176 bump version to 0.3.,0 (#279) 2022-11-22 16:53:45 +03:00
lucas lelievre
d0b117ab36 Merge branch 'main' of github.com:SlimeVR/SlimeVR-Server into merge-gui-and-server 2022-11-22 10:42:42 +01:00
Erimel
3d3e6faad7 Add config delays for reset/quickreset keybindings (#278) 2022-11-22 05:02:16 +03:00
Butterscotch!
5b44eaddfa Add mounting reset (two-pose reset) (#251) 2022-11-22 04:40:13 +03:00
Erimel
85ea2a0d06 OSC Support (#274) 2022-11-22 04:36:43 +03:00
Collin Kees
ba146e0fb7 Upgrades to legtweaks (#260) 2022-11-22 04:33:04 +03:00
lucas lelievre
6dbe80050f Syncronise with main 2022-11-21 21:36:30 +01:00
lucas lelievre
1dd11ce579 Fix extentions files formatting 2022-11-21 21:32:59 +01:00
williammb
317630628f Remove org/json from jackson (#272) 2022-11-21 23:29:57 +03:00
lucas lelievre
d1f72c9280 Use workspaces modules, update ci, update solarxr 2022-11-19 23:27:04 +01:00
Ryan Butler
e349440ce0 Fixed NPE in tracker ip addr (#269) 2022-11-14 18:02:04 +03:00
lucas lelievre
ae94de39b1 Merge remote-tracking branch 'gui/main' into merge-gui-and-server 2022-11-13 02:27:28 +01:00
lucas lelievre
813c1340a8 Preparing merge with server repo 2022-11-13 02:00:31 +01:00
Erimel
d8a7fa978b Add third party notices with releases (#262) 2022-11-12 18:33:18 +03:00
Uriel
d9988cc658 Refactor code to Java 17 (#244) 2022-11-12 03:14:08 +03:00
lucas lelievre
f38360e4f1 Do not send position or rotation if not available (#265) 2022-11-09 20:18:46 +03:00
lucas lelievre
a6e17c96b8 Hide position if not sent (#33) 2022-11-09 18:10:37 +01:00
lucas lelievre
b149b87fa7 Pub sub implementation (#263) 2022-11-07 23:34:52 +03:00
lucas lelievre
79b1a96e8c add glow effect (#30) 2022-11-07 03:11:32 +01:00
lucas lelievre
cef818b430 Fix min hieight of table row (#29) 2022-11-07 02:57:20 +01:00
lucas lelievre
dd8e9a623f Kepp wifi between pages (#28) 2022-11-07 02:49:47 +01:00
lucas lelievre
fcad1142b0 Tauri update (#27)
* Rust cache

* Update tauri to v1.1.1
2022-11-07 02:25:17 +01:00
lucas lelievre
af629007e1 Rust cache (#26)
* Rust cache

* Add node cache also and update rust-cache version
2022-11-07 02:22:18 +01:00
lucas lelievre
25374a1d6a Implement pubsub protocol + Use it for the overlay 2022-11-07 00:59:08 +01:00
Butterscotch!
2f2f57a46f Add a mounting rotation button to the GUI (#22)
* Add support for mounting reset

* Add reset mounting button

* Don't display negative timer on reset buttons

* Fix reset button timer going negative

* Update package-lock.json
2022-11-03 21:35:25 +01:00
TheDevMinerTV
eed7dd98af docs: add rust to build prereqs (#21) 2022-11-03 21:34:24 +01:00
Butterscotch!
660599b5e1 Replace ip-bigint with ip-num (#23) 2022-11-03 21:33:53 +01:00
Butterscotch!
3d2aa988a0 Better AutoBone body proportion error (#258) 2022-10-27 16:00:04 +03:00
lucas lelievre
f3d32da4cd Bring back device ip (#256) 2022-10-20 18:10:31 +03:00
lucas lelievre
9f9d45c450 Fix lock 2022-10-18 07:11:01 +02:00
lucas lelievre
85671f5497 Add device ip (#18)
* Add device ip

* Use ip address instead of hardware address
2022-10-18 04:42:20 +02:00
Collin Kees
081c2eb191 Add Toggles to settings page (#15)
* add settings for legtweaks

* change settings over flatbuffer

* add toggle control

* bug fix and cleanup

* removed horrific gramatical issues

* made FK settings

* add other toggles

* grammatical corrections

* change text to be in line with style

* Make it work :p

* Remove console log

Co-authored-by: lucas lelievre <loucass003@gmail.com>
2022-10-17 07:47:17 +02:00
Erimel
c3225c10c6 Update for Better Filtering (#17)
* rename filtering stuff

* fix description error

* Make it compile

Co-authored-by: lucas lelievre <loucass003@gmail.com>
2022-10-13 23:49:47 +02:00
Erimel
d5059ed48c Better filtering (#241) 2022-10-13 16:17:32 +03:00
unlogisch04
8b1e4cb21a Adding more Serial Commands to the Server (#245) 2022-10-05 19:36:08 +03:00
Erimel
6242afda42 fix crashing when converting zoom (#242) 2022-09-17 00:09:53 +03:00
Erimel
4f44e6c7c7 fix arms from controllers (#240) 2022-09-13 03:14:29 +03:00
Butterscotch!
6fec8c6d07 Autobone cleanup, logging improvements, and restoring functionality (#237) 2022-09-13 03:14:02 +03:00
Erimel
1348f9f5ef fix trackers not loading none/null (#239) 2022-09-13 03:13:45 +03:00
Eiren Rain
1b5a4bf369 Remove Slime Java Commons submodule, (#236) 2022-09-13 03:13:06 +03:00
Collin Kees
426f914f4d Leg tweaks (#223) 2022-08-30 19:50:15 +03:00
Eiren Rain
caa11f9dfc Bump version to v0.2.1 2022-08-24 23:04:09 +02:00
Butterscotch!
d1ed22d3d3 Add a recurring AutoBone recording for user debug info (#235) 2022-08-24 23:54:03 +03:00
Kitlith
67ea5edda6 Add "fast reset" user action to protobuf bridge. (#232) 2022-08-17 18:16:03 +03:00
lucas lelievre
8c6d5e2369 Fix NPE on config converter. (#234) 2022-08-16 22:38:00 +03:00
lucas lelievre
c5e05d2940 Fix Tracker config not being saved properly (#231) 2022-08-11 21:31:58 +03:00
lucas lelievre
8adf3fe591 Implement overlay toggle (#230) 2022-08-09 21:49:07 +03:00
Loler920a
101c403138 Make elbows track from HMD by default (#228) 2022-08-09 21:32:43 +03:00
lucas lelievre
5d1dbb27e1 Config refactor round 2 (#229) 2022-08-09 21:27:28 +03:00
lucas lelievre
0e73480e8a Overlay settings (#13)
* Overlay settings

* remove console log
2022-08-09 06:35:41 -07:00
lucas lelievre
58b0153cdc Reindent + Fix reponsive on the preparation step 2022-08-09 15:33:24 +02:00
Spazzwan
378cc12401 Autobone edits (#12)
* Update Recording.tsx

* Update Preparation.tsx

* Update Preparation.tsx

* Update Recording.tsx

* Update Recording.tsx

* Update Recording.tsx

* Update StartRecording.tsx

* Update Done.tsx

* Update Done.tsx

* Update Recording.tsx

* Update Preparation.tsx

* Update StartRecording.tsx

* Update StartRecording.tsx

* Update Preparation.tsx

* Update StartRecording.tsx

* Update Preparation.tsx

* Update Recording.tsx

* Update StartRecording.tsx
2022-08-09 06:30:55 -07:00
lucas lelievre
0146c5825c Reindent + Fix reponsive on the preparation step 2022-08-09 15:29:22 +02:00
Spazzwan
5cc2b391f8 Merge branch 'SlimeVR:main' into main 2022-08-09 22:13:17 +10:00
Spazzwan
80bced317c Update StartRecording.tsx 2022-08-09 22:09:47 +10:00
Spazzwan
3f51170be7 Update Recording.tsx 2022-08-09 22:09:03 +10:00
Spazzwan
ad7bd26577 Update Preparation.tsx 2022-08-09 22:08:08 +10:00
Spazzwan
820b8b21ec Update StartRecording.tsx 2022-08-09 21:33:07 +10:00
Spazzwan
12fc9f0377 Update Preparation.tsx 2022-08-09 21:31:58 +10:00
lucas lelievre
b475099b58 fix window not showing up" 2022-08-09 13:18:37 +02:00
Spazzwan
3ea3fbcd99 Update StartRecording.tsx 2022-08-09 20:23:50 +10:00
Spazzwan
28fae6f8db Update StartRecording.tsx 2022-08-09 19:40:55 +10:00
Spazzwan
d466871762 Update Preparation.tsx 2022-08-09 19:39:08 +10:00
Spazzwan
87850ee485 Update Recording.tsx 2022-08-09 19:29:51 +10:00
Spazzwan
86cfa7ce4d Update Done.tsx 2022-08-09 19:18:16 +10:00
Spazzwan
0315e523b5 Update Done.tsx 2022-08-09 19:17:59 +10:00
Spazzwan
ad99dfb439 Update StartRecording.tsx 2022-08-09 19:12:54 +10:00
Spazzwan
c7bf9a6d24 Update Recording.tsx 2022-08-09 19:09:31 +10:00
Spazzwan
38ffa9bb6d Update Recording.tsx 2022-08-09 19:07:27 +10:00
Spazzwan
1ac0191964 Update Recording.tsx 2022-08-09 19:06:39 +10:00
Spazzwan
75fab32a32 Update Preparation.tsx 2022-08-09 19:03:25 +10:00
Spazzwan
cf3eccde64 Update Preparation.tsx 2022-08-09 19:00:28 +10:00
Spazzwan
5a0240a01a Update Recording.tsx 2022-08-09 18:56:15 +10:00
Ryan Butler
390d6f3b51 Model settings (#226) 2022-08-04 20:34:33 +03:00
Erimel
29121913fd Add Skeleton settings to config and change some FK averaging logic. (#215) 2022-08-04 20:02:58 +03:00
lucas lelievre
7489d6ed34 Autobone tracker highlight 2022-08-04 16:14:48 +02:00
lucas lelievre
5d288063ad Fix Typos, window position, tracker list and missign links 2022-08-03 13:12:56 +02:00
lucas lelievre
efce9d3748 Window position save + Window controls button hover effect 2022-08-03 11:34:37 +02:00
lucas lelievre
e9c0b79b73 Better big buttons 2022-08-03 02:13:16 +02:00
lucas lelievre
29268da5c0 First round of fixes 2022-08-03 01:46:41 +02:00
lucas lelievre
41a87b1c9b update to new protocol 2022-07-30 09:08:36 +02:00
lucas lelievre
612d99ae70 Update solarxr dep 2022-07-30 08:56:00 +02:00
lucas lelievre
d878789fcf Fix build 2022-07-30 08:51:18 +02:00
lucas lelievre
2674da1185 New look (#10)
* WIP

* Current progress for erimel

* basic components + Typography

* Current progress  + formating

* Settings ok

* Small Tracker cards + progress on onboarding

* git attributes

* Fix lf

* change some settings naming stuff (#8)

* change some settings naming stuff

* rename legs label to feet

* Body proportions begin

* Serial console + Tracker settings

* interactions on cards

* Body proportions adjust

* Standalone body proportions + some responsive changes

* Dev mode + uniform ui

* Serial layout fix

* Remove old code / cleaning

* make dev table interactable

* Autobone

Co-authored-by: Erimel <marioluigivideo@gmail.com>
2022-07-30 08:46:27 +02:00
lucas lelievre
8d90663799 Add set tracker name in the rpc (#222) 2022-07-30 00:38:15 +03:00
lucas lelievre
bc3cc4ce14 Send manufacturer through the protocol (#221) 2022-07-30 00:37:42 +03:00
lucas lelievre
b5159c9776 Catch flatbuffers errors (#218) 2022-07-30 00:37:11 +03:00
Erimel
9ee09319d7 Skeleton arms rework and cleaning up (#214) 2022-07-15 02:24:21 +03:00
lucas lelievre
7818582f3f Implement Tracker names (#210) 2022-07-15 02:06:22 +03:00
lucas lelievre
2ed0726b76 New readme (#2)
* New readme

* Update README.md

Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>

* Update README.md

Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>

* Update README.md

Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>

* Addressing TheButlah's Feedbacks

* Update README.md

Co-authored-by: Ryan Butler <thebutlah@gmail.com>

* Update README.md

Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>
Co-authored-by: Ryan Butler <thebutlah@gmail.com>
2022-07-05 21:03:34 +02:00
Erimel
0b7f79340b Set disconnected TrackerStatus (#211) 2022-07-04 16:35:08 +03:00
lucas lelievre
c22b5ce421 Implement devices in the protocol (#205) 2022-07-04 00:57:21 +03:00
Erimel
078b140966 Rename hmd bodypart to head (#209) 2022-07-04 00:54:29 +03:00
Erimel
c3e4e86c4e Fixing skeleton stuff (#206) 2022-07-04 00:53:29 +03:00
Erimel
d0b1a9c822 remove waist_tracker, only use hip_tracker (#208) 2022-07-04 00:50:05 +03:00
lucas lelievre
531503f789 Merge pull request #7 from SlimeVR/fix-build
Fix build
2022-07-03 11:26:56 +02:00
lucas lelievre
3abf984d19 Fix build 2022-07-03 10:51:53 +02:00
Erimel
e875cbbcbc Place tracker at origin when disabled (#207) 2022-07-01 02:14:17 +03:00
lucas lelievre
e0dff69d7c Merge pull request #4 from Louka3000/foot_shift
rename foot_offset to foot_shift
2022-06-29 05:55:23 +02:00
Louka
23141305c1 update packages 2022-06-28 16:09:08 -04:00
Louka
04b5bfac9d owo 2022-06-28 16:08:41 -04:00
Eiren Rain
663170681a Bump version to 0.2.0 2022-06-28 21:09:27 +02:00
Butterscotch!
b1318567e3 AutoBone: Adjust bone offsets for directly and implement new contribution based error calculation (#204) 2022-06-28 22:00:57 +03:00
Eiren Rain
d1a02c52a9 Monor changes, added comments 2022-06-28 20:36:04 +02:00
lucas lelievre
b3efcd19db Remove realTracker checks for cleaner code (#203) 2022-06-28 21:33:43 +03:00
Erimel
66e4e4e0a0 Basic shoulder tracking support (#200) 2022-06-28 21:32:11 +03:00
Erimel
7c37fdb24e Use split offsets and rename foot_offset to foot_shift (#199) 2022-06-28 21:20:31 +03:00
Eiren Rain
ceb1cc77d8 Minor cleanup and comments from last PRs 2022-06-28 20:11:08 +02:00
Ryan Butler
8df4726d22 [Feature] Add support for bones in DataFeedUpdate (#196) 2022-06-28 20:57:09 +03:00
Ryan Butler
408df5273d Fix NPE in Websocket logging (#202) 2022-06-28 20:21:38 +03:00
Ryan Butler
7a4d087be2 Prevent logs in gitignore (#201) 2022-06-28 20:21:01 +03:00
Louka
f7249a883f rename foot_offset to foot_shift 2022-06-23 20:49:17 -04:00
lucas lelievre
b1ef647819 Merge pull request #3 from ButterscotchV/github-actions
Add GitHub Actions workflow and update npm packages
2022-06-21 22:44:02 +02:00
Erimel
11a15ab5b1 Cleaning up the skeleton a bit (#197) 2022-06-21 17:22:53 +03:00
Eiren Rain
f6ffd63b05 Fix left arm tracker not resetting (#198) 2022-06-21 01:13:09 +03:00
Butterscotch!
879065f420 Use npm ci instead of install 2022-06-20 16:30:05 -04:00
Butterscotch!
1169f68eb2 Add CI workflow and update npm packages
Create build-gui.yml

Update build-gui.yml

Force install in GitHub Actions

Update SolarXR-Protocol

Update packages to not need to force

Fix CI env declaration
2022-06-20 16:11:07 -04:00
lucas lelievre
0afe9d2ef8 Fix optional in the feeder and bring back none option in the gui (#194) 2022-06-11 20:15:27 +03:00
lucas lelievre
738bf20dc6 Merge pull request #1 from ButterscotchV/autobone-gui
Add basic AutoBone interface
2022-06-11 18:46:07 +02:00
Erimel
c02b95346f Extended knee model + temporary fix for null/optional (#193) 2022-06-09 13:21:40 +03:00
Erimel
db33c561ab fix minor typo in firewall.bat (#192) 2022-06-06 21:08:58 +03:00
Eiren Rain
df2cfa1e57 Skeleton data (#189) 2022-06-05 01:04:07 +03:00
Ryan Butler
d40e2c2ce2 Refactored TrackerPosition (#181) 2022-06-01 17:08:56 +03:00
Butterscotch!
215f3b9f44 Implement AutoBone into the protocol (#187)
Implement event-based AutoBoneHandler & more
2022-06-01 16:59:17 +03:00
Ryan Butler
766cf9ae72 Update instructions for spotless on IntelliJ (#183) 2022-05-31 13:42:57 +03:00
Kamilake
26d808deb7 Handling exception thrown when closing WiFiWindow (#185) 2022-05-30 17:43:43 +03:00
Butterscotch!
4b887332ef Add basic AutoBone interface & export body part labels 2022-05-30 01:46:04 -04:00
Eiren Rain
f9259c976d Update commons version 2022-05-24 17:17:32 +03:00
Erimel
39c3285a0a Fix getting previous rotations (#180) 2022-05-24 01:09:00 +03:00
Ryan Butler
57f3624ee7 CI & Formatting improvements (#178)
* CI & Formatting improvements

+ Added spotlessCheck to CI
+ Now formatting .yaml files (with spaces)
* Bumped version numbers of actions

* Renamed .yml to .yaml in accordance with yaml.org/faq
2022-05-23 15:54:10 +03:00
Eiren Rain
5a4b656a74 WIP of skeleton data 2022-05-19 19:03:38 +03:00
Eiren Rain
bf7e13d923 Update spotless 2022-05-19 18:08:57 +03:00
Ryan Butler
dedec668e1 Added spotless and CONTRIBUTING.md (#172) 2022-05-19 17:51:46 +03:00
Eiren Rain
1e4013be98 This time it should work 2022-05-16 20:52:28 +03:00
Eiren Rain
76c3210788 Should be the last one for gradle or I give up... 2022-05-16 20:48:42 +03:00
Eiren Rain
4a99eff854 Fix gradle build (hopefully) 2022-05-16 20:46:18 +03:00
Eiren Rain
237dabce17 Update commons with formatted code 2022-05-16 20:41:42 +03:00
Eiren Rain
6f36f7624a Update commons 2022-05-16 20:36:26 +03:00
Eiren Rain
1dea626422 Eclipse formatting (#176)
* Make eclipse formatter better follow our conventions and format all of it
* Don't join wrapped lines to allow for hand-formatting
* Fix formatting of switch statements and add breaks in enum declarations
* Use new formatter by @thebutlah, adjust formatter more
2022-05-16 20:05:46 +03:00
Eiren Rain
c74cc539c9 Clarify README regarding licencing 2022-05-08 17:56:53 +03:00
Eiren Rain
910e32bb3e Merge pull request #166 from Futurabeast/clean-get-tracker-by-id
Change getTrackerById
2022-05-03 15:33:18 +03:00
Eiren Rain
6ad3c862ce Merge pull request #171 from TheButlah/fix_concurrent_modification_datafeed
Fix concurrent modification in DataFeedHandler
2022-05-03 15:27:43 +03:00
Eiren Rain
05819baf97 Merge pull request #173 from TheButlah/trackerpos_from_role
Computed trackers use TrackerRole to determine TrackerPosition, if null
2022-05-03 15:25:52 +03:00
Eiren Rain
d84ba2aef5 Merge pull request #174 from TheButlah/fix_more_fbs_bugs
Fix position and rotation getting mixed up in flatbuffer
2022-05-03 15:24:20 +03:00
Ryan Butler
ec9e7d94bc Fix position and rotation getting mixed up in flatbuffer 2022-05-03 03:24:22 -04:00
Ryan Butler
a800749b87 Fix concurrent modification in DataFeedHandler 2022-05-03 00:41:25 -04:00
lucas lelievre
675c69af60 WIP 2022-05-03 06:41:23 +02:00
Ryan Butler
76fe83452e Computed trackers use TrackerRole to determine TrackerPosition, if null 2022-05-02 23:45:57 -04:00
Eiren Rain
6d940503af Merge pull request #169 from TheButlah/gitignore_eclipse
.gitignore eclipse stuff
2022-05-02 23:17:21 +03:00
Ryan Butler
0ea5b58b50 .gitignoring most eclipse stuff 2022-05-02 13:38:50 -04:00
Eiren Rain
94c079815f Merge pull request #168 from TheButlah/fix_computed_tracker_num
Computed trackers should use their tracker id as their num
2022-05-02 13:47:43 +03:00
Eiren Rain
11ab7a6cb6 Merge pull request #167 from TheButlah/fix_invalid_fb_serialization
Fix invalid flatbuffer offsets
2022-05-02 13:47:15 +03:00
Ryan Butler
7f67135e69 Computed trackers should use their tracker id as their num 2022-05-02 02:58:24 -04:00
Ryan Butler
a1717bbf7a Fix invalid flatbuffer offsets 2022-05-02 02:09:33 -04:00
Eiren Rain
c99375364d Merge pull request #165 from deiteris/use-foreach
Refactor for to foreach
2022-05-01 16:02:24 +03:00
Eiren Rain
94460ed7ab Merge pull request #163 from Futurabeast/fix-index-error-datafeed
Fix iteration on the sensors, i used the key of the map instead of the index of the array
2022-05-01 01:07:18 +03:00
lucas lelievre
413332462f more readable version of it 2022-04-30 23:06:14 +02:00
lucas lelievre
18386d57d6 Better tracker id with no possible null pointer exception 2022-04-30 22:50:32 +02:00
lucas lelievre
f72045438e Change getTrackerById 2022-04-30 21:58:26 +02:00
Yury
17f74c693c Refactor for to foreach 2022-04-30 20:34:13 +03:00
lucas lelievre
fb3057b80a I don't know what this does, but I'm gonna merge it anyway
add filtering description
2022-04-30 07:55:51 +02:00
lucas lelievre
4eec83e5f4 Merge pull request #9 from Louka3000/main
Better tracker rotation slider
2022-04-30 07:54:52 +02:00
Louka
f94850c120 better tracker rotation slider 2022-04-30 01:50:39 -04:00
lucas lelievre
3fb87a4688 Fix iteration on the sensors, i used the key of the map instead of the index of the array 2022-04-30 04:03:53 +02:00
Erimel
488c3ec22c add filtering description 2022-04-29 18:48:36 -04:00
lucas lelievre
cccf57d37a new palette 2022-04-29 00:56:01 +02:00
lucas lelievre
8f1be283a4 rename extensions file 2022-04-28 19:24:38 +02:00
lucas lelievre
049465fc41 Add recomended extensions 2022-04-28 19:21:25 +02:00
lucas lelievre
00be864bbf Change event name on front side to match rust changes 2022-04-28 17:13:25 +02:00
lucas lelievre
494d362ec6 Merge pull request #5 from TheButlah/more_err
Added "terminated" and "other" events to "server-status", fixed icon
2022-04-28 17:12:07 +02:00
lucas lelievre
2c3ac89844 new process events + fallback to current folder if no arguments 2022-04-28 17:10:32 +02:00
Eiren Rain
9205f6cab7 Merge pull request #162 from Futurabeast/format-all
Format all files based on .editorconfig
2022-04-28 15:32:48 +03:00
lucas lelievre
d0ee364fb9 Fix conflicts with main 2022-04-28 14:30:40 +02:00
lucas lelievre
3a80ad0632 Change the formating to tabs 2022-04-28 03:44:24 +02:00
lucas lelievre
93c353bbc6 Fix crlf 2022-04-27 23:20:14 +02:00
Eiren Rain
9f883dccec Fix eclipse prefs 2022-04-27 23:42:16 +03:00
lucas lelievre
ad3b697517 New formatting rules 2022-04-27 22:40:03 +02:00
Eiren Rain
5f3097185e Merge pull request #161 from Futurabeast/fix-forward-to-front
Fix Converting FORWARD rotation to FRONT
2022-04-27 23:33:11 +03:00
lucas lelievre
7ac7f7d424 New formatting rules 2022-04-27 22:29:09 +02:00
lucas lelievre
ba58f4df6a Reformat the formatter 2022-04-27 22:25:28 +02:00
lucas lelievre
297bfddf6c Update src/main/java/dev/slimevr/NetworkProtocol.java
Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>
2022-04-27 22:21:09 +02:00
lucas lelievre
e4d0aca744 Update src/main/java/dev/slimevr/bridge/BridgeThread.java
Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>
2022-04-27 22:21:05 +02:00
lucas lelievre
8b5ac226c3 Update src/main/java/dev/slimevr/bridge/BridgeThread.java
Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>
2022-04-27 22:21:00 +02:00
lucas lelievre
cfc264fa33 Update src/main/java/dev/slimevr/bridge/BridgeThread.java
Co-authored-by: TheDevMinerTV <tobigames200@gmail.com>
2022-04-27 22:20:49 +02:00
lucas lelievre
9e12958ca6 reformat all 2022-04-27 21:39:54 +02:00
lucas lelievre
8609fb9e97 Fix Converting FORWARD rotation to FRON 2022-04-27 21:30:54 +02:00
Eiren Rain
9d6dda8b17 Use https for solarxr module 2022-04-27 19:38:36 +03:00
Eiren Rain
92b64f0f12 Merge pull request #159 from Futurabeast/main
Headless Server / SolarXR Protocol implementation
2022-04-27 19:33:59 +03:00
Ryan Butler
ffda9f6b2e Added "terminated" and "other" events to "server-status", fixed icon 2022-04-26 23:51:17 -04:00
lucas lelievre
ae881565e8 Prepare for beta 2022-04-27 02:40:10 +02:00
lucas lelievre
2b46032329 Add icon 2022-04-26 23:50:51 +02:00
lucas lelievre
f4ee1ff73d Remove icon 2022-04-26 23:50:43 +02:00
lucas lelievre
a54e850de8 Merge console stdio with some minor improvements 2022-04-26 23:47:23 +02:00
lucas lelievre
3e554c1b8a new settings 2022-04-26 21:19:28 +02:00
Ryan Butler
a7c442d785 Events now get sent to frontend 2022-04-26 00:19:19 -04:00
lucas lelievre
677fa71ba1 Cancel change to .settings 2022-04-26 02:08:56 +02:00
lucas lelievre
9f3f34ce70 Reformat protocol 2022-04-26 02:07:45 +02:00
lucas lelievre
2d2b6588b3 Sync with main solarxr 2022-04-26 02:04:59 +02:00
lucas lelievre
f6e1cc7747 update default dependency 2022-04-25 20:47:25 +02:00
Ryan Butler
e04357c815 Added clap 2022-04-25 14:31:44 -04:00
lucas lelievre
17d75cfee0 New settings layout + update solarxr 2022-04-25 20:06:25 +02:00
lucas lelievre
44fa266697 remove slimevr_protocol from submodules 2022-04-25 00:39:37 +02:00
lucas lelievre
57f7ea6745 clean useless stuff 2022-04-25 00:38:50 +02:00
lucas lelievre
326c7e969a remove ignored files 2022-04-25 00:37:29 +02:00
lucas lelievre
23f9b3b276 Sync with lastest server 2022-04-25 00:21:32 +02:00
lucas lelievre
1e74deede3 Current progress 2022-04-24 19:53:56 +02:00
lucas lelievre
4906d9551e New icons 2022-04-24 16:41:23 +02:00
lucas lelievre
83b40d3351 Config stuff 2022-04-24 16:28:35 +02:00
lucas lelievre
ce8929af04 rename to solarxr 2022-04-24 16:09:35 +02:00
lucas lelievre
c2a51e4d57 Merge pull request #2 from TheButlah/add_license
Add LICENSE
2022-04-24 14:04:15 +02:00
lucas lelievre
5fae72fb03 Merge branch 'master' into add_license 2022-04-24 14:03:57 +02:00
lucas lelievre
1b6b6e30ad Merge pull request #1 from TheButlah/fix_child_proc
fix: Child process termination, workspaces, gitignore, logger
2022-04-24 14:03:18 +02:00
Ryan Butler
451d687198 Add LICENSE 2022-04-24 01:35:25 -04:00
Ryan Butler
90144f13c8 fix: Child process termination, workspaces, gitignore, logger
* Now using cargo workspaces, means you can `cargo run` from toplevel.
* Command execution now is cwd independent.
+ Added pretty_env_logger which lets us leverage log crate for easy
  logging.
* Windows now uses the win32job crate to ensure that all child processes
  will properly terminate when the parent process does.
+ Added empty rustfmt.toml to ensure everyone uses default rustfmt
  settings.
* Gitignore now ignores more stuff.
2022-04-24 01:18:00 -04:00
lucas lelievre
9fc9b66745 Rust stuff 2022-04-24 03:55:39 +02:00
loucass003
2317ad94f5 Update submodule to solarxr-protocol 2022-04-24 01:20:55 +02:00
Eiren Rain
58d1f2de96 Merge pull request #158 from Louka3000/skeloff-fix
Fix hip when not using legs
2022-04-23 19:03:15 +03:00
Louka
de101b3576 Fix hip when not using legs
disables pelvis averaging if user isn't using knee trackers.
2022-04-20 21:26:36 -04:00
lucas lelievre
9fbfc43655 Clean packages 2022-04-16 16:40:30 +02:00
loucass003
e3e37023e8 More rpc stuff 2022-04-15 01:17:16 +02:00
Eiren Rain
63409b61ea Merge pull request #157 from mgschwan/main
Change variable naming of configPath
2022-04-14 17:15:20 +03:00
Michael Gschwandtner
c827e7725b Revert changed files 2022-04-14 16:10:35 +02:00
Michael Gschwandtner
0bcaed719b Merge branch 'SlimeVR:main' into main 2022-04-14 16:06:17 +02:00
Michael Gschwandtner
c77d73c460 Rename configPath variable 2022-04-14 16:04:37 +02:00
loucass003
9fc5d41e1b protocol rework Sets -> Map 2022-04-14 09:15:01 +02:00
Eiren Rain
ac0cb9e9cb Merge pull request #149 from Louka3000/hand-tracking
Hand tracking support + elbows without controllers
2022-04-12 20:22:32 +03:00
lucas lelievre
f961318035 update submodule 2022-04-12 09:09:29 +02:00
lucas lelievre
52fa670293 Datafeed almost done 2022-04-12 09:07:18 +02:00
Eiren Rain
d0c3e0ae8d Merge pull request #155 from mgschwan/main
Make VRServer config path variable
2022-04-12 01:57:10 +03:00
Louka
0b2491ead5 Properly handle elbows with hand tracking
Instead of moving the controller chains to the slimevr hand, now just make the computed elbows affected by the elbow from the slimevr hand chain.

Also refactored some stuff to replace "upper arm distance" by "elbow offset". Idek if it's useful but it may be so I'm keeping it.
2022-04-11 18:39:30 -04:00
Michael Gschwandtner
1723d19882 Make VRServer config path variable
Add a constructor that accepts a path to the config file
2022-04-12 00:37:46 +02:00
Louka
416f96fe44 Merge branch 'main' into hand-tracking 2022-04-11 17:41:32 -04:00
Eiren Rain
7b700b4a0c Merge pull request #154 from mgschwan/main
Make WebSocketVRBridge compatible with Android
2022-04-11 21:37:50 +03:00
Eiren Rain
bde578fb9d Merge pull request #151 from Louka3000/neck-tracking
Neck tracking support owo
2022-04-11 21:05:37 +03:00
Michael Gschwandtner
c41dc490ed Make WebSocketVRBridge compatible with Android
Change JSONObject.optFloat (does not exist on Android) to optDouble
2022-04-11 16:00:42 +02:00
Eiren Rain
6d9e816d19 Merge pull request #153 from Louka3000/filters-fix
Make filter dependent on tracker tps
2022-04-08 00:59:28 +03:00
Erimel
8f19afee88 Merge branch 'SlimeVR:main' into hand-tracking 2022-04-07 01:18:50 -04:00
Louka
784ec877d8 Make filter dependent on tracker tps
Why was this in the wrong place wth
2022-04-06 20:35:47 -04:00
Eiren Rain
48c509ef54 Merge pull request #152 from mgschwan/main
Add full reset command to WebSocket bridge
2022-04-06 15:43:56 +03:00
Eiren Rain
0a5f06816d Merge pull request #150 from Louka3000/patch-1
Null check on designation I forgor
2022-04-06 15:42:06 +03:00
Louka
ecbeaf10ed Remove unnecessary code
Also makes my code a whole lot clearer damn.
Now I can understand it myself!!! :P
2022-04-05 18:02:30 -04:00
Michael Gschwandtner
c8e4918b4e Merge branch 'SlimeVR:main' into main 2022-04-05 22:17:55 +02:00
Michael Gschwandtner
4ab5609dbd Add full reset command to WebSocket bridge 2022-04-05 22:11:40 +02:00
Louka
cfe8eb62e7 Neck tracking support owo
This is not a joke.
As I suspected, adding a neck tracker does help with reducing sliding. I tested it in VRChat myself.
Think of it like adding a fourth spine tracker.
Anyway, this can be useful to mocap suits and furries, pls merge ty owo.
2022-04-05 00:11:43 -04:00
Erimel
f2ceb84969 Null check on designation I forgor
sowwy, this completely breaks the server whenever a new tracker (never connected before) connects.  

;-;
2022-04-04 23:41:51 -04:00
Louka
039628d7e4 Hand tracking support + elbows without controllers
This extends the HMD skeleton to support arm tracking. We do end up with kinda duplicate bones tho.

If user has controllers: elbows go from controllers with tracker on lower arm and possibility for upper arm tracker.

If user has no controller (or no feeder app) and enables Elbow SteamVR trackers: elbows go from chest.

If user has no controllers and enables Hand SteamVR trackers: SteamVR trackers on the users hand appear using upper arm, forearm and hand trackers. Use chest tracker as well for more precision.

This also adds a lot of body proportions...
2022-04-04 22:21:18 -04:00
Eiren Rain
91fb4bc035 Merge pull request #146 from Louka3000/legs-fix
Fix ambiguous usage of "Legs"
2022-04-04 16:07:59 +03:00
Eiren Rain
d89ccc3401 Merge pull request #147 from TheDevMinerTV/fix/pingpongpacket
Fix "could not parse packet" warning for PingPongPackets
2022-04-04 16:02:21 +03:00
loucass003
7ab9a37989 Started implementing new protocol 2022-04-04 07:37:26 +02:00
TheDevMinerTV
cf7054b6da Fix "could not parse packet" warning for PingPongPackets 2022-04-04 00:29:22 +02:00
Louka
758f9e8f2f support old configs + rename in skeleton 2022-04-03 11:44:40 -04:00
Louka
fef21906f5 Fix ambiguous usage of "Legs"
- Leg in tracker roles is now knee
- Legs in SteamVR trackers to enable is now Feet
2022-04-03 11:18:44 -04:00
loucass003
4ae37944d9 Everything 2022-04-02 22:36:25 +02:00
loucass003
37ce6a69c1 update submodule 2022-04-02 22:35:45 +02:00
loucass003
aaed8fbd49 Body proportions 2022-04-02 22:33:32 +02:00
loucass003
5fbac9d861 More data 2022-04-02 08:39:31 +02:00
lucas lelievre
c54298709f update submodules url 2022-04-01 05:32:25 +02:00
lucas lelievre
b7d1637b18 Add more tracker data 2022-04-01 04:57:51 +02:00
lucas lelievre
56402526f7 new layout 2022-03-31 18:10:10 +02:00
lucas lelievre
015fa551b7 slimevr_protocol submodules 2022-03-31 16:05:34 +02:00
lucas lelievre
a681f0e5b3 rm folder 2022-03-31 16:05:03 +02:00
lucas lelievre
281810dfbb begin websocket api 2022-03-31 16:00:13 +02:00
lucas lelievre
9482e60dfa Initialize project using Create React App 2022-03-30 18:02:12 +02:00
Eiren Rain
38b8e65d53 Merge pull request #137 from Louka3000/main
Basic Interpolation and Extrapolation
2022-03-28 16:56:05 +03:00
Louka
74ccaa6cf1 fix size/capacity of circle buffer 2022-03-28 00:07:43 -04:00
Louka
4d2083df27 Use circle buffer to get previous rotations
Should help with performance.
2022-03-27 23:58:23 -04:00
Louka
98068232a6 don't create as many quaternions 2022-03-27 06:33:36 -04:00
Eiren Rain
60711df671 Merge pull request #128 from ButterscotchV/autobone-work
Consolidate PoseFrames functionality and add documentation
2022-03-24 14:05:55 +02:00
Erimel
c6b7c11418 Merge branch 'SlimeVR:main' into main 2022-03-23 21:47:52 -04:00
Eiren Rain
ece8811293 Merge pull request #138 from Louka3000/issue61
Align spine yaw with HMD when no spine trackers are present
2022-03-24 02:10:03 +02:00
Louka
8c95c491b9 use GetYaw() 2022-03-23 18:53:43 -04:00
Erimel
45091565b4 Merge branch 'SlimeVR:main' into issue61 2022-03-23 18:42:36 -04:00
Erimel
7c0222189a Merge branch 'SlimeVR:main' into main 2022-03-23 18:42:26 -04:00
Eiren Rain
a84c735761 Update commons 2022-03-24 00:40:20 +02:00
Louka
946c5d4527 calculate hmd yaw better 2022-03-23 18:34:47 -04:00
Louka
2ac6208302 / 2 * 4 = *2 2022-03-23 18:05:58 -04:00
Louka
0cd65c825c Align spine yaw with HMD when no spine tracker
issue https://github.com/SlimeVR/SlimeVR-Server/issues/61
2022-03-23 18:04:09 -04:00
Eiren Rain
43d97a7b97 Merge pull request #136 from Louka3000/upper-arms
Upper arm tracking support for VRC shoulders
2022-03-23 18:38:02 +02:00
Louka
9923556212 removed bad code lol
Code I stole was bad and did unncessery things that made extrapolation wonky
2022-03-22 21:44:29 -04:00
Louka
0a65783637 Make bone
bone yes
2022-03-22 19:58:52 -04:00
Louka
b5bd7e0a26 changed default values for filters 2022-03-22 18:35:00 -04:00
Louka
82779d101b fixed a NullPointerException
When the type was null oops
2022-03-22 01:20:40 -04:00
Louka
9c18d349dd upper arms support
for vrchat's shoulder tracking.
Not recommended since that's 2 trackers PER ARM, but good to have the option.
2022-03-22 00:46:38 -04:00
Louka
8c74071e30 Small adjustments to filter
-renamed frame to tick
- increased max intensity
2022-03-19 13:33:54 -04:00
Louka
256e5079cf Tracker filters GUI and config
I am now master at GUI.
(never again).
Might have done some dumb things like giving IMUTracker VRServer idk, tell me if there's something to fix <3
2022-03-19 03:02:06 -04:00
Louka
4263e86189 Basic interpolation and extrapolation
only the logic. Need to make config and GUI
2022-03-18 22:36:06 -04:00
Eiren Rain
dadb0bb378 Merge pull request #135 from Louka3000/main
Prettier changing proportions
2022-03-15 14:56:26 +02:00
Erimel
8ba25ca840 Merge branch 'SlimeVR:main' into main 2022-03-14 18:12:01 -04:00
Louka
09ac04331f Prettier changing proportions
- Now removes the .0 if the value is whole (only see decimal if is .5)
- Add precision adjust button unselected by default to toggle between 1 and 0.5 adjustment.
2022-03-14 18:11:29 -04:00
Eiren Rain
c21caa76d5 Bump version number to 0.1.6 2022-03-14 20:02:10 +02:00
Eiren Rain
4073d8fc32 Merge pull request #134 from Louka3000/main
Change default proportions and allow half-decimal editing
2022-03-14 15:33:49 +02:00
Erimel
f8b7be8572 Merge branch 'SlimeVR:main' into main 2022-03-13 18:27:01 -04:00
Louka
d6ab811de0 Change default proportions and allow half-decimal editing
- Better initial and default body proportions for people that don't want to calibrate
- Now changes bone length to half decimal (0.5). Rounds up to the nearest 0.5.
2022-03-13 18:25:43 -04:00
Eiren Rain
9fa6722f2b Merge pull request #133 from Blixtdraken/main
Changed the scroll speed for the ui
2022-03-13 18:21:35 +02:00
Blixtdraken
c51204e9cd Changed the scroll speed for the ui. 2022-03-13 17:12:40 +01:00
Eiren Rain
74794d8610 Merge pull request #132 from Louka3000/main
Elbow tracking support OwO
2022-03-12 12:56:49 +02:00
Louka
16978f5acd change default elbow distance
25cm to 22cm
2022-03-11 21:15:49 -05:00
Louka
71e24d0cb9 oops Mighty <3
fix FORWARD being renamed to FRONT
2022-03-10 19:47:28 -05:00
Louka
9a45f99b0e Vertical controllet offset 2022-03-10 18:45:36 -05:00
Louka
7f829f56a3 Fix reset and fix pipe creation order
owo
2022-03-10 18:35:51 -05:00
Erimel
347531f4fe Merge branch 'SlimeVR:main' into main 2022-03-10 18:21:08 -05:00
Eiren Rain
a1c33a0852 Merge pull request #131 from MightyGood/patch-1
Change FORWARD to FRONT for tracker mounting
2022-03-10 17:55:01 +02:00
MightyGood
9cd441654e Change FORWARD to FRONT for tracker mounting
Front fits better with the other options, and should cause less confusion about what the drop-down items mean.
2022-03-10 09:46:24 -06:00
Eiren Rain
88c866a735 Merge pull request #130 from kitlith/feeder_app_protobuf
Switch feeder app from old protocol to new protocol.
2022-03-10 16:00:55 +02:00
Louka
b11492c3f3 minor cleanup
removed skeleton offset for arms; useless
2022-03-10 01:07:35 -05:00
Erimel
52e30b6323 Merge pull request #3 from kitlith/feeder_app_protobuf
Switch feeder app from old protocol to new protocol.
2022-03-10 00:37:47 -05:00
Louka
1ebad806f9 Fix reset and wrist
oh wow, it works.
2022-03-09 19:24:35 -05:00
Louka
51129d3b5d Wrists
doesn't work as intended but does something
2022-03-09 01:27:13 -05:00
Louka
379e1cdcf0 Get all nodes better
for SkeletonList
2022-03-09 01:08:26 -05:00
Louka
0a8f76cfd4 Initial elbows commit
testing
2022-03-08 00:13:49 -05:00
Kitlith
a382698c32 Switch feeder app from old protocol to new protocol. 2022-03-07 20:56:22 -08:00
Butterscotch!
d43002952c Consolidate PoseFrames functionality & add documentation 2022-02-17 22:51:15 -05:00
Eiren Rain
718f1d02c6 Merge pull request #127 from ColdIce1605/ignore-runtime-created-files
Ignore runtime created files
2022-02-17 08:40:52 +02:00
ColdIce
542de22550 Revert "restart branch"
This reverts commit e18ce338e9.
2022-02-16 21:16:22 -06:00
ColdIce
327d458f00 update .gitignore 2022-02-16 21:14:49 -06:00
Eiren Rain
5f206dd12e Merge pull request #125 from Louka3000/patch-2
waist tracker will default to hip before chest
2022-02-16 12:33:09 +02:00
ColdIce
e18ce338e9 restart branch 2022-02-16 01:25:15 -06:00
Erimel
51e6255e9d waist tracker will default to hip before chest
If user has chest + waist but uses chest + hip in the server, chest would be chest+waist and waist would be hip.
This can be fixed by a better explanation of “waist vs hip” in the new GUI, or just defaulting waist to hip instead of chest when no waist tracker is found.
2022-02-15 14:48:21 -05:00
Eiren Rain
7fa7e6c2cc Merge pull request #124 from ColdIce1605/platform-package-fix
Platform Package Fix
2022-02-15 10:19:34 +02:00
ColdIce
710d154817 remove files 2022-02-15 02:17:55 -06:00
ColdIce
f354a10a81 fix .idea related things
sadly can't get rid of the one Magneto change do to LF :P
2022-02-15 02:17:14 -06:00
ColdIce
8bb8135f41 Move windows related code to its own package
Ah no more git history issues
2022-02-15 02:12:20 -06:00
Eiren Rain
e7b9968519 Better tracker timeout handling 2022-02-15 09:59:27 +02:00
Eiren Rain
bfc58d51f2 Merge pull request #122 from Kamilake/patch-1
Change the minimum compatible Java version
2022-02-11 07:14:10 +02:00
Eiren Rain
c158022da5 Merge pull request #123 from Kamilake/patch-2
Add a hide password option
2022-02-11 05:56:55 +02:00
Kamilake
9e010b0026 Add a hide password option 2022-02-11 11:44:18 +09:00
Kamilake
a085b09e07 Change the minimum compatible Java version 2022-02-11 09:36:11 +09:00
Kamilake
37da4ab7fe Change the minimum compatible Java version 2022-02-11 09:22:28 +09:00
Eiren Rain
c5945d784b Merge pull request #121 from ButterscotchV/spell-fix
Fix spelling mistakes
2022-02-09 21:09:33 +02:00
Butterscotch!
16ca08446b Fix spelling mistakes 2022-02-09 04:44:05 -05:00
Eiren Rain
b487350714 Update version to 0.1.5 2022-02-07 20:31:19 +02:00
Eiren Rain
753b12b49e Merge pull request #120 from ButterscotchV/bvh-recording
Add simple BVH recording button
2022-02-07 20:01:45 +02:00
Butterscotch!
0d90cf9c20 Add simple BVH recording button 2022-02-07 01:40:11 -05:00
Eiren Rain
658fd2916d Merge pull request #118 from deiteris/main
Switch to latest gradle and update dependencies
2022-02-05 17:43:00 +02:00
Yury
ed4ea675fb Keep JavaOSC package and remove slf4j package 2022-02-05 18:39:10 +03:00
Yury
2746fd7a67 Remove guava 2022-02-05 18:37:25 +03:00
Eiren Rain
a6b92c60b0 Update commons 2022-02-05 17:33:40 +02:00
Eiren Rain
d4d36a65ec Merge pull request #119 from ButterscotchV/bvh-fix
Fix BVH local angle calculations and abstract PoseStreamer
2022-02-05 17:25:34 +02:00
Butterscotch!
97df8ee12f Simplify PoseFrameStreamer constructor 2022-02-05 07:21:14 -05:00
Butterscotch!
2ab637b4e8 Improve PoseFrameStreamer functionality 2022-02-05 07:08:45 -05:00
Butterscotch!
9a821b051f Abstract PoseStreamer 2022-02-05 07:08:44 -05:00
Butterscotch!
e2f09fc93d Add fake root method & fix local angle calculation 2022-02-05 06:01:07 -05:00
Butterscotch!
891d8e0468 Fix BVH angles 2022-02-05 05:04:31 -05:00
Yury
494e31e41f Switch to latest gradle and update dependencies 2022-02-05 13:02:46 +03:00
Eiren Rain
b369ae6a2a Fix battery reading compatibility with owoTrack 2022-02-02 18:39:53 +02:00
Eiren Rain
5c22ef0192 Fix backwards compatibility with extensions on old firmware 2022-01-29 00:45:28 +02:00
Eiren Rain
d99cbb9c85 Fix backwards compatibility with old firmware and owoTrack 2022-01-28 02:53:08 +02:00
Eiren Rain
4f14f01830 Merge pull request #114 from SlimeVR/test
Network refactoring
2022-01-27 21:51:56 +02:00
Eiren Rain
930b5c701a Cleanup UDP responses 2022-01-27 21:38:49 +02:00
Eiren Rain
bd9e2c47a3 Merge branch 'main' into test 2022-01-27 21:30:39 +02:00
Eiren Rain
53ca2cf881 Move UDP packets and parsing to own calsses
Cleanup UDP networking significantly
2022-01-27 21:30:25 +02:00
Eiren Rain
55e17e7625 Minor network fixes 2022-01-27 19:52:30 +02:00
Eiren Rain
13b37aa2a9 Improved debug, added checkbox to display sensors debug info 2022-01-27 19:31:13 +02:00
Eiren Rain
fe4dde69ea Merge pull request #113 from Louka3000/patch-1
fix link setup
2022-01-27 02:21:07 +02:00
Erimel
0268a5a3ec fix link setup 2022-01-26 19:13:52 -05:00
Eiren Rain
4bddb529d4 Fix ping not working 2022-01-25 22:00:02 +02:00
Eiren Rain
435f5d1751 Don't create new trackers if tracker's IP changed while server is running, hand over old trackers to the new connection
Implements #70
2022-01-25 21:46:50 +02:00
Eiren Rain
af8ce60dbe Fix signal strength reading 2022-01-20 20:57:03 +02:00
Eiren Rain
25f53232cd Fix packet number reading 2022-01-20 20:27:23 +02:00
Eiren Rain
012cb518b3 Fix merge issues, track packets order, improve logging in UDP server 2022-01-20 18:03:53 +02:00
Eiren Rain
2d1ffbc5b0 Merge branch 'main' into test
# Conflicts:
#	src/main/java/dev/slimevr/vr/trackers/TrackersUDPServer.java
2022-01-20 17:54:56 +02:00
Eiren Rain
c88a6802a9 Minor debug stuff 2022-01-20 17:50:08 +02:00
Eiren Rain
f5d608ac6a Merge pull request #111 from ButterscotchV/autobone-fix
Fix AutoBone overwriting configs & improve code documentation
2022-01-20 14:19:46 +03:00
Butterscotch!
5d49bbfb29 Fix AutoBone overwriting configs & improve code documentation 2022-01-19 19:20:47 -05:00
Eiren Rain
5ce520a316 Merge pull request #110 from deiteris/main
Fix decimal places for battery voltage
2022-01-20 00:44:49 +03:00
Yury
98c2c6e202 Merge branch 'main' of https://github.com/deiteris/SlimeVR-Server 2022-01-20 00:25:12 +03:00
Yury
a2fc809d71 Fix decimal places for battery voltage 2022-01-20 00:24:47 +03:00
Eiren Rain
eb302aaef1 Merge pull request #107 from Louka3000/main
Updated default body proportions (again
2022-01-16 02:12:36 +03:00
Louka
3b354f103a Update SkeletonConfigValue.java 2022-01-15 18:00:50 -05:00
Eiren Rain
03c24a5d39 Merge pull request #106 from deiteris/main
Fix log in firewall_uninstall.bat
2022-01-13 01:11:38 +03:00
Yury
a8f13bb570 Fix log in firewall_uninstall.bat 2022-01-13 00:56:08 +03:00
Eiren Rain
f8e35e0a72 Merge pull request #105 from deiteris/main
Show battery level reported by tracker
2022-01-13 00:32:10 +03:00
Yury
27c153f5d3 Show battery level reported by tracker 2022-01-12 19:30:51 +03:00
Eiren Rain
82fdedfa14 Minor changes 2022-01-10 12:54:25 +02:00
Eiren Rain
f5bfbb13e2 Added contributions notice to the README 2022-01-10 12:50:02 +02:00
Eiren Rain
80de578334 Fix missing refactoring changes 2022-01-09 12:27:32 +02:00
Eiren Rain
3b0acbe406 Create new trackers only when sensor info packet received 2022-01-09 12:25:57 +02:00
Eiren Rain
1062361612 Merge pull request #99 from deiteris/main
Add RSSI to trackers
2022-01-09 13:17:57 +03:00
Eiren Rain
7d81fe6f92 Merge pull request #102 from Louka3000/main
Skeleton offset
2022-01-09 11:13:42 +03:00
Eiren Rain
0285eca613 Merge pull request #103 from ColdIce1605/fix-typos
Fix typos
2022-01-08 09:03:10 +03:00
James R
b0aea9ba89 fix typos 2022-01-07 20:54:34 -06:00
Louka
b98eafb66f Remove vertical foot offset
Only keep skeleton offset
2022-01-07 09:12:06 -05:00
Louka
566df6793c fixed foot rotation (I broke it)
I still think there's a better way to do this horizontal foot offset thing
2022-01-06 23:43:26 -05:00
Louka
4949e0a7f3 Skeleton offset and vertical foot offset 2022-01-06 22:30:20 -05:00
Yury
572dcdf1bb Add RSSI to trackers 2022-01-02 23:25:56 +03:00
Eiren Rain
80ce825494 Merge pull request #97 from carl-anders/keybindings-wrap-even-more-no-more-panics-plz
Keybindings: Catch even more errors, and manually check that operating system is Windows
2021-12-27 02:23:13 +03:00
Carl Andersson
bdc3b1971c Fix accidental inversion of check 2021-12-26 21:49:46 +01:00
Carl Andersson
cee400a4c6 Simplify OS & error checks 2021-12-26 21:48:52 +01:00
Carl Andersson
e58706d212 Keybindings: Catch even more errors, and manually check that operating system is Windows 2021-12-26 06:05:27 +01:00
Eiren Rain
ad03caa064 Bump version to 0.1.3 2021-12-24 21:26:03 +02:00
Eiren Rain
e2d6189547 Code formatting 2021-12-24 21:25:40 +02:00
Eiren Rain
7b15d242f7 Move rest of the classes to dev.slimev package, comment out wrong unit-test, minor cleanups 2021-12-24 21:18:58 +02:00
Eiren Rain
b81458d034 Merge pull request #95 from ButterscotchVanilla/skeleton-refactor
Skeleton refactor
2021-12-24 22:09:57 +03:00
Eiren Rain
0595422f69 Merge pull request #96 from deiteris/main
Send empty packets when there are no active trackers
2021-12-18 20:46:43 +03:00
Yury
8e58adb279 Send empty packets when there are no active trackers 2021-12-18 16:33:49 +03:00
ButterscotchVanilla
a5e4b4d8e2 Fix all config "Reset" buttons being timed 2021-12-16 21:33:48 -05:00
ButterscotchVanilla
be2c010b5a Remove comment, this was fixed 2021-12-16 19:14:37 -05:00
ButterscotchVanilla
e107326fee Fix merge conflict 2021-12-16 18:54:20 -05:00
Eiren Rain
4da54f6dec Merge pull request #94 from Louka3000/main
Changed default body proportions
2021-12-16 18:15:42 +03:00
ButterscotchVanilla
1a3a955e10 Change StringBuilder.isEmpty() to length check instead for Java 8 compatibility 2021-12-16 02:26:02 -05:00
ButterscotchVanilla
3f304f7275 Optimize offset calculation for bulk config set & finish AutoBone implementation 2021-12-16 02:06:55 -05:00
ButterscotchVanilla
0690d742c7 Properly save SkeletonConfig values 2021-12-16 01:38:16 -05:00
ButterscotchVanilla
43bbd4b4dd Update config defaults from @Louka3000 2021-12-16 00:27:19 -05:00
ButterscotchVanilla
77fa27a698 Remove String skeleton config & fix null exception with SkeletonConfig 2021-12-15 23:00:08 -05:00
Louka
8991e4f9f8 Changed default body proportions 2021-12-15 20:43:13 -05:00
ButterscotchVanilla
c9740651ba Remove other HumanSkeleton implementations 2021-12-08 23:35:21 -05:00
ButterscotchVanilla
473550ba07 Move skeleton namespace 2021-12-08 23:12:43 -05:00
ButterscotchVanilla
a7cbe91e73 Make SimpleSkeleton compatible with HumanSkeleton 2021-12-08 23:10:54 -05:00
ButterscotchVanilla
40281f68b9 Use config enum instead of strings for AutoBone 2021-12-08 22:00:43 -05:00
ButterscotchVanilla
d3049751ba Update AutoBone to use SkeletonConfig 2021-12-08 21:26:32 -05:00
ButterscotchVanilla
68164756c2 Add more ways to set SkeletonConfig values 2021-12-08 19:53:07 -05:00
ButterscotchVanilla
91c0ddef28 Add new SkeletonConfig class for configuring bone lengths and toggles 2021-12-08 17:57:53 -05:00
Eiren Rain
0641ca1b7b Bump version to 0.1.2 2021-12-07 14:26:20 +02:00
ButterscotchVanilla
e3d9eb6ac9 Add new config for offset slide error & disable dist scaling 2021-12-06 19:37:47 -05:00
ButterscotchVanilla
7eec89bd53 AutoBone: Add offset slide error 2021-12-04 20:59:42 -05:00
ButterscotchVanilla
289a7f8313 AutoBone: Scale distances by height difference 2021-12-04 02:55:18 -05:00
ButterscotchVanilla
f49b2556ae Add full tracker functionality to SimpleSkeleton 2021-12-04 00:45:37 -05:00
Eiren Rain
318c43077c Merge pull request #89 from ButterscotchVanilla/bvh-standard
Add functional BVH recording
2021-12-02 23:54:10 +03:00
Eiren Rain
5691b68166 Merge pull request #90 from ButterscotchVanilla/patch-1
Update GitHub Actions workflow
2021-12-02 23:52:31 +03:00
Butterscotch!
0ea44f988c Update GitHub Actions workflow 2021-12-02 15:45:11 -05:00
ButterscotchVanilla
59e2f796eb Add reference to ViRe in a comment 2021-12-02 12:14:45 -05:00
ButterscotchVanilla
f1a75a98d0 Add extra Spine node for rotation 2021-12-02 03:37:13 -05:00
ButterscotchVanilla
76ac3fcf55 Fix angle calculations 2021-12-01 23:50:47 -05:00
ButterscotchVanilla
6cc3c8e84b Add attempted Euler conversion 2021-12-01 23:19:00 -05:00
ButterscotchVanilla
36907c3244 Add closeOutput for specific stream 2021-12-01 20:21:55 -05:00
ButterscotchVanilla
dfeb02c1a7 Add local rotation calculations to TransformNodeWrapper 2021-12-01 20:17:36 -05:00
ButterscotchVanilla
6adf5f4090 Move node hierarchy wrapping to TransformNodeWrapper 2021-12-01 20:17:36 -05:00
ButterscotchVanilla
e44ce3fb0b Add getParent to TransformNode and add StdBVHFileStream 2021-12-01 20:17:36 -05:00
ButterscotchVanilla
76ab69e44e Wrap TransformNodes for different PoseStream hierarchy requirements 2021-12-01 20:17:35 -05:00
Eiren Rain
57d009df5c Fix bug with wrong trackers being read in skeleton if no leg trackers are attached 2021-12-02 02:11:01 +02:00
Eiren Rain
b4d07b0b7e Merge pull request #88 from deiteris/main
Improve bat script error checking
2021-12-01 16:46:07 +03:00
Yury
da3afa6f8e Improve bat script error checking 2021-12-01 11:43:35 +03:00
Eiren Rain
ec1c491e93 Merge pull request #87 from Louka3000/main
autobone hip-only doesn't affect waist distance anymore
2021-12-01 10:27:45 +03:00
Louka
baccb556e8 autobone hip-only doesn't affect waist distance anymore
- Now autobone checks if user has BOTH waist and hip tracker to add the waist distance value.
- Also renamed certain variable, replacing "hip" by "torso"
2021-11-29 20:08:08 -05:00
Eiren Rain
eedfa61d74 Merge pull request #85 from deiteris/main
Prevent path change when running as admin
2021-11-24 08:39:44 +03:00
Eiren Rain
2a9225178f Merge pull request #84 from Louka3000/main
Changed body proportions: Torso, Chest, Waist
2021-11-23 23:36:31 +03:00
Louka
259190e478 Changed body proportions: Torso, Chest, Waist
Body proportions have been changed: - Torso length is now the base value, replacing waist length in earlier versions.
- Hip length is now waist distance. Waist distance is only used when using a hip tracker
- Chest distance/length is the same. It is only used when using a chest tracker
- Autobone support with any mix-n-match configuration :)
- Virtual Waist changed its name to "Hip offset". It still behaves the same.
2021-11-23 15:11:16 -05:00
Yury
24a0c3b136 Prevent path change when running as admin 2021-11-23 12:11:09 +03:00
Louka
f46f2bc913 Tries to get the waist first for the rotation node for Autobone
When you want the rotation node, it should give the node that has the rotation that affects the bone you want
2021-11-22 22:48:43 -05:00
Eiren Rain
77f048c48e Merge pull request #83 from Louka3000/hip-tracker
Hip tracker support
2021-11-23 04:00:14 +03:00
Louka
4055d51758 Autobone support
Added basic autobone support for the hip tracker, fixed "allTracekrs" and changed initial values of upper body.
2021-11-21 18:14:19 -05:00
Louka
21eff5e1ba Better reset and initial values
owo
2021-11-20 21:32:47 -05:00
Louka
34174b442f Virtual waist affected by kneebuf 2021-11-20 20:49:32 -05:00
Louka
77d37ab2a7 Cleanup and support for hip tracker alone/
why would you want hip alone instead of waist? idk
2021-11-20 16:35:22 -05:00
Louka
350fdbce9d Can use chest tracker alone
hip tracker will default to the waist tracker's position (waist or chest) if no hip tracker is found
2021-11-20 15:03:33 -05:00
Louka
e19cec4d3e Initial commit
added hip tracking support.
Independent from waist.
Has a hip length value going from waist to hip.
Legs depend on hip instead of waist
should work normally without hip tracker.
Should work just fine with a virtual waist offset.
2021-11-20 00:04:33 -05:00
Eiren Rain
e56d7665ed Merge pull request #81 from carl-anders/softer-keybinding-failure-mode
Keybinding: If JIntellitype fails to load, still allow server to run
2021-11-12 02:59:46 +02:00
Carl Andersson
a0e23bfbe9 Keybinding: Be even better at catching errors from JIntellitype 2021-11-12 00:35:41 +01:00
Carl Andersson
b7dc33f79e Keybinding: If JIntellitype fails to load, still allow server to run 2021-11-11 06:31:35 +01:00
Eiren Rain
d8c31eec81 Merge pull request #80 from deiteris/main
Display information message in case Java is not installed
2021-11-08 20:32:42 +02:00
Yury
e84ee760b1 Display information message in case Java is not installed 2021-11-08 21:25:26 +03:00
Eiren Rain
6ba1cc6bdb Merge pull request #79 from deiteris/main
Add forgotten imports
2021-11-08 17:22:31 +02:00
Yury
1b5e534592 Add forgotten imports 2021-11-08 18:01:43 +03:00
Eiren Rain
1a3e21007b Merge pull request #78 from deiteris/main
Prevent server from running if required ports are busy
2021-11-06 20:26:58 +02:00
Yury
55e11ffb5c Prevent server from running if required ports are busy 2021-11-06 21:22:24 +03:00
Eiren Rain
957a040996 Bump version to v0.1.1 2021-10-23 21:00:31 +03:00
Eiren Rain
460a42b135 Merge pull request #67 from ButterscotchVanilla/mocap-stuff
Add base internal mocap functionality
2021-10-22 17:43:47 +03:00
Eiren Rain
8c356b401c Merge pull request #71 from Louka3000/main
Foot Offset and Updated Icons
2021-10-22 17:42:19 +03:00
ButterscotchVanilla
820d06f008 Move PoseStreamer files 2021-10-21 22:48:38 -04:00
Louka
3fa22fa716 Merge branch 'SlimeVR:main' into main 2021-10-20 21:17:09 -04:00
Louka
333daa9cfb Updated Icons
Replaced the old Icons with the new ones. Also made the 16x16 icon pixel.
2021-10-20 21:15:23 -04:00
Eiren Rain
0e61460cdb Bump version to 0.1.0 Test 1 2021-10-21 00:57:49 +03:00
Eiren Rain
268da18bb5 Properly handle tracker error state for tracker extensions, and timeout for all trackers 2021-10-21 00:57:13 +03:00
Eiren Rain
3fec29cbc6 Minor GUI cleanup 2021-10-20 03:49:57 +03:00
Louka
4f3e79a4ac Foot Offset
Added horizontal backwards/forwards foot offset feature.
2021-10-17 01:03:31 -04:00
Eiren Rain
8b3699024b Merge branch 'main' of https://github.com/SlimeVR/SlimeVR-Server into main 2021-10-17 02:08:40 +03:00
Eiren Rain
dd071f2538 Properly use tracker's IP if no MAC recieved 2021-10-17 02:07:30 +03:00
Eiren Rain
ebe74dac17 Merge pull request #69 from ButterscotchVanilla/java-popup
Add a simple error log and popup for unsupported Java versions
2021-10-14 16:35:45 +03:00
ButterscotchVanilla
909a51892f Add a simple error log and popup for unsupported Java versions 2021-10-14 04:31:20 -04:00
ButterscotchVanilla
35c26bec0f Fix Pose Recorder and Streamer synchronization and reduce if nesting 2021-10-13 07:05:29 -04:00
ButterscotchVanilla
8f05284792 Rename PoseFileStream and remove unexpected buffer 2021-10-13 03:05:39 -04:00
ButterscotchVanilla
e1d3af0734 Fix formatting 2021-10-13 02:38:30 -04:00
ButterscotchVanilla
c3fc5607ba Explain the editorconfig change in a comment 2021-10-13 01:57:07 -04:00
ButterscotchVanilla
a326d76f6a Add basic BVH file streamer 2021-10-13 01:57:07 -04:00
ButterscotchVanilla
472fcab821 Add a basic PoseStreamer implementation for streaming mocap data 2021-10-13 01:57:06 -04:00
ButterscotchVanilla
e7f81eb1aa Rename PoseFrame to PoseFrames 2021-10-13 01:57:06 -04:00
ButterscotchVanilla
31375855a0 Fix PoseRecorder frame timing 2021-10-13 01:56:04 -04:00
Eiren Rain
385890d0f0 Bundle LICENSE in the build 2021-10-05 14:58:15 +03:00
Eiren Rain
c9b4b5f18f Added explanation of licensing terms 2021-10-05 14:57:29 +03:00
Eiren Rain
c49af7fb33 Add discorvery port to firewall and add firewall uninstall script 2021-10-05 14:23:16 +03:00
Eiren Rain
4f042de2f4 Minor refactoring 2021-10-05 14:18:13 +03:00
Eiren Rain
f3e2b2ca40 Merge pull request #64 from SlimeVR/ipc-upgrade
IPC upgrade
2021-10-05 14:17:08 +03:00
Eiren Rain
a690447391 Fix thread safety 2021-10-05 14:15:47 +03:00
Eiren Rain
01593352ab Bump version to 0.1.0 2021-10-05 14:13:09 +03:00
Eiren Rain
0e4618529d Merge branch 'main' into ipc-upgrade 2021-10-05 14:11:04 +03:00
Eiren Rain
57c97cd5e1 Move eclipse project to java 11 2021-10-05 13:51:57 +03:00
Eiren Rain
8606c0daa3 Change how SteamVR trackers are selected 2021-10-05 13:51:44 +03:00
Eiren Rain
e94551d4f7 Merge pull request #63 from carl-anders/keyboard-keybindings
Keyboard keybindings: Actually do the correct type of reset
2021-10-03 21:26:33 +03:00
Carl Andersson
ffcd4f32ed Keyboard keybindings: Actually do the correct type of reset 2021-10-03 20:21:21 +02:00
Eiren Rain
2248f577df Merge pull request #62 from adigyran/main
Updated github CI to use 11th java
2021-10-03 18:33:01 +03:00
adigyran
8a57553986 updated gradle CI to use 11th java 2021-10-03 18:31:36 +03:00
Eiren Rain
bb01ce776b Merge branch 'main' into ipc-upgrade
# Conflicts:
#	src/main/java/io/eiren/vr/trackers/TrackersUDPServer.java
2021-10-03 13:18:14 +03:00
Eiren Rain
631870846c Fix classpath for new gradle build 2021-10-03 13:13:33 +03:00
Eiren Rain
a45abb7992 Update README.md 2021-10-02 19:48:54 +03:00
Eiren Rain
c7aaffa5e6 Merge pull request #58 from adigyran/main
slime commons as submodule
2021-10-02 19:46:34 +03:00
adigyran
7def0d0b4e gitlab ci with submodule 2021-10-02 19:44:14 +03:00
adigyran
c035135fb7 slime commons as submodule 2021-10-02 18:43:51 +03:00
Eiren Rain
15ffdeeeb8 Merge pull request #57 from carl-anders/keyboard-keybindings
Keyboard keybindings
2021-10-02 17:47:18 +03:00
Eiren Rain
74f6902a1b Fix NPE in WebSocket bridge 2021-10-02 17:45:56 +03:00
Carl Andersson
b2ae71333a Remove unused json dependency 2021-10-02 16:31:45 +02:00
Carl Andersson
fc88269f2d Add support for keyboard keybindings for reset and quick reset 2021-10-02 15:30:53 +02:00
Eiren Rain
a191fcf803 Bump version to Test 6 2021-10-01 17:39:20 +03:00
Eiren Rain
37b109bd73 Make UDP server support any number of sensors on a single tracker 2021-10-01 17:39:03 +03:00
Eiren Rain
27b2a77f48 Display descriptive tracker names instead of mac addresses in the GUI 2021-10-01 17:30:37 +03:00
Eiren Rain
0f34dd0967 Add back the bridge for SteamVR input, make it also reconnect automatically 2021-10-01 17:30:17 +03:00
Eiren Rain
10fc717500 Fix new bridge 2021-10-01 14:49:01 +03:00
Eiren Rain
250068c6c2 Reset trackers on bridge disconnect 2021-10-01 13:32:44 +03:00
Eiren Rain
488838752b Implement new named pipe bridge and test it lightly 2021-10-01 12:27:04 +03:00
Eiren Rain
dd0f4deae3 Merge pull request #54 from JimWails/main
Fix Spelling mistakes
2021-10-01 04:28:01 +03:00
JimWails
2df4106c92 Fix Spelling mistakes
Change upd:// to udp://
2021-09-30 23:48:42 +08:00
Eiren Rain
ed58076c68 Rework new bridge, don't use internal trackers
Update messages, added more enums and such; some refactoring
2021-09-30 14:42:37 +03:00
Eiren Rain
a4b300198d More work on IPC, minor bridges refactoring 2021-09-29 21:51:14 +03:00
Eiren Rain
6980023c5a Merge branch 'main' into ipc-upgrade 2021-09-29 20:37:35 +03:00
Eiren Rain
9f4d956345 Don't start SteamVR bridge not on Windows for now 2021-09-29 17:16:28 +03:00
Eiren Rain
ce4a90dc55 Early implementation of WebSocket VR Bridge 2021-09-24 01:53:10 +03:00
Eiren Rain
82ba193bb4 Minor GUI cleanup 2021-09-23 22:55:45 +03:00
Eiren Rain
a3a004536d Make GUI greatly less annoying and stretchy 2021-09-23 22:46:17 +03:00
Eiren Rain
bb1d7e06c2 Minor GUI update 2021-09-23 21:42:11 +03:00
Eiren Rain
3689e6723c IPC upgrade WIP 2021-09-23 21:18:42 +03:00
Eiren Rain
ef504c40b6 Use tracker mac address to save tracker configs 2021-09-22 22:37:45 +03:00
Eiren Rain
5e4a128d25 Update firewall script 2021-09-21 20:22:48 +03:00
Eiren Rain
67d93d87b5 Added protobuf and generated messages class 2021-09-18 23:44:51 +03:00
Eiren Rain
56b8b58606 Bump version to 0.0.19 2021-09-18 16:51:49 +03:00
Eiren Rain
97bc9343c1 Code formatting, move some packages 2021-09-18 16:50:54 +03:00
Eiren Rain
18cea30f72 Merge pull request #49 from ButterscotchVanilla/autobone-positions
AutoBone PoseFrame file format rework and other related fixes
2021-09-18 03:04:29 +03:00
Eiren Rain
d5c048600e Fix SteamVR input bridge not setting tracker status properly 2021-09-18 02:58:22 +03:00
ButterscotchVanilla
6d103d4ff9 Get all trackers directly in setPoseFromFrame 2021-09-17 19:18:24 -04:00
Eiren Rain
7008197760 Merge pull request #48 from kitlith/target_java8_release
Fixes some compatibility issues when compiling with Java9+ jdk.
2021-09-17 15:32:21 +03:00
Kitlith
da66f33edc Fixes some compatibility issues when compiling with Java9+ jdk.
i.e.:
java.lang.NoSuchMethodError:
java.nio.ByteBuffer.rewind()Ljava/nio/ByteBuffer;
2021-09-16 16:36:00 -07:00
ButterscotchVanilla
4109d1c825 Add pelvis averaging for SimpleSkeleton and fix neck rotation 2021-09-16 00:30:22 -04:00
ButterscotchVanilla
a300663a9e Spelling fix and check for null in TrackerUtils 2021-09-14 10:36:35 -04:00
ButterscotchVanilla
cb33dac3b9 Handle getRotation and getPosition responses properly 2021-09-14 09:14:16 -04:00
ButterscotchVanilla
582bac8050 Check recording for chest tracker when loading AutoBone configs 2021-09-14 09:08:22 -04:00
ButterscotchVanilla
5e1c45bc09 Record individual trackers with PoseFrame and optimize iterations 2021-09-14 08:50:08 -04:00
ButterscotchVanilla
b3073e6938 Handle busy status and add better exception messages 2021-09-14 04:20:43 -04:00
ButterscotchVanilla
63e259689f Handle computed trackers better and handle tracker status in data collection 2021-09-14 04:01:10 -04:00
ButterscotchVanilla
d92ea0a39e Small clean-up and ignore computed trackers in PoseFrame by default 2021-09-14 02:52:06 -04:00
ButterscotchVanilla
81bbb4008b Only allow loading tracker configs if the tracker is user editable 2021-09-14 01:45:35 -04:00
ButterscotchVanilla
45ad0698b1 Allow multiple TrackerFrames with the same designation in PoseFrame, make TrackerFrame extend Tracker 2021-09-14 01:06:36 -04:00
ButterscotchVanilla
bc542a7bb1 Don't put null designations in the trackers 2021-09-12 13:19:33 -04:00
ButterscotchVanilla
efb065f558 Fix TrackerBodyPosition.getByDesignation capitalization 2021-09-12 13:19:33 -04:00
ButterscotchVanilla
00e63db029 Use HashMap directly 2021-09-12 13:19:32 -04:00
ButterscotchVanilla
f6a2926033 Remove comment and useless if statement 2021-09-12 13:19:32 -04:00
ButterscotchVanilla
5b0f8afa4e Change namespaces, change PoseRecorder format, use TrackerBodyPosition for designation 2021-09-12 13:19:32 -04:00
Eiren Rain
c5b4421eae Fix tracker info not updating for IMU trackers 2021-09-12 19:58:03 +03:00
Eiren Rain
4d3f04e227 Bump version to 0.0.18 Test 3 2021-09-12 12:11:20 +03:00
Eiren Rain
75ad29a68d Can select role for SteamVR trackers
Trackers now have info if they report position or rotation
Extended pelvis model is always on
2021-09-12 12:10:59 +03:00
Eiren Rain
62e1e65dda Merge pull request #46 from ButterscotchVanilla/pelvis-fix
Fix leg averaging for pelvis and add waist tracker averaging
2021-09-12 12:00:11 +03:00
ButterscotchVanilla
02f64314b8 Fix leg averaging for pelvis and add waist tracker averaging 2021-09-12 04:49:54 -04:00
Eiren Rain
12d7f191ee Fix NPE, added bat scripts to the build 2021-09-04 09:25:16 +03:00
Eiren Rain
37135e1c8e Merge pull request #45 from ButterscotchVanilla/main
AutoBone: Move hardcoded values to variables
2021-09-03 06:54:33 +03:00
ButterscotchVanilla
85a0c25d0e AutoBone: Move hardcoded values to variables 2021-09-02 22:17:19 -04:00
Eiren Rain
1f081392df Always have a skeleton with legs, can work with any trackers, fill in empty trackers with static or previous 2021-09-02 11:41:54 +03:00
Eiren Rain
c02f9b827d Merge branch 'main' of https://github.com/SlimeVR/SlimeVR-Server into main 2021-09-02 11:33:46 +03:00
Eiren Rain
7e95c9f999 Remember window size and position between restarts
Added window and taskbar icons
2021-09-02 11:33:27 +03:00
Eiren Rain
4836b025e9 Merge pull request #41 from JimWails/main
Add support for ch910xx
2021-08-29 17:08:04 +03:00
JimWails
9a76838602 Add support for ch910xx
Already test on ESP8266 which use CH9102X driver
2021-08-28 22:27:30 +08:00
Eiren Rain
6c27186ce9 Make GUI less garbage (still gabage, but less) 2021-08-26 11:57:35 +03:00
Eiren Rain
74c25c2ca3 Don't use source port to id trackers 2021-08-23 16:39:43 +03:00
Eiren Rain
91ee6ff6c0 Merge pull request #35 from adigyran/patch-6
Update README.md
2021-08-22 15:59:17 +03:00
Yury
05ba866bef Update README.md
new build command
2021-08-22 15:55:38 +03:00
Eiren Rain
af3aab86dc Don't crash on pipe errors, just log them 2021-08-22 15:03:11 +03:00
Eiren Rain
4370defb69 Merge pull request #34 from adigyran/main
Gradle shadow plugin for dependency resolving
2021-08-22 14:50:20 +03:00
Eiren Rain
a105879c9a Supress config file not found error to create less confusion 2021-08-22 14:46:55 +03:00
Eiren Rain
9383be678c Don't parse some packets when paired with owoTrack #33 2021-08-22 14:46:35 +03:00
Eiren Rain
7c8a394147 Handle HMD pipe better 2021-08-22 14:43:27 +03:00
Eiren Rain
ffc8a9dae4 Remove new spine model from the main branch 2021-08-22 14:36:35 +03:00
adigyran
bb4a65882d Gradle shadow plugin. Based on Kitlith change of build.gradle. Using now library for Slime Commons dependency resolving. Changed gradle.yml accordingly. It produces slimevr.jar file 2021-08-22 13:44:26 +03:00
Yury
5ebbb907e7 Update gradle.yml
fix resolving
2021-08-22 13:39:20 +03:00
Yury
2ba66d7f91 Update .github/workflows/gradle.yml
Co-authored-by: Butterscotch! <bscotchvanilla@gmail.com>
2021-08-22 13:38:28 +03:00
Yury
7f8fe9e4f4 Update .github/workflows/gradle.yml
Co-authored-by: Butterscotch! <bscotchvanilla@gmail.com>
2021-08-22 13:38:22 +03:00
Yury
12292070ce Update .github/workflows/gradle.yml
Co-authored-by: Butterscotch! <bscotchvanilla@gmail.com>
2021-08-22 13:34:46 +03:00
adigyran
8bc2b72ab0 readme fix for new command 2021-08-22 13:32:20 +03:00
adigyran
208ae6b6d6 reformat code 2021-08-22 13:21:20 +03:00
adigyran
ba8121a8a7 Gradle shadow plugin. Based on Kitlith change of build.gradle. Using now library for Slime Commons dependency resolving. Changed gradle.yml accordingly. It produces slimevr.jar file 2021-08-22 13:15:22 +03:00
Eiren Rain
c8da0427f9 Added simple test extended spine model, SlimeVR/SlimeVR-Server#31 2021-08-20 17:05:15 +03:00
429 changed files with 116954 additions and 7105 deletions

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" output="bin/main" path="src/main/java">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/main" path="src/main/resources">
<attributes>
<attribute name="gradle_scope" value="main"/>
<attribute name="gradle_used_by_scope" value="main,test"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/java">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="bin/test" path="src/test/resources">
<attributes>
<attribute name="gradle_scope" value="test"/>
<attribute name="gradle_used_by_scope" value="test"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8/"/>
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
<classpathentry combineaccessrules="false" kind="src" path="/Slime Java Commons"/>
<classpathentry kind="output" path="bin/default"/>
</classpath>

View File

@@ -1,11 +0,0 @@
# This file is for unifying the coding style for different editors and IDEs
# See editorconfig.org
root = true
[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

80
.github/workflows/build-gui.yml vendored Normal file
View File

@@ -0,0 +1,80 @@
name: Build GUI
on:
push:
paths:
- .github/workflows/build-gui.yml
- gui/**
- package*.json
pull_request:
paths:
- .github/workflows/build-gui.yml
- gui/**
- package*.json
workflow_dispatch:
jobs:
build:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, windows-latest]
node-version: [16.x]
runs-on: ${{ matrix.os }}
env:
# Don't mark warnings as errors
CI: false
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- if: matrix.os == 'ubuntu-latest'
name: Set up Linux dependencies
run: |
sudo apt-get update
sudo apt-get install -y libgtk-3-dev webkit2gtk-4.0 libappindicator3-dev librsvg2-dev patchelf
- name: Cache cargo dependencies
uses: Swatinem/rust-cache@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Build
run: |
npm ci
npm run tauri build
- if: matrix.os == 'windows-latest'
name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.0
with:
# Artifact name
name: SlimeVR-GUI
# A file, directory or wildcard pattern that describes what to upload
path: gui/target/release/slimevr-ui.exe
- if: matrix.os == 'ubuntu-latest'
name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.0
with:
# Artifact name
name: SlimeVR-GUI-Deb
# A file, directory or wildcard pattern that describes what to upload
path: gui/target/release/bundle/deb/slimevr-ui*.deb
- if: matrix.os == 'ubuntu-latest'
name: Upload a Build Artifact
uses: actions/upload-artifact@v3.1.0
with:
# Artifact name
name: SlimeVR-GUI-AppImage
# A file, directory or wildcard pattern that describes what to upload
path: gui/target/release/bundle/appimage/slimevr-ui*.AppImage

61
.github/workflows/gradle.yaml vendored Normal file
View File

@@ -0,0 +1,61 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: SlimeVR Server
on: [push, pull_request]
jobs:
test:
strategy:
matrix:
os: [ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: "17"
distribution: "adopt"
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Check code formatting
run: ./gradlew spotlessCheck
- name: Test with Gradle
run: ./gradlew test
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: "17"
distribution: "adopt"
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Build with Gradle
run: ./gradlew shadowJar
- name: Upload the Server JAR as a Build Artifact
uses: actions/upload-artifact@v3
with:
# Artifact name
name: "SlimeVR-Server" # optional, default is artifact
# A file, directory or wildcard pattern that describes what to upload
path: server/build/libs/*

View File

@@ -1,65 +0,0 @@
# This workflow will build a Java project with Gradle
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
name: SlimeVR Server
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
- name: Clone Slime Java Commons
uses: actions/checkout@v2.3.4
with:
repository: Eirenliel/slime-java-commons
# Relative path under $GITHUB_WORKSPACE to place the repository
path: Slime Java Commons
- name: Set up JDK 8
uses: actions/setup-java@v2.1.0
with:
java-version: '8'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Test with Gradle
run: ./gradlew clean test
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.4
- name: Clone Slime Java Commons
uses: actions/checkout@v2.3.4
with:
repository: Eirenliel/slime-java-commons
# Relative path under $GITHUB_WORKSPACE to place the repository
path: Slime Java Commons
- name: Set up JDK 8
uses: actions/setup-java@v2.1.0
with:
java-version: '8'
distribution: 'adopt'
- name: Grant execute permission for gradlew
run: chmod +x gradlew
- name: Build with Gradle
run: ./gradlew clean serverJar
- name: Upload the Server JAR as a Build Artifact
uses: actions/upload-artifact@v2.2.4
with:
# Artifact name
name: "SlimeVR-Server" # optional, default is artifact
# A file, directory or wildcard pattern that describes what to upload
path: build/libs/*

30
.gitignore vendored
View File

@@ -1,12 +1,30 @@
# Ignore Gradle project-specific cache directory
.gradle
# Ignore Gradle build output directory
build
/bin/
# Syncthing ignore file
.stignore
MagnetoLib.dll
# Ignore .idea
.idea
# Ignore eclipse stuff
.project
.classpath
.settings
# VSCode stuff
/.vscode/settings.json
# Ignore eclipse stuff
.project
.classpath
.settings
# Node Stuff
/node_modules
.husky
# ignore gradle build folder
build/

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "solarxr-protocol"]
path = solarxr-protocol
url = https://github.com/SlimeVR/SolarXR-Protocol.git

View File

@@ -1,23 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>SlimeVR Server</name>
<comment>SlimeVR Server</comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
</natures>
</projectDescription>

View File

@@ -1,2 +0,0 @@
connection.project.dir=
eclipse.preferences.version=1

View File

@@ -1,2 +0,0 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8

View File

@@ -1,2 +0,0 @@
eclipse.preferences.version=1
line.separator=\r\n

View File

@@ -1,416 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.annotation.inheritNullAnnotations=enabled
org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore
org.eclipse.jdt.core.compiler.annotation.nonnull=org.eclipse.jdt.annotation.NonNull
org.eclipse.jdt.core.compiler.annotation.nonnull.secondary=
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=org.eclipse.jdt.annotation.NonNullByDefault
org.eclipse.jdt.core.compiler.annotation.nonnullbydefault.secondary=
org.eclipse.jdt.core.compiler.annotation.nullable=org.eclipse.jdt.annotation.Nullable
org.eclipse.jdt.core.compiler.annotation.nullable.secondary=
org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.methodParameters=do not generate
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.APILeak=warning
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning
org.eclipse.jdt.core.compiler.problem.deadCode=ignore
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=info
org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore
org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
org.eclipse.jdt.core.compiler.problem.fatalOptionalError=disabled
org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning
org.eclipse.jdt.core.compiler.problem.forbiddenReference=info
org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning
org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled
org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore
org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=warning
org.eclipse.jdt.core.compiler.problem.localVariableHiding=ignore
org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning
org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore
org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=error
org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled
org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error
org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled
org.eclipse.jdt.core.compiler.problem.missingSerialVersion=ignore
org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=error
org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning
org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning
org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
org.eclipse.jdt.core.compiler.problem.nonnullParameterAnnotationDropped=warning
org.eclipse.jdt.core.compiler.problem.nonnullTypeVariableFromLegacyInvocation=warning
org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error
org.eclipse.jdt.core.compiler.problem.nullReference=error
org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error
org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning
org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
org.eclipse.jdt.core.compiler.problem.pessimisticNullAnalysisForFreeTypeVariables=warning
org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning
org.eclipse.jdt.core.compiler.problem.potentialNullReference=ignore
org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=ignore
org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning
org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning
org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore
org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore
org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore
org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning
org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled
org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
org.eclipse.jdt.core.compiler.problem.syntacticNullAnalysisForFields=enabled
org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore
org.eclipse.jdt.core.compiler.problem.terminalDeprecation=warning
org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=enabled
org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
org.eclipse.jdt.core.compiler.problem.unclosedCloseable=warning
org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore
org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentType=warning
org.eclipse.jdt.core.compiler.problem.unlikelyCollectionMethodArgumentTypeStrict=disabled
org.eclipse.jdt.core.compiler.problem.unlikelyEqualsArgumentType=info
org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore
org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=ignore
org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=ignore
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
org.eclipse.jdt.core.compiler.problem.unusedExceptionParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedImport=warning
org.eclipse.jdt.core.compiler.problem.unusedLabel=warning
org.eclipse.jdt.core.compiler.problem.unusedLocal=warning
org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning
org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning
org.eclipse.jdt.core.compiler.problem.unusedTypeParameter=ignore
org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning
org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning
org.eclipse.jdt.core.compiler.source=1.8
org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines=2147483647
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=48
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=0
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=0
org.eclipse.jdt.core.formatter.alignment_for_compact_if=0
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=0
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=48
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header=0
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_module_statements=16
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=0
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=48
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_type_arguments=0
org.eclipse.jdt.core.formatter.alignment_for_type_parameters=0
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=false
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=false
org.eclipse.jdt.core.formatter.comment.format_line_comments=false
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=4
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=false
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=200
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement=common_lines
org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause=common_lines
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=tab
org.eclipse.jdt.core.formatter.tabulation.size=4
org.eclipse.jdt.core.formatter.use_on_off_tags=true
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
org.eclipse.jdt.core.formatter.wrap_before_assignment_operator=false
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_conditional_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true
org.eclipse.jdt.core.javaFormatter=org.eclipse.jdt.core.defaultJavaFormatter

View File

@@ -1,3 +0,0 @@
eclipse.preferences.version=1
formatter_profile=_Essentia
formatter_settings_version=13

15
.vscode/extensions.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
// See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations.
// Extension identifier format: ${publisher}.${name}. Example: vscode.csharp
// List of extensions which should be recommended for users of this workspace.
"recommendations": [
"richardwillis.vscode-spotless-gradle",
"gaborv.flatbuffers",
"dbaeumer.vscode-eslint",
"esbenp.prettier-vscode",
"rust-lang.rust-analyzer",
"bradlc.vscode-tailwindcss"
],
// List of extensions recommended by VS Code that should not be recommended for users of this workspace.
"unwantedRecommendations": []
}

75
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,75 @@
# Contributing to SlimeVR
This document describes essential knowledge for contributors to SlimeVR.
## How to get started
### Getting the code
First, clone the codebase using `git`. If you don't have `git` installed, go install it.
```bash
# Clone repositories
git clone --recursive https://github.com/SlimeVR/SlimeVR-Server.git
# Enter the directory of the codebase
cd SlimeVR-Server
```
Now you can open the codebase in your favorite IDE or text editor.
### Building the code
The code is built with `gradle`, a cli tool that manages java projects and their
dependencies. You can build the code with `./gradlew build` and run it with
`./gradlew run`.
## Code Style
Code is autoformatted with [spotless](https://github.com/diffplug/spotless/tree/main/plugin-gradle).
Code is checked for autoformatting whenever you build, but you can also run
`./gradlew spotlessCheck` if you prefer.
To autoformat your code from the command line, you can run `./gradlew spotlessApply`.
We recommend installing support for spotless in your IDE of choice, and formatting
whenever you save a file, to make things easy.
If you need to prevent autoformatting for a particular region of code, use
`// @formatter:off` and `// @formatter:on`
### Setting up spotless in VSCode
* Install the `richardwillis.vscode-spotless-gradle` extension
* Add the following to your workspace settings, at `.vscode/settings.json`:
```json
"spotlessGradle.format.enable": true,
"editor.formatOnSave": true,
"[java]": {
"editor.defaultFormatter": "richardwillis.vscode-spotless-gradle"
}
```
### Setting up spotless for IntelliJ
* Install https://plugins.jetbrains.com/plugin/18321-spotless-gradle.
* Add a keyboard shortcut for `Code` > `Reformat Code with Spotless`
* They are working on support to do this on save without a keybind
[here](https://github.com/ragurney/spotless-intellij-gradle/issues/8)
### Setting up Eclipse autoformatting
Import the formatting settings defined in `spotless.xml`, like this:
* Go to `File > Properties`, then `Java Code Style > Formatter`
* Check `Enable project specific settings`
* Click `Import`, then open `spotless.xml`, then `Apply`
* Go to `Java Editor > Save Actions`
* Select `Enable project specific settings`, `Perform the selected actions on save`,
`Format source code`, `Format all lines`
Eclipse will only do a subset of the checks in `spotless`, so you may still want to do
`./gradlew spotlessApply` if you ever see an error from spotless.
## Code Licensing
SlimeVR uses an MIT license, and some parts of the project use a dual MIT/Apache 2.0
license. Be sure that any code that you reference, or dependencies you add, are
compatible with these licenses. `GPL-v3` for example is not compatible because it
requires any and all code that depends on it to *also* be licensed under `GPL-v3`.
## Discord
We use discord *a lot* to coordinate and discuss development. Come join us at
https://discord.gg/SlimeVR!

42
LICENSE
View File

@@ -1,21 +1,21 @@
MIT License
Copyright (c) 2021 Eiren Rain
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
MIT License
Copyright (c) 2021 Eiren Rain, SlimeVR
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -13,22 +13,22 @@ Integrations:
## How to use
Latest instructions are currently [here](https://gist.github.com/Eirenliel/8c0eefcdbda1076d5c2e1bf634831d20). Will be updated and republished as time goes on.
It's recommended to download installer from here: https://github.com/SlimeVR/SlimeVR-Installer/releases/latest/download/slimevr_web_installer.exe
## How to build
Latest instructions are [on our site](https://docs.slimevr.dev/server-setup/slimevr-setup.html).
You need to execute these commands in the folder where you want this project.
## License Clarification
```bash
# Clone repositories
git clone https://github.com/SlimeVR/SlimeVR-Server.git
git clone https://github.com/Eirenliel/slime-java-commons.git
**SlimeVR software** (including server, firmware, drivers, installator, documents, and others - see licence for each case specifically) **is distributed under the [MIT License](https://github.com/SlimeVR/SlimeVR-Server/blob/main/LICENSE) and is copyright of Eiren Rain and SlimeVR.** The MIT Licence is a permissive license giving you rights to modify and distribute the software with little strings attached.
# Enter the directory and build the runnable server JAR
cd SlimeVR-Server
gradlew serverJar
```
**However, the MIT License has some limits, and if you wish to distribute software based on SlimeVR, you need to be aware of them:**
Open Slime VR Server project in Eclipse or Intellij Idea
* When distributing any software that uses or is based on SlimeVR, you have to provide to the end-user the original, unmodified `LICENSE` file from SlimeVR. This file is located [here](https://github.com/SlimeVR/SlimeVR-Server/blob/main/LICENSE). This includes the `Copyright (c) 2021 Eiren Rain, SlimeVR` part of the license. It is not sufficient to use a generic MIT License, it must be the original license file.
* This applies even if you distribute software without the source code. In this case, one way to provide it to the end-user is to have a menu in your application that lists all the open source licenses used, including SlimeVR's.
run gradle command `serverJar` to build a runnable server JAR
Please refer to the [LICENSE](https://github.com/SlimeVR/SlimeVR-Server/blob/main/LICENSE) file if you are at any point uncertain what the exact the requirements are.
## Contributions
By contributing to this project you are placing all your code under MIT or less restricting licenses, and you certify that the code you have used is compatible with those licenses or is authored by you. If you're doing so on your work time, you certify that your employer is okay with this.
For a how-to on contributing, see [CONTRIBUTING.md](CONTRIBUTING.md).

View File

@@ -1,77 +0,0 @@
/*
* This file was generated by the Gradle 'init' task.
*
* This generated file contains a sample Java Library project to get you started.
* For more details take a look at the Java Libraries chapter in the Gradle
* User Manual available at https://docs.gradle.org/6.3/userguide/java_library_plugin.html
*/
plugins {
// Apply the java-library plugin to add support for Java Library
id 'java-library'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
// Set compiler to use UTF-8
compileJava.options.encoding = 'UTF-8'
compileTestJava.options.encoding = 'UTF-8'
javadoc.options.encoding = 'UTF-8'
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
tasks.withType(Test) {
systemProperty('file.encoding', 'UTF-8')
}
tasks.withType(Javadoc){
options.encoding = 'UTF-8'
}
repositories {
// Use jcenter for resolving dependencies.
// You can declare any Maven/Ivy/file repository here.
jcenter()
mavenCentral()
}
dependencies {
compile project(':Slime Java Commons')
// This dependency is exported to consumers, that is to say found on their compile classpath.
compile 'org.apache.commons:commons-math3:3.6.1'
compile 'org.yaml:snakeyaml:1.25'
compile 'net.java.dev.jna:jna:5.6.0'
compile 'net.java.dev.jna:jna-platform:5.6.0'
compile 'com.illposed.osc:javaosc-core:0.8'
compile 'com.fazecast:jSerialComm:[2.0.0,3.0.0)'
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:28.2-jre'
// Use JUnit test framework
testImplementation platform('org.junit:junit-bom:5.7.2')
testImplementation 'org.junit.jupiter:junit-jupiter'
testImplementation 'org.junit.platform:junit-platform-launcher'
}
test {
useJUnitPlatform()
}
subprojects.each { subproject -> evaluationDependsOn(subproject.path) }
task serverJar (type: Jar, dependsOn: subprojects.tasks['build']) {
// Make the JAR runnable
manifest {
attributes 'Main-Class': 'io.eiren.vr.Main'
}
// Pack all dependencies within the JAR
from {
configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
}
// Add this project's classes in the JAR
with jar
}

6
gradle.properties Normal file
View File

@@ -0,0 +1,6 @@
# Fixes bug with spotless. See https://github.com/diffplug/spotless/issues/834#issuecomment-819118761
org.gradle.jvmargs=--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED \
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED

Binary file not shown.

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.3-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

269
gradlew vendored Normal file → Executable file
View File

@@ -1,7 +1,7 @@
#!/usr/bin/env sh
#!/bin/sh
#
# Copyright 2015 the original author or authors.
# Copyright © 2015-2021 the original authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -17,78 +17,113 @@
#
##############################################################################
##
## Gradle start up script for UN*X
##
#
# Gradle start up script for POSIX generated by Gradle.
#
# Important for running:
#
# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
# noncompliant, but you have some other compliant shell such as ksh or
# bash, then to run this script, type that shell name before the whole
# command line, like:
#
# ksh Gradle
#
# Busybox and similar reduced shells will NOT work, because this script
# requires all of these POSIX shell features:
# * functions;
# * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
# «${var#prefix}», «${var%suffix}», and «$( cmd )»;
# * compound commands having a testable exit status, especially «case»;
# * various built-in commands including «command», «set», and «ulimit».
#
# Important for patching:
#
# (2) This script targets any POSIX shell, so it avoids extensions provided
# by Bash, Ksh, etc; in particular arrays are avoided.
#
# The "traditional" practice of packing multiple parameters into a
# space-separated string is a well documented source of bugs and security
# problems, so this is (mostly) avoided, by progressively accumulating
# options in "$@", and eventually passing that to Java.
#
# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
# see the in-line comments for details.
#
# There are tweaks for specific operating systems such as AIX, CygWin,
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
#
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
app_path=$0
# Need this for daisy-chained symlinks.
while
APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
[ -h "$app_path" ]
do
ls=$( ls -ld "$app_path" )
link=${ls#*' -> '}
case $link in #(
/*) app_path=$link ;; #(
*) app_path=$APP_HOME$link ;;
esac
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
APP_BASE_NAME=${0##*/}
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
MAX_FD=maximum
warn () {
echo "$*"
}
} >&2
die () {
echo
echo "$*"
echo
exit 1
}
} >&2
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
case "$( uname )" in #(
CYGWIN* ) cygwin=true ;; #(
Darwin* ) darwin=true ;; #(
MSYS* | MINGW* ) msys=true ;; #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
JAVACMD=$JAVA_HOME/jre/sh/java
else
JAVACMD="$JAVA_HOME/bin/java"
JAVACMD=$JAVA_HOME/bin/java
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
@@ -97,7 +132,7 @@ Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
JAVACMD=java
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
@@ -105,79 +140,95 @@ location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, stacking in reverse order:
# * args from the command line
# * the main class name
# * -classpath
# * -D...appname settings
# * --module-path (only if needed)
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
# For Cygwin or MSYS, switch paths to Windows format before running java
if "$cygwin" || "$msys" ; then
APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
JAVACMD=$( cygpath --unix "$JAVACMD" )
# Now convert the arguments - kludge to limit ourselves to /bin/sh
for arg do
if
case $arg in #(
-*) false ;; # don't mess with options #(
/?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
[ -e "$t" ] ;; #(
*) false ;;
esac
then
arg=$( cygpath --path --ignore --mixed "$arg" )
fi
# Roll the args list around exactly as many times as the number of
# args, so each arg winds up back in the position where it started, but
# possibly modified.
#
# NB: a `for` loop captures its iteration list before it begins, so
# changing the positional parameters here affects neither the number of
# iterations, nor the values presented in `arg`.
shift # remove old arg
set -- "$@" "$arg" # push replacement arg
done
fi
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
# double quotes to make sure that they get re-expanded; and
# * put everything else in single quotes, so that it's not re-expanded.
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.
#
# In Bash we could simply go:
#
# readarray ARGS < <( xargs -n1 <<<"$var" ) &&
# set -- "${ARGS[@]}" "$@"
#
# but POSIX shell has neither arrays nor command substitution, so instead we
# post-process each arg (as a line of input to sed) to backslash-escape any
# character that might be a shell metacharacter, then use eval to reverse
# that process (while maintaining the separation between arguments), and wrap
# the whole thing up as a single "set" statement.
#
# This will of course break if any of these variables contains a newline or
# an unmatched quote.
#
eval "set -- $(
printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
xargs -n1 |
sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"

22
gradlew.bat vendored
View File

@@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@@ -54,7 +54,7 @@ goto fail
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
@@ -64,28 +64,14 @@ echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windows variants
if not "%OS%" == "Windows_NT" goto win9xME_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell

40
gui/.eslintrc.json Normal file
View File

@@ -0,0 +1,40 @@
{
"env": {
"browser": true,
"es2021": true,
"jest": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"prettier"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": "latest",
"sourceType": "module"
},
"plugins": ["react-hooks", "@typescript-eslint", "prettier"],
"rules": {
"react/react-in-jsx-scope": "off",
"react/prop-types": "off",
"spaced-comment": "error",
"quotes": ["error", "single"],
"no-duplicate-imports": "error",
"no-inline-styles": "off",
"@typescript-eslint/no-explicit-any": "off",
"react/no-unescaped-entities": "off",
"prettier/prettier": "warn"
},
"settings": {
"import/resolver": {
"typescript": {}
},
"react": {
"version": "detect"
}
}
}

1
gui/.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
* text=auto eol=lf

26
gui/.gitignore vendored Normal file
View File

@@ -0,0 +1,26 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# JS/TS dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# Build artifacts
/build
/target
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
*.log

6
gui/.prettierrc Normal file
View File

@@ -0,0 +1,6 @@
{
"trailingComma": "es5",
"tabWidth": 2,
"semi": true,
"singleQuote": true
}

3392
gui/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

3
gui/Cargo.toml Normal file
View File

@@ -0,0 +1,3 @@
[workspace]
resolver = "2"
members = ["src-tauri"]

6
gui/LICENSE Normal file
View File

@@ -0,0 +1,6 @@
This codebase is dual-licensed under either
* MIT License (docs/LICENSE-MIT or http://opensource.org/licenses/MIT)
* Apache License, Version 2.0 (docs/LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0)
at your option.

54
gui/README.md Normal file
View File

@@ -0,0 +1,54 @@
# SlimeVR UI
This is the GUI of SlimeVR, it uses the SolarXR protocol to communicate with the server and is completely isolated from the server logic.
This project is written in Typescript + React for the frontend and uses Tauri + Rust as a small backend. This makes the application more lightweight than electron.
## Compiling
### Prerequisites
- [Node.js](https://nodejs.org) 16 (We recommend the use of `nvm` instead of installing Node.js directly)
- Windows Webview
- SlimeVR server installed
- [Rust](https://rustup.rs)
```
npm install
```
Build for production
```
npm run tauri build
```
Launch in dev mode
```
npm run tauri dev
```
## Contributing
By contributing to this project you are placing all your code under MIT or less restricting licenses, and you certify that the code you have used is compatible with those licenses or is authored by you. If you're doing so on your work time, you certify that your employer is okay with this.
## License
All code in this repository is dual-licensed under either:
- MIT License ([LICENSE-MIT](docs/LICENSE-MIT))
- Apache License, Version 2.0 ([LICENSE-APACHE](docs/LICENSE-APACHE))
at your option. This means you can select the license you prefer!
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.
### Complying with the license
Please note that these licenses are very permissive, but if you wish to distribute software based on this code, you need to be aware of the following limits of these licenses:
- When distributing any software that uses or is based on SlimeVR, you have to provide to the end-user the original, unmodified `LICENSE-MIT` or `LICENSE-APACHE` file (or both) from SlimeVR. This includes the `Copyright (c) 2022 SlimeVR Contributors` part of the license. It is not sufficient to use a generic MIT/Apache License, it must be the original license file.
- This applies even if you distribute software without the source code. In this case, one way to provide it to the end-user is to have a menu in your application that lists all the open source licenses used, including SlimeVR's.
Please refer to the original license files if you are at any point uncertain what the exact the requirements are.

104
gui/config/env.js Normal file
View File

@@ -0,0 +1,104 @@
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
// Make sure that including paths.js after env.js will read .env variables.
delete require.cache[require.resolve('./paths')];
const NODE_ENV = process.env.NODE_ENV;
if (!NODE_ENV) {
throw new Error(
'The NODE_ENV environment variable is required but was not specified.'
);
}
// https://github.com/bkeepers/dotenv#what-other-env-files-can-i-use
const dotenvFiles = [
`${paths.dotenv}.${NODE_ENV}.local`,
// Don't include `.env.local` for `test` environment
// since normally you expect tests to produce the same
// results for everyone
NODE_ENV !== 'test' && `${paths.dotenv}.local`,
`${paths.dotenv}.${NODE_ENV}`,
paths.dotenv,
].filter(Boolean);
// Load environment variables from .env* files. Suppress warnings using silent
// if this file is missing. dotenv will never modify any environment variables
// that have already been set. Variable expansion is supported in .env files.
// https://github.com/motdotla/dotenv
// https://github.com/motdotla/dotenv-expand
dotenvFiles.forEach(dotenvFile => {
if (fs.existsSync(dotenvFile)) {
require('dotenv-expand')(
require('dotenv').config({
path: dotenvFile,
})
);
}
});
// We support resolving modules according to `NODE_PATH`.
// This lets you use absolute paths in imports inside large monorepos:
// https://github.com/facebook/create-react-app/issues/253.
// It works similar to `NODE_PATH` in Node itself:
// https://nodejs.org/api/modules.html#modules_loading_from_the_global_folders
// Note that unlike in Node, only *relative* paths from `NODE_PATH` are honored.
// Otherwise, we risk importing Node.js core modules into an app instead of webpack shims.
// https://github.com/facebook/create-react-app/issues/1023#issuecomment-265344421
// We also resolve them to make sure all tools using them work consistently.
const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
.split(path.delimiter)
.filter(folder => folder && !path.isAbsolute(folder))
.map(folder => path.resolve(appDirectory, folder))
.join(path.delimiter);
// Grab NODE_ENV and REACT_APP_* environment variables and prepare them to be
// injected into the application via DefinePlugin in webpack configuration.
const REACT_APP = /^REACT_APP_/i;
function getClientEnvironment(publicUrl) {
const raw = Object.keys(process.env)
.filter(key => REACT_APP.test(key))
.reduce(
(env, key) => {
env[key] = process.env[key];
return env;
},
{
// Useful for determining whether were running in production mode.
// Most importantly, it switches React into the correct mode.
NODE_ENV: process.env.NODE_ENV || 'development',
// Useful for resolving the correct path to static assets in `public`.
// For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// This should only be used as an escape hatch. Normally you would put
// images into the `src` and `import` them in code to get their paths.
PUBLIC_URL: publicUrl,
// We support configuring the sockjs pathname during development.
// These settings let a developer run multiple simultaneous projects.
// They are used as the connection `hostname`, `pathname` and `port`
// in webpackHotDevClient. They are used as the `sockHost`, `sockPath`
// and `sockPort` options in webpack-dev-server.
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
// Whether or not react-refresh is enabled.
// It is defined here so it is available in the webpackHotDevClient.
FAST_REFRESH: process.env.FAST_REFRESH !== 'false',
}
);
// Stringify all values so we can feed into webpack DefinePlugin
const stringified = {
'process.env': Object.keys(raw).reduce((env, key) => {
env[key] = JSON.stringify(raw[key]);
return env;
}, {}),
};
return { raw, stringified };
}
module.exports = getClientEnvironment;

View File

@@ -0,0 +1,66 @@
'use strict';
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');
const chalk = require('react-dev-utils/chalk');
const paths = require('./paths');
// Ensure the certificate and key provided are valid and if not
// throw an easy to debug error
function validateKeyAndCerts({ cert, key, keyFile, crtFile }) {
let encrypted;
try {
// publicEncrypt will throw an error with an invalid cert
encrypted = crypto.publicEncrypt(cert, Buffer.from('test'));
} catch (err) {
throw new Error(
`The certificate "${chalk.yellow(crtFile)}" is invalid.\n${err.message}`
);
}
try {
// privateDecrypt will throw an error with an invalid key
crypto.privateDecrypt(key, encrypted);
} catch (err) {
throw new Error(
`The certificate key "${chalk.yellow(keyFile)}" is invalid.\n${
err.message
}`
);
}
}
// Read file and throw an error if it doesn't exist
function readEnvFile(file, type) {
if (!fs.existsSync(file)) {
throw new Error(
`You specified ${chalk.cyan(
type
)} in your env, but the file "${chalk.yellow(file)}" can't be found.`
);
}
return fs.readFileSync(file);
}
// Get the https config
// Return cert files if provided in env, otherwise just true or false
function getHttpsConfig() {
const { SSL_CRT_FILE, SSL_KEY_FILE, HTTPS } = process.env;
const isHttps = HTTPS === 'true';
if (isHttps && SSL_CRT_FILE && SSL_KEY_FILE) {
const crtFile = path.resolve(paths.appPath, SSL_CRT_FILE);
const keyFile = path.resolve(paths.appPath, SSL_KEY_FILE);
const config = {
cert: readEnvFile(crtFile, 'SSL_CRT_FILE'),
key: readEnvFile(keyFile, 'SSL_KEY_FILE'),
};
validateKeyAndCerts({ ...config, keyFile, crtFile });
return config;
}
return isHttps;
}
module.exports = getHttpsConfig;

View File

@@ -0,0 +1,29 @@
'use strict';
const babelJest = require('babel-jest').default;
const hasJsxRuntime = (() => {
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
return false;
}
try {
require.resolve('react/jsx-runtime');
return true;
} catch (e) {
return false;
}
})();
module.exports = babelJest.createTransformer({
presets: [
[
require.resolve('babel-preset-react-app'),
{
runtime: hasJsxRuntime ? 'automatic' : 'classic',
},
],
],
babelrc: false,
configFile: false,
});

View File

@@ -0,0 +1,14 @@
'use strict';
// This is a custom Jest transformer turning style imports into empty objects.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process() {
return 'module.exports = {};';
},
getCacheKey() {
// The output is always the same.
return 'cssTransform';
},
};

View File

@@ -0,0 +1,40 @@
'use strict';
const path = require('path');
const camelcase = require('camelcase');
// This is a custom Jest transformer turning file imports into filenames.
// http://facebook.github.io/jest/docs/en/webpack.html
module.exports = {
process(src, filename) {
const assetFilename = JSON.stringify(path.basename(filename));
if (filename.match(/\.svg$/)) {
// Based on how SVGR generates a component name:
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
const pascalCaseFilename = camelcase(path.parse(filename).name, {
pascalCase: true,
});
const componentName = `Svg${pascalCaseFilename}`;
return `const React = require('react');
module.exports = {
__esModule: true,
default: ${assetFilename},
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
return {
$$typeof: Symbol.for('react.element'),
type: 'svg',
ref: ref,
key: null,
props: Object.assign({}, props, {
children: ${assetFilename}
})
};
}),
};`;
}
return `module.exports = ${assetFilename};`;
},
};

134
gui/config/modules.js Normal file
View File

@@ -0,0 +1,134 @@
'use strict';
const fs = require('fs');
const path = require('path');
const paths = require('./paths');
const chalk = require('react-dev-utils/chalk');
const resolve = require('resolve');
/**
* Get additional module paths based on the baseUrl of a compilerOptions object.
*
* @param {Object} options
*/
function getAdditionalModulePaths(options = {}) {
const baseUrl = options.baseUrl;
if (!baseUrl) {
return '';
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
// We don't need to do anything if `baseUrl` is set to `node_modules`. This is
// the default behavior.
if (path.relative(paths.appNodeModules, baseUrlResolved) === '') {
return null;
}
// Allow the user set the `baseUrl` to `appSrc`.
if (path.relative(paths.appSrc, baseUrlResolved) === '') {
return [paths.appSrc];
}
// If the path is equal to the root directory we ignore it here.
// We don't want to allow importing from the root directly as source files are
// not transpiled outside of `src`. We do allow importing them with the
// absolute path (e.g. `src/Components/Button.js`) but we set that up with
// an alias.
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return null;
}
// Otherwise, throw an error.
throw new Error(
chalk.red.bold(
"Your project's `baseUrl` can only be set to `src` or `node_modules`." +
' Create React App does not support other values at this time.'
)
);
}
/**
* Get webpack aliases based on the baseUrl of a compilerOptions object.
*
* @param {*} options
*/
function getWebpackAliases(options = {}) {
const baseUrl = options.baseUrl;
if (!baseUrl) {
return {};
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return {
src: paths.appSrc,
};
}
}
/**
* Get jest aliases based on the baseUrl of a compilerOptions object.
*
* @param {*} options
*/
function getJestAliases(options = {}) {
const baseUrl = options.baseUrl;
if (!baseUrl) {
return {};
}
const baseUrlResolved = path.resolve(paths.appPath, baseUrl);
if (path.relative(paths.appPath, baseUrlResolved) === '') {
return {
'^src/(.*)$': '<rootDir>/src/$1',
};
}
}
function getModules() {
// Check if TypeScript is setup
const hasTsConfig = fs.existsSync(paths.appTsConfig);
const hasJsConfig = fs.existsSync(paths.appJsConfig);
if (hasTsConfig && hasJsConfig) {
throw new Error(
'You have both a tsconfig.json and a jsconfig.json. If you are using TypeScript please remove your jsconfig.json file.'
);
}
let config;
// If there's a tsconfig.json we assume it's a
// TypeScript project and set up the config
// based on tsconfig.json
if (hasTsConfig) {
const ts = require(resolve.sync('typescript', {
basedir: paths.appNodeModules,
}));
config = ts.readConfigFile(paths.appTsConfig, ts.sys.readFile).config;
// Otherwise we'll check if there is jsconfig.json
// for non TS projects.
} else if (hasJsConfig) {
config = require(paths.appJsConfig);
}
config = config || {};
const options = config.compilerOptions || {};
const additionalModulePaths = getAdditionalModulePaths(options);
return {
additionalModulePaths: additionalModulePaths,
webpackAliases: getWebpackAliases(options),
jestAliases: getJestAliases(options),
hasTsConfig,
};
}
module.exports = getModules();

77
gui/config/paths.js Normal file
View File

@@ -0,0 +1,77 @@
'use strict';
const path = require('path');
const fs = require('fs');
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebook/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);
// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
const publicUrlOrPath = getPublicUrlOrPath(
process.env.NODE_ENV === 'development',
require(resolveApp('package.json')).homepage,
process.env.PUBLIC_URL
);
const buildPath = process.env.BUILD_PATH || 'build';
const moduleFileExtensions = [
'web.mjs',
'mjs',
'web.js',
'js',
'web.ts',
'ts',
'web.tsx',
'tsx',
'json',
'web.jsx',
'jsx',
];
// Resolve file paths in the same order as webpack
const resolveModule = (resolveFn, filePath) => {
const extension = moduleFileExtensions.find(extension =>
fs.existsSync(resolveFn(`${filePath}.${extension}`))
);
if (extension) {
return resolveFn(`${filePath}.${extension}`);
}
return resolveFn(`${filePath}.js`);
};
// config after eject: we're in ./config/
module.exports = {
dotenv: resolveApp('.env'),
appPath: resolveApp('.'),
appBuild: resolveApp(buildPath),
appPublic: resolveApp('public'),
appHtml: resolveApp('public/index.html'),
appIndexJs: resolveModule(resolveApp, 'src/index'),
appPackageJson: resolveApp('package.json'),
appSrc: resolveApp('src'),
appTsConfig: resolveApp('tsconfig.json'),
appJsConfig: resolveApp('jsconfig.json'),
yarnLockFile: resolveApp('yarn.lock'),
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
proxySetup: resolveApp('src/setupProxy.js'),
appNodeModules: resolveApp('node_modules'),
appWebpackCache: resolveApp('node_modules/.cache'),
appTsBuildInfoFile: resolveApp('node_modules/.cache/tsconfig.tsbuildinfo'),
swSrc: resolveModule(resolveApp, 'src/service-worker'),
publicUrlOrPath,
};
module.exports.moduleFileExtensions = moduleFileExtensions;

View File

@@ -0,0 +1,753 @@
'use strict';
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const resolve = require('resolve');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const ESLintPlugin = require('eslint-webpack-plugin');
const paths = require('./paths');
const modules = require('./modules');
const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin =
process.env.TSC_COMPILE_ON_ERROR === 'true'
? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin')
: require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash');
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime');
const reactRefreshWebpackPluginRuntimeEntry = require.resolve(
'@pmmmwh/react-refresh-webpack-plugin'
);
const babelRuntimeEntry = require.resolve('babel-preset-react-app');
const babelRuntimeEntryHelpers = require.resolve(
'@babel/runtime/helpers/esm/assertThisInitialized',
{ paths: [babelRuntimeEntry] }
);
const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', {
paths: [babelRuntimeEntry],
});
// Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';
const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true';
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true';
const imageInlineSizeLimit = parseInt(
process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
);
// Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig);
// Check if Tailwind config exists
const useTailwind = fs.existsSync(
path.join(paths.appPath, 'tailwind.config.js')
);
// Get the path to the uncompiled service worker (if it exists).
const swSrc = paths.swSrc;
// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const hasJsxRuntime = (() => {
if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {
return false;
}
try {
require.resolve('react/jsx-runtime');
return true;
} catch (e) {
return false;
}
})();
// This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function (webpackEnv) {
const isEnvDevelopment = webpackEnv === 'development';
const isEnvProduction = webpackEnv === 'production';
// Variable used for enabling profiling in Production
// passed into alias object. Uses a flag if passed into the build command
const isEnvProductionProfile =
isEnvProduction && process.argv.includes('--profile');
// We will provide `paths.publicUrlOrPath` to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
// Get environment variables to inject into our app.
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
const shouldUseReactRefresh = env.raw.FAST_REFRESH;
// common function to get style loaders
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
isEnvDevelopment && require.resolve('style-loader'),
isEnvProduction && {
loader: MiniCssExtractPlugin.loader,
// css is located in `static/css`, use '../../' to locate index.html folder
// in production `paths.publicUrlOrPath` can be a relative path
options: paths.publicUrlOrPath.startsWith('.')
? { publicPath: '../../' }
: {},
},
{
loader: require.resolve('css-loader'),
options: cssOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: {
postcssOptions: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
config: false,
plugins: !useTailwind
? [
'postcss-flexbugs-fixes',
[
'postcss-preset-env',
{
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
},
],
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
'postcss-normalize',
]
: [
'tailwindcss',
'postcss-flexbugs-fixes',
[
'postcss-preset-env',
{
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
},
],
],
},
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
},
},
].filter(Boolean);
if (preProcessor) {
loaders.push(
{
loader: require.resolve('resolve-url-loader'),
options: {
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
root: paths.appSrc,
},
},
{
loader: require.resolve(preProcessor),
options: {
sourceMap: true,
},
}
);
}
return loaders;
};
return {
target: ['browserslist'],
mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',
// Stop compilation early in production
bail: isEnvProduction,
devtool: isEnvProduction
? shouldUseSourceMap
? 'source-map'
: false
: isEnvDevelopment && 'cheap-module-source-map',
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
entry: paths.appIndexJs,
output: {
// The build folder.
path: paths.appBuild,
// Add /* filename */ comments to generated require()s in the output.
pathinfo: isEnvDevelopment,
// There will be one main bundle, and one file per asynchronous chunk.
// In development, it does not produce real files.
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[name].[hash][ext]',
// webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: paths.publicUrlOrPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: isEnvProduction
? info =>
path
.relative(paths.appSrc, info.absoluteResourcePath)
.replace(/\\/g, '/')
: isEnvDevelopment &&
(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),
},
cache: {
type: 'filesystem',
version: createEnvironmentHash(env.raw),
cacheDirectory: paths.appWebpackCache,
store: 'pack',
buildDependencies: {
defaultWebpack: ['webpack/lib/'],
config: [__filename],
tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>
fs.existsSync(f)
),
},
},
infrastructureLogging: {
level: 'none',
},
optimization: {
minimize: isEnvProduction,
minimizer: [
// This is only used in production mode
new TerserPlugin({
terserOptions: {
parse: {
// We want terser to parse ecma 8 code. However, we don't want it
// to apply any minification steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
// Disabled because of an issue with Terser breaking valid code:
// https://github.com/facebook/create-react-app/issues/5250
// Pending further investigation:
// https://github.com/terser-js/terser/issues/120
inline: 2,
},
mangle: {
safari10: true,
},
// Added for profiling in devtools
keep_classnames: isEnvProductionProfile,
keep_fnames: isEnvProductionProfile,
output: {
ecma: 5,
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
ascii_only: true,
},
},
}),
// This is only used in production mode
new CssMinimizerPlugin(),
],
},
resolve: {
// This allows you to set a fallback for where webpack should look for modules.
// We placed these paths second because we want `node_modules` to "win"
// if there are any conflicts. This matches Node resolution mechanism.
// https://github.com/facebook/create-react-app/issues/253
modules: ['node_modules', paths.appNodeModules].concat(
modules.additionalModulePaths || []
),
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebook/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: paths.moduleFileExtensions
.map(ext => `.${ext}`)
.filter(ext => useTypeScript || !ext.includes('ts')),
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
// Allows for better profiling with ReactDevTools
...(isEnvProductionProfile && {
'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling',
}),
...(modules.webpackAliases || {}),
},
plugins: [
// Prevents users from importing files from outside of src/ (or node_modules/).
// This often causes confusion because we only process files within src/ with babel.
// To fix this, we prevent you from importing files out of src/ -- if you'd like to,
// please link the files into your node_modules/ and let module-resolution kick in.
// Make sure your source files are compiled, as they will not be processed in any way.
new ModuleScopePlugin(paths.appSrc, [
paths.appPackageJson,
reactRefreshRuntimeEntry,
reactRefreshWebpackPluginRuntimeEntry,
babelRuntimeEntry,
babelRuntimeEntryHelpers,
babelRuntimeRegenerator,
]),
],
},
module: {
strictExportPresence: true,
rules: [
// Handle node_modules packages that contain sourcemaps
shouldUseSourceMap && {
enforce: 'pre',
exclude: /@babel(?:\/|\\{1,2})runtime/,
test: /\.(js|mjs|jsx|ts|tsx|css)$/,
loader: require.resolve('source-map-loader'),
},
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
// back to the "file" loader at the end of the loader list.
oneOf: [
// TODO: Merge this config once `image/avif` is in the mime-db
// https://github.com/jshttp/mime-db
{
test: [/\.avif$/],
type: 'asset',
mimetype: 'image/avif',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit,
},
},
},
// "url" loader works like "file" loader except that it embeds assets
// smaller than specified limit in bytes as data URLs to avoid requests.
// A missing `test` is equivalent to a match.
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit,
},
},
},
{
test: /\.svg$/,
use: [
{
loader: require.resolve('@svgr/webpack'),
options: {
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
},
},
{
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash].[ext]',
},
},
],
issuer: {
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
},
},
// Process application JS with Babel.
// The preset includes JSX, Flow, TypeScript, and some ESnext features.
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
presets: [
[
require.resolve('babel-preset-react-app'),
{
runtime: hasJsxRuntime ? 'automatic' : 'classic',
},
],
],
plugins: [
isEnvDevelopment &&
shouldUseReactRefresh &&
require.resolve('react-refresh/babel'),
].filter(Boolean),
// This is a feature of `babel-loader` for webpack (not Babel itself).
// It enables caching results in ./node_modules/.cache/babel-loader/
// directory for faster rebuilds.
cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled
cacheCompression: false,
compact: isEnvProduction,
},
},
// Process any JS outside of the app with Babel.
// Unlike the application JS, we only compile the standard ES features.
{
test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve('babel-preset-react-app/dependencies'),
{ helpers: true },
],
],
cacheDirectory: true,
// See #6846 for context on why cacheCompression is disabled
cacheCompression: false,
// Babel sourcemaps are needed for debugging into node_modules
// code. Without the options below, debuggers like VSCode
// show incorrect code and set breakpoints on the wrong lines.
sourceMaps: shouldUseSourceMap,
inputSourceMap: shouldUseSourceMap,
},
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use MiniCSSExtractPlugin to extract that CSS
// to a file, but in development "style" loader enables hot editing
// of CSS.
// By default we support CSS Modules with the extension .module.css
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'icss',
},
}),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
},
}),
},
// Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'icss',
},
},
'sass-loader'
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
{
test: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
},
},
'sass-loader'
),
},
// "file" loader makes sure those assets get served by WebpackDevServer.
// When you `import` an asset, you get its (virtual) filename.
// In production, they would get copied to the `build` folder.
// This loader doesn't use a "test" so it will catch all modules
// that fall through the other loaders.
{
// Exclude `js` files to keep "css" loader working as it injects
// its runtime that would otherwise be processed through "file" loader.
// Also exclude `html` and `json` extensions so they get processed
// by webpacks internal loaders.
exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
type: 'asset/resource',
},
// ** STOP ** Are you adding a new loader?
// Make sure to add the new loader(s) before the "file" loader.
],
},
].filter(Boolean),
},
plugins: [
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
),
// Inlines the webpack runtime script. This script is too small to warrant
// a network request.
// https://github.com/facebook/create-react-app/issues/5358
isEnvProduction &&
shouldInlineRuntimeChunk &&
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
// Makes some environment variables available in index.html.
// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
// It will be an empty string unless you specify "homepage"
// in `package.json`, in which case it will be the pathname of that URL.
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
// This gives some necessary context to module not found errors, such as
// the requesting resource.
new ModuleNotFoundPlugin(paths.appPath),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.
// It is absolutely essential that NODE_ENV is set to production
// during a production build.
// Otherwise React will be compiled in the very slow development mode.
new webpack.DefinePlugin(env.stringified),
// Experimental hot reloading for React .
// https://github.com/facebook/react/tree/main/packages/react-refresh
isEnvDevelopment &&
shouldUseReactRefresh &&
new ReactRefreshWebpackPlugin({
overlay: false,
}),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebook/create-react-app/issues/240
isEnvDevelopment && new CaseSensitivePathsPlugin(),
isEnvProduction &&
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
}),
// Generate an asset manifest file with the following content:
// - "files" key: Mapping of all asset filenames to their corresponding
// output file so that tools can pick it up without having to parse
// `index.html`
// - "entrypoints" key: Array of files which are included in `index.html`,
// can be used to reconstruct the HTML if necessary
new WebpackManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter(
fileName => !fileName.endsWith('.map')
);
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
}),
// Moment.js is an extremely popular library that bundles large locale files
// by default due to how webpack interprets its code. This is a practical
// solution that requires the user to opt into importing specific locales.
// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack
// You can remove this if you don't use Moment.js:
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
// Generate a service worker script that will precache, and keep up to date,
// the HTML & assets that are part of the webpack build.
isEnvProduction &&
fs.existsSync(swSrc) &&
new WorkboxWebpackPlugin.InjectManifest({
swSrc,
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
// Bump up the default maximum size (2mb) that's precached,
// to make lazy-loading failure scenarios less likely.
// See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
}),
// TypeScript type checking
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
async: isEnvDevelopment,
typescript: {
typescriptPath: resolve.sync('typescript', {
basedir: paths.appNodeModules,
}),
configOverwrite: {
compilerOptions: {
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
skipLibCheck: true,
inlineSourceMap: false,
declarationMap: false,
noEmit: true,
incremental: true,
tsBuildInfoFile: paths.appTsBuildInfoFile,
},
},
context: paths.appPath,
diagnosticOptions: {
syntactic: true,
},
mode: 'write-references',
// profile: true,
},
issue: {
// This one is specifically to match during CI tests,
// as micromatch doesn't match
// '../cra-template-typescript/template/src/App.tsx'
// otherwise.
include: [
{ file: '../**/src/**/*.{ts,tsx}' },
{ file: '**/src/**/*.{ts,tsx}' },
],
exclude: [
{ file: '**/src/**/__tests__/**' },
{ file: '**/src/**/?(*.){spec|test}.*' },
{ file: '**/src/setupProxy.*' },
{ file: '**/src/setupTests.*' },
],
},
logger: {
infrastructure: 'silent',
},
}),
!disableESLintPlugin &&
new ESLintPlugin({
// Plugin options
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
context: paths.appSrc,
cache: true,
cacheLocation: path.resolve(
paths.appNodeModules,
'.cache/.eslintcache'
),
// ESLint class options
cwd: paths.appPath,
resolvePluginsRelativeTo: __dirname,
baseConfig: {
extends: [require.resolve('eslint-config-react-app/base')],
rules: {
...(!hasJsxRuntime && {
'react/react-in-jsx-scope': 'error',
}),
},
},
}),
].filter(Boolean),
// Turn off performance processing because we utilize
// our own hints via the FileSizeReporter
performance: false,
};
};

View File

@@ -0,0 +1,9 @@
'use strict';
const { createHash } = require('crypto');
module.exports = env => {
const hash = createHash('md5');
hash.update(JSON.stringify(env));
return hash.digest('hex');
};

View File

@@ -0,0 +1,127 @@
'use strict';
const fs = require('fs');
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
const paths = require('./paths');
const getHttpsConfig = require('./getHttpsConfig');
const host = process.env.HOST || '0.0.0.0';
const sockHost = process.env.WDS_SOCKET_HOST;
const sockPath = process.env.WDS_SOCKET_PATH; // default: '/ws'
const sockPort = process.env.WDS_SOCKET_PORT;
module.exports = function (proxy, allowedHost) {
const disableFirewall =
!proxy || process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true';
return {
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
// websites from potentially accessing local content through DNS rebinding:
// https://github.com/webpack/webpack-dev-server/issues/887
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
// However, it made several existing use cases such as development in cloud
// environment or subdomains in development significantly more complicated:
// https://github.com/facebook/create-react-app/issues/2271
// https://github.com/facebook/create-react-app/issues/2233
// While we're investigating better solutions, for now we will take a
// compromise. Since our WDS configuration only serves files in the `public`
// folder we won't consider accessing them a vulnerability. However, if you
// use the `proxy` feature, it gets more dangerous because it can expose
// remote code execution vulnerabilities in backends like Django and Rails.
// So we will disable the host check normally, but enable it if you have
// specified the `proxy` setting. Finally, we let you override it if you
// really know what you're doing with a special environment variable.
// Note: ["localhost", ".localhost"] will support subdomains - but we might
// want to allow setting the allowedHosts manually for more complex setups
allowedHosts: disableFirewall ? 'all' : [allowedHost],
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': '*',
'Access-Control-Allow-Headers': '*',
},
// Enable gzip compression of generated files.
compress: true,
static: {
// By default WebpackDevServer serves physical files from current directory
// in addition to all the virtual build products that it serves from memory.
// This is confusing because those files wont automatically be available in
// production build folder unless we copy them. However, copying the whole
// project directory is dangerous because we may expose sensitive files.
// Instead, we establish a convention that only files in `public` directory
// get served. Our build script will copy `public` into the `build` folder.
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
// Note that we only recommend to use `public` folder as an escape hatch
// for files like `favicon.ico`, `manifest.json`, and libraries that are
// for some reason broken when imported through webpack. If you just want to
// use an image, put it in `src` and `import` it from JavaScript instead.
directory: paths.appPublic,
publicPath: [paths.publicUrlOrPath],
// By default files from `contentBase` will not trigger a page reload.
watch: {
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebook/create-react-app/issues/293
// src/node_modules is not ignored to support absolute imports
// https://github.com/facebook/create-react-app/issues/1065
ignored: ignoredFiles(paths.appSrc),
},
},
client: {
webSocketURL: {
// Enable custom sockjs pathname for websocket connection to hot reloading server.
// Enable custom sockjs hostname, pathname and port for websocket connection
// to hot reloading server.
hostname: sockHost,
pathname: sockPath,
port: sockPort,
},
overlay: {
errors: true,
warnings: false,
},
},
devMiddleware: {
// It is important to tell WebpackDevServer to use the same "publicPath" path as
// we specified in the webpack config. When homepage is '.', default to serving
// from the root.
// remove last slash so user can land on `/test` instead of `/test/`
publicPath: paths.publicUrlOrPath.slice(0, -1),
},
https: getHttpsConfig(),
host,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
index: paths.publicUrlOrPath,
},
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
proxy,
onBeforeSetupMiddleware(devServer) {
// Keep `evalSourceMapMiddleware`
// middlewares before `redirectServedPath` otherwise will not have any effect
// This lets us fetch source contents from webpack for the error overlay
devServer.app.use(evalSourceMapMiddleware(devServer));
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(devServer.app);
}
},
onAfterSetupMiddleware(devServer) {
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
devServer.app.use(redirectServedPath(paths.publicUrlOrPath));
// This service worker file is effectively a 'no-op' that will reset any
// previous service worker registered for the same host:port combination.
// We do this in development to avoid hitting the production cache if
// it used the same host and port.
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
devServer.app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
},
};
};

201
gui/docs/LICENSE-APACHE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2022 SlimeVR Contributors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

21
gui/docs/LICENSE-MIT Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 SlimeVR Contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

26539
gui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

185
gui/package.json Normal file
View File

@@ -0,0 +1,185 @@
{
"name": "slimevr-ui",
"version": "0.4.0",
"private": true,
"dependencies": {
"@babel/core": "^7.16.0",
"@fontsource/poppins": "^4.5.8",
"@pmmmwh/react-refresh-webpack-plugin": "^0.5.3",
"@svgr/webpack": "^6.2.1",
"@tauri-apps/api": "^1.0.2",
"add": "^2.0.6",
"babel-jest": "^27.4.2",
"babel-loader": "^8.2.3",
"babel-plugin-named-asset-import": "^0.3.8",
"babel-preset-react-app": "^10.0.1",
"bfj": "^7.0.2",
"browserslist": "^4.18.1",
"camelcase": "^6.2.1",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
"classnames": "^2.3.1",
"css-loader": "^6.5.1",
"css-minimizer-webpack-plugin": "^3.2.0",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"eslint-config-react-app": "^7.0.0",
"eslint-webpack-plugin": "^3.1.1",
"file-loader": "^6.2.0",
"flatbuffers": "^22.10.26",
"fs-extra": "^10.0.0",
"html-webpack-plugin": "^5.5.0",
"identity-obj-proxy": "^3.0.0",
"ip-num": "^1.4.1",
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0",
"math3d": "^0.2.2",
"mini-css-extract-plugin": "^2.4.5",
"postcss": "^8.4.4",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-loader": "^6.2.1",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^7.0.1",
"prompts": "^2.4.2",
"quaternion": "^1.3.0",
"react": "^18.0.0",
"react-app-polyfill": "^3.0.0",
"react-dev-utils": "^12.0.0",
"react-dom": "^18.0.0",
"react-hook-form": "^7.29.0",
"react-modal": "3.15.1",
"react-refresh": "^0.11.0",
"react-router-dom": "^6.2.2",
"resolve": "^1.20.0",
"resolve-url-loader": "^4.0.0",
"sass-loader": "^12.3.0",
"semver": "^7.3.5",
"solarxr-protocol": "file:../solarxr-protocol",
"source-map-loader": "^3.0.0",
"style-loader": "^3.3.1",
"tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5",
"typescript": "^4.6.3",
"web-vitals": "^2.1.4",
"webpack": "^5.64.4",
"webpack-dev-server": "^4.6.0",
"webpack-manifest-plugin": "^4.0.2",
"workbox-webpack-plugin": "^6.4.1"
},
"scripts": {
"start": "cross-env BROWSER=none node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js",
"dev": "tauri dev",
"tauri": "tauri",
"lint": "eslint src/**/*.{js,jsx,ts,tsx,json}",
"lint:fix": "eslint --fix src/**/*.{js,jsx,ts,tsx,json}",
"format": "prettier --write src/**/*.{js,jsx,ts,tsx,css,md,json} --config ./.prettierrc"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@tailwindcss/forms": "^0.5.0",
"@tauri-apps/cli": "^1.0.2",
"@testing-library/jest-dom": "^5.16.3",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.4.1",
"@types/math3d": "^0.2.3",
"@types/node": "^16.11.26",
"@types/react": "18.0.25",
"@types/react-dom": "^18.0.5",
"@types/react-modal": "3.13.1",
"@typescript-eslint/eslint-plugin": "^5.43.0",
"@typescript-eslint/parser": "^5.43.0",
"autoprefixer": "^10.4.4",
"cross-env": "^7.0.3",
"eslint": "^8.18.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^8.5.0",
"eslint-import-resolver-typescript": "^3.1.1",
"eslint-plugin-import": "^2.26.0",
"eslint-plugin-jsx-a11y": "^6.6.0",
"eslint-plugin-prettier": "^4.1.0",
"eslint-plugin-react": "^7.30.1",
"eslint-plugin-react-hooks": "^4.6.0",
"husky": "^8.0.0",
"node-polyfill-webpack-plugin": "^1.1.4",
"postcss": "^8.4.12",
"prettier": "^2.7.1",
"pretty-quick": "^3.1.3",
"tailwindcss": "^3.0.23"
},
"jest": {
"roots": [
"<rootDir>/src"
],
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"setupFiles": [
"react-app-polyfill/jsdom"
],
"setupFilesAfterEnv": [
"<rootDir>/src/setupTests.ts"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/*.{spec,test}.{js,jsx,ts,tsx}"
],
"testEnvironment": "jsdom",
"transform": {
"^.+\\.(js|jsx|mjs|cjs|ts|tsx)$": "<rootDir>/config/jest/babelTransform.js",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|mjs|cjs|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs|cjs|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"modulePaths": [],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"watchPlugins": [
"jest-watch-typeahead/filename",
"jest-watch-typeahead/testname"
],
"resetMocks": true
},
"babel": {
"presets": [
"react-app"
]
}
}

6
gui/postcss.config.js Normal file
View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
gui/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 948 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 570 KiB

43
gui/public/index.html Normal file
View File

@@ -0,0 +1,43 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<meta
name="description"
content="Web site created using create-react-app"
/>
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<!--
manifest.json provides metadata used when your web app is installed on a
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>React App</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

BIN
gui/public/logo192.png Normal file

Binary file not shown.

BIN
gui/public/logo512.png Normal file

Binary file not shown.

25
gui/public/manifest.json Normal file
View File

@@ -0,0 +1,25 @@
{
"short_name": "React App",
"name": "Create React App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}

3
gui/public/robots.txt Normal file
View File

@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:

2
gui/rust-toolchain.toml Normal file
View File

@@ -0,0 +1,2 @@
[toolchain]
channel = "stable"

0
gui/rustfmt.toml Normal file
View File

217
gui/scripts/build.js Normal file
View File

@@ -0,0 +1,217 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const path = require('path');
const chalk = require('react-dev-utils/chalk');
const fs = require('fs-extra');
const bfj = require('bfj');
const webpack = require('webpack');
const configFactory = require('../config/webpack.config');
const paths = require('../config/paths');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const formatWebpackMessages = require('react-dev-utils/formatWebpackMessages');
const printHostingInstructions = require('react-dev-utils/printHostingInstructions');
const FileSizeReporter = require('react-dev-utils/FileSizeReporter');
const printBuildError = require('react-dev-utils/printBuildError');
const measureFileSizesBeforeBuild =
FileSizeReporter.measureFileSizesBeforeBuild;
const printFileSizesAfterBuild = FileSizeReporter.printFileSizesAfterBuild;
const useYarn = fs.existsSync(paths.yarnLockFile);
// These sizes are pretty large. We'll warn for bundles exceeding them.
const WARN_AFTER_BUNDLE_GZIP_SIZE = 512 * 1024;
const WARN_AFTER_CHUNK_GZIP_SIZE = 1024 * 1024;
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
const argv = process.argv.slice(2);
const writeStatsJson = argv.indexOf('--stats') !== -1;
// Generate configuration
const config = configFactory('production');
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// First, read the current file sizes in build directory.
// This lets us display how much they changed later.
return measureFileSizesBeforeBuild(paths.appBuild);
})
.then(previousFileSizes => {
// Remove all content but keep the directory so that
// if you're in it, you don't end up in Trash
fs.emptyDirSync(paths.appBuild);
// Merge with the public folder
copyPublicFolder();
// Start the webpack build
return build(previousFileSizes);
})
.then(
({ stats, previousFileSizes, warnings }) => {
if (warnings.length) {
console.log(chalk.yellow('Compiled with warnings.\n'));
console.log(warnings.join('\n\n'));
console.log(
'\nSearch for the ' +
chalk.underline(chalk.yellow('keywords')) +
' to learn more about each warning.'
);
console.log(
'To ignore, add ' +
chalk.cyan('// eslint-disable-next-line') +
' to the line before.\n'
);
} else {
console.log(chalk.green('Compiled successfully.\n'));
}
console.log('File sizes after gzip:\n');
printFileSizesAfterBuild(
stats,
previousFileSizes,
paths.appBuild,
WARN_AFTER_BUNDLE_GZIP_SIZE,
WARN_AFTER_CHUNK_GZIP_SIZE
);
console.log();
const appPackage = require(paths.appPackageJson);
const publicUrl = paths.publicUrlOrPath;
const publicPath = config.output.publicPath;
const buildFolder = path.relative(process.cwd(), paths.appBuild);
printHostingInstructions(
appPackage,
publicUrl,
publicPath,
buildFolder,
useYarn
);
},
err => {
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
if (tscCompileOnError) {
console.log(
chalk.yellow(
'Compiled with the following type errors (you may want to check these before deploying your app):\n'
)
);
printBuildError(err);
} else {
console.log(chalk.red('Failed to compile.\n'));
printBuildError(err);
process.exit(1);
}
}
)
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
// Create the production build and print the deployment instructions.
function build(previousFileSizes) {
console.log('Creating an optimized production build...');
const compiler = webpack(config);
return new Promise((resolve, reject) => {
compiler.run((err, stats) => {
let messages;
if (err) {
if (!err.message) {
return reject(err);
}
let errMessage = err.message;
// Add additional information for postcss errors
if (Object.prototype.hasOwnProperty.call(err, 'postcssNode')) {
errMessage +=
'\nCompileError: Begins at CSS selector ' +
err['postcssNode'].selector;
}
messages = formatWebpackMessages({
errors: [errMessage],
warnings: [],
});
} else {
messages = formatWebpackMessages(
stats.toJson({ all: false, warnings: true, errors: true })
);
}
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
return reject(new Error(messages.errors.join('\n\n')));
}
if (
process.env.CI &&
(typeof process.env.CI !== 'string' ||
process.env.CI.toLowerCase() !== 'false') &&
messages.warnings.length
) {
// Ignore sourcemap warnings in CI builds. See #8227 for more info.
const filteredWarnings = messages.warnings.filter(
w => !/Failed to parse source map/.test(w)
);
if (filteredWarnings.length) {
console.log(
chalk.yellow(
'\nTreating warnings as errors because process.env.CI = true.\n' +
'Most CI servers set it automatically.\n'
)
);
return reject(new Error(filteredWarnings.join('\n\n')));
}
}
const resolveArgs = {
stats,
previousFileSizes,
warnings: messages.warnings,
};
if (writeStatsJson) {
return bfj
.write(paths.appBuild + '/bundle-stats.json', stats.toJson())
.then(() => resolve(resolveArgs))
.catch(error => reject(new Error(error)));
}
return resolve(resolveArgs);
});
});
}
function copyPublicFolder() {
fs.copySync(paths.appPublic, paths.appBuild, {
dereference: true,
filter: file => file !== paths.appHtml,
});
}

154
gui/scripts/start.js Normal file
View File

@@ -0,0 +1,154 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const fs = require('fs');
const chalk = require('react-dev-utils/chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
choosePort,
createCompiler,
prepareProxy,
prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const semver = require('semver');
const paths = require('../config/paths');
const configFactory = require('../config/webpack.config');
const createDevServerConfig = require('../config/webpackDevServer.config');
const getClientEnvironment = require('../config/env');
const react = require(require.resolve('react', { paths: [paths.appPath] }));
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;
// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
process.exit(1);
}
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
if (process.env.HOST) {
console.log(
chalk.cyan(
`Attempting to bind to HOST environment variable: ${chalk.yellow(
chalk.bold(process.env.HOST)
)}`
)
);
console.log(
`If this was unintentional, check that you haven't mistakenly set it in your shell.`
);
console.log(
`Learn more here: ${chalk.yellow('https://cra.link/advanced-config')}`
);
console.log();
}
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// We attempt to use the default port but if it is busy, we offer the user to
// run on a different port. `choosePort()` Promise resolves to the next free port.
return choosePort(HOST, DEFAULT_PORT);
})
.then(port => {
if (port == null) {
// We have not found a port.
return;
}
const config = configFactory('development');
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const useTypeScript = fs.existsSync(paths.appTsConfig);
const urls = prepareUrls(
protocol,
HOST,
port,
paths.publicUrlOrPath.slice(0, -1)
);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler({
appName,
config,
urls,
useYarn,
useTypeScript,
webpack,
});
// Load proxy config
const proxySetting = require(paths.appPackageJson).proxy;
const proxyConfig = prepareProxy(
proxySetting,
paths.appPublic,
paths.publicUrlOrPath
);
// Serve webpack assets generated by the compiler over a web server.
const serverConfig = {
...createDevServerConfig(proxyConfig, urls.lanUrlForConfig),
host: HOST,
port,
};
const devServer = new WebpackDevServer(serverConfig, compiler);
// Launch WebpackDevServer.
devServer.startCallback(() => {
if (isInteractive) {
clearConsole();
}
if (env.raw.FAST_REFRESH && semver.lt(react.version, '16.10.0')) {
console.log(
chalk.yellow(
`Fast Refresh requires React 16.10 or higher. You are using React ${react.version}.`
)
);
}
console.log(chalk.cyan('Starting the development server...\n'));
openBrowser(urls.localUrlForBrowser);
});
['SIGINT', 'SIGTERM'].forEach(function (sig) {
process.on(sig, function () {
devServer.close();
process.exit();
});
});
if (process.env.CI !== 'true') {
// Gracefully exit when stdin ends
process.stdin.on('end', function () {
devServer.close();
process.exit();
});
}
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});

52
gui/scripts/test.js Normal file
View File

@@ -0,0 +1,52 @@
'use strict';
// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'test';
process.env.NODE_ENV = 'test';
process.env.PUBLIC_URL = '';
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
const jest = require('jest');
const execSync = require('child_process').execSync;
let argv = process.argv.slice(2);
function isInGitRepository() {
try {
execSync('git rev-parse --is-inside-work-tree', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
function isInMercurialRepository() {
try {
execSync('hg --cwd . root', { stdio: 'ignore' });
return true;
} catch (e) {
return false;
}
}
// Watch unless on CI or explicitly running all tests
if (
!process.env.CI &&
argv.indexOf('--watchAll') === -1 &&
argv.indexOf('--watchAll=false') === -1
) {
// https://github.com/facebook/create-react-app/issues/5210
const hasSourceControl = isInGitRepository() || isInMercurialRepository();
argv.push(hasSourceControl ? '--watch' : '--watchAll');
}
jest.run(argv);

4
gui/src-tauri/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Generated by Cargo
# will have compiled files and executables
/target/
WixTools

4067
gui/src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

34
gui/src-tauri/Cargo.toml Normal file
View File

@@ -0,0 +1,34 @@
[package]
name = "slimevr_ui"
version = "0.1.0"
description = "SlimeVR GUI Application"
license = "MIT OR Apache-2.0"
repository = ""
default-run = "slimevr_ui"
edition = "2021"
rust-version = "1.59"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
# by default Tauri runs in production mode
# when `tauri dev` runs it is executed with `cargo run --no-default-features` if `devPath` is an URL
default = ["custom-protocol"]
# this feature is used used for production builds where `devPath` points to the filesystem
# DO NOT remove this
custom-protocol = ["tauri/custom-protocol"]
[build-dependencies]
tauri-build = { version = "1", features = [] }
[dependencies]
serde_json = "1"
serde = { version = "1", features = ["derive"] }
tauri = { version = "1.1.1", features = ["cli", "devtools", "fs-all", "path-all", "shell-execute", "window-close", "window-maximize", "window-minimize", "window-set-resizable", "window-set-title", "window-start-dragging", "window-unmaximize", "window-unminimize"] }
pretty_env_logger = "0.4"
log = "0.4"
clap-verbosity-flag = "1"
tauri-plugin-window-state = "0.1.0"
[target.'cfg(windows)'.dependencies]
win32job = "1"

3
gui/src-tauri/build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

11
gui/src-tauri/run.bat.old Normal file
View File

@@ -0,0 +1,11 @@
@echo off
setlocal enableextensions
echo "TEST"
cd /d "C:\Program Files (x86)\SlimeVR Server"
jre\bin\java.exe -Xmx512M -jar slimevr.jar --no-gui
if %errorlevel% NEQ 0 (
pause
)

127
gui/src-tauri/src/main.rs Normal file
View File

@@ -0,0 +1,127 @@
#![cfg_attr(
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use clap::Parser;
use clap_verbosity_flag::{InfoLevel, Verbosity};
use std::env;
use std::path::PathBuf;
use tauri::api::clap;
use tauri::api::process::Command;
use tauri::Manager;
#[derive(Parser)]
#[clap(version, about)]
struct Cli {
#[clap(short, long)]
display_console: bool,
#[clap(long)]
launch_from_path: Option<PathBuf>,
#[clap(flatten)]
verbosity: Verbosity<InfoLevel>,
}
fn is_valid_path(path: &PathBuf) -> bool {
let java_folder = path.join("jre");
let server_path = path.join("slimevr.jar");
return java_folder.exists() && server_path.exists();
}
fn get_launch_path(cli: Cli) -> Option<PathBuf> {
let mut path = cli.launch_from_path.unwrap_or_default();
if path.exists() && is_valid_path(&path) {
return Some(path);
}
path = env::current_dir().unwrap();
if path.exists() && is_valid_path(&path) {
return Some(path);
}
path = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
if path.exists() && is_valid_path(&path) {
return Some(path);
}
None
}
fn main() {
let cli = Cli::parse();
// Set up loggers and global handlers
{
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "info")
}
pretty_env_logger::init();
}
// Ensure child processes die when spawned on windows
#[cfg(target_os = "windows")]
{
use win32job::{ExtendedLimitInfo, Job};
let mut info = ExtendedLimitInfo::new();
info.limit_kill_on_job_close();
let job = Job::create_with_limit_info(&mut info).expect("Failed to create Job");
job.assign_current_process()
.expect("Failed to assign current process to Job");
// We don't do anything with the job anymore, but we shouldn't drop it because that would
// terminate our process tree. So we intentionally leak it instead.
std::mem::forget(job);
}
// Spawn server process
let run_path = get_launch_path(cli);
let stdout_recv = if let Some(p) = run_path {
log::info!("Server found on path: {}", p.to_str().unwrap());
let java_folder = p.join("jre");
let (recv, _child) = Command::new(java_folder.join("bin/java").to_str().unwrap())
.current_dir(p)
.args(["-Xmx512M", "-jar", "slimevr.jar", "--no-gui"])
.spawn()
.expect("Unable to start the server jar");
Some(recv)
} else {
log::warn!("No server found. We will not start the server.");
None
};
tauri::Builder::default()
.plugin(tauri_plugin_window_state::Builder::default().build())
.setup(|app| {
if let Some(mut recv) = stdout_recv {
let app_handle = app.app_handle();
tauri::async_runtime::spawn(async move {
use tauri::api::process::CommandEvent;
while let Some(cmd_event) = recv.recv().await {
let emit_me = match cmd_event {
CommandEvent::Stderr(s) => ("stderr", s),
CommandEvent::Stdout(s) => ("stdout", s),
CommandEvent::Error(s) => ("error", s),
CommandEvent::Terminated(s) => ("terminated", format!("{s:?}")),
_ => ("other", "".to_string()),
};
app_handle
.emit_all("server-status", emit_me)
.expect("Failed to emit");
}
app_handle
.emit_all("server-status", ("other", "receiver cancelled"))
.expect("Failed to emit");
});
}
Ok(())
})
//
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

View File

@@ -0,0 +1,86 @@
{
"package": {
"productName": "slimevr-ui",
"version": "0.1.0"
},
"build": {
"distDir": "../build",
"devPath": "http://localhost:3000",
"beforeDevCommand": "npm run start",
"beforeBuildCommand": "npm run build"
},
"tauri": {
"bundle": {
"active": true,
"targets": "all",
"identifier": "slimevr.dev",
"icon": ["icons/icon.ico", "icons/icon.png"],
"resources": [],
"externalBin": [],
"copyright": "",
"category": "DeveloperTool",
"shortDescription": "",
"longDescription": "",
"deb": {
"depends": []
},
"macOS": {
"frameworks": [],
"exceptionDomain": "",
"signingIdentity": null,
"providerShortName": null,
"entitlements": null
},
"windows": {
"certificateThumbprint": null,
"digestAlgorithm": "sha256",
"timestampUrl": ""
}
},
"updater": {
"active": false
},
"allowlist": {
"shell": {
"all": false,
"execute": true
},
"fs": {
"scope": ["$APP/*", "$APP"],
"all": true
},
"path": {
"all": true
},
"window": {
"setResizable": true,
"setTitle": true,
"maximize": true,
"unmaximize": true,
"minimize": true,
"unminimize": true,
"close": true,
"startDragging": true
}
},
"windows": [
{
"title": "Slimevr UI",
"width": 1289,
"height": 709,
"minWidth": 880,
"minHeight": 740,
"resizable": true,
"fullscreen": false,
"decorations": false,
"transparent": false,
"fileDropEnabled": false,
"visible": true
}
],
"security": {
"csp": null
},
"cli": {}
}
}

9
gui/src/App.test.tsx Normal file
View File

@@ -0,0 +1,9 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
});

174
gui/src/App.tsx Normal file
View File

@@ -0,0 +1,174 @@
import {
useProvideWebsocketApi,
WebSocketApiContext,
} from './hooks/websocket-api';
import {
BrowserRouter as Router,
Routes,
Route,
Outlet,
} from 'react-router-dom';
import { Home } from './components/home/Home';
import { AppContextProvider } from './components/providers/AppContext';
import { useEffect } from 'react';
import { MainLayoutRoute } from './components/MainLayout';
import { SettingsLayoutRoute } from './components/settings/SettingsLayout';
import { GeneralSettings } from './components/settings/pages/GeneralSettings';
import { Serial } from './components/settings/pages/Serial';
import { Event, listen } from '@tauri-apps/api/event';
import { TopBar } from './components/TopBar';
import { ConfigContextProvider } from './components/providers/ConfigContext';
import { OnboardingLayout } from './components/onboarding/OnboardingLayout';
import { HomePage } from './components/onboarding/pages/Home';
import { WifiCredsPage } from './components/onboarding/pages/WifiCreds';
import { ConnectTrackersPage } from './components/onboarding/pages/ConnectTracker';
import { OnboardingContextProvider } from './components/onboarding/OnboardingContextProvicer';
import { TrackersAssignPage } from './components/onboarding/pages/trackers-assign/TrackerAssignment';
import { EnterVRPage } from './components/onboarding/pages/EnterVR';
import { AutomaticMountingPage } from './components/onboarding/pages/mounting/AutomaticMounting';
import { ManualMountingPage } from './components/onboarding/pages/mounting/ManualMounting';
import { ResetTutorialPage } from './components/onboarding/pages/ResetTutorial';
import { AutomaticProportionsPage } from './components/onboarding/pages/body-proportions/AutomaticProportions';
import { ManualProportionsPage } from './components/onboarding/pages/body-proportions/ManualProportions';
import { TrackerSettingsPage } from './components/tracker/TrackerSettings';
import { DonePage } from './components/onboarding/pages/Done';
import { OSCSettings } from './components/settings/pages/OSCSettings';
function Layout() {
return (
<>
<Routes>
<Route
path="/"
element={
<MainLayoutRoute>
<Home />
</MainLayoutRoute>
}
/>
<Route
path="/tracker/:trackernum/:deviceid"
element={
<MainLayoutRoute background={false}>
<TrackerSettingsPage />
</MainLayoutRoute>
}
/>
<Route
path="/settings"
element={
<SettingsLayoutRoute>
<Outlet></Outlet>
</SettingsLayoutRoute>
}
>
<Route path="trackers" element={<GeneralSettings />} />
<Route path="serial" element={<Serial />} />
<Route path="osc/vrchat" element={<OSCSettings />} />
</Route>
<Route
path="/onboarding"
element={
<OnboardingLayout>
<Outlet></Outlet>
</OnboardingLayout>
}
>
<Route path="home" element={<HomePage />} />
<Route path="wifi-creds" element={<WifiCredsPage />} />
<Route path="connect-trackers" element={<ConnectTrackersPage />} />
<Route path="trackers-assign" element={<TrackersAssignPage />} />
<Route path="enter-vr" element={<EnterVRPage />} />
<Route path="mounting/auto" element={<AutomaticMountingPage />} />
<Route path="mounting/manual" element={<ManualMountingPage />} />
<Route path="reset-tutorial" element={<ResetTutorialPage />} />
<Route
path="body-proportions/auto"
element={<AutomaticProportionsPage />}
/>
<Route
path="body-proportions/manual"
element={<ManualProportionsPage />}
/>
<Route path="done" element={<DonePage />} />
</Route>
<Route path="*" element={<TopBar></TopBar>}></Route>
</Routes>
</>
);
}
function App() {
const websocketAPI = useProvideWebsocketApi();
useEffect(() => {
const unlisten = listen(
'server-status',
(event: Event<[string, string]>) => {
const [event_type, s] = event.payload;
if ('stderr' === event_type) {
// This strange invocation is what lets us lose the line information in the console
// See more here: https://stackoverflow.com/a/48994308
setTimeout(
console.log.bind(
console,
`%c[SERVER] %c${s}`,
'color:cyan',
'color:red'
)
);
} else if (event_type === 'stdout') {
setTimeout(
console.log.bind(
console,
`%c[SERVER] %c${s}`,
'color:cyan',
'color:green'
)
);
} else if (event_type === 'error') {
console.error('Error: %s', s);
} else if (event_type === 'terminated') {
console.error('Server Process Terminated: %s', s);
} else if (event_type === 'other') {
console.log('Other process event: %s', s);
}
}
);
return () => {
// eslint-disable-next-line @typescript-eslint/no-empty-function
unlisten.then(() => {});
};
}, []);
return (
<Router>
<ConfigContextProvider>
<WebSocketApiContext.Provider value={websocketAPI}>
<AppContextProvider>
<OnboardingContextProvider>
<div className="h-full w-full text-standard bg-background-80 text-background-10">
<div className="flex-col h-full">
{!websocketAPI.isConnected && (
<>
<TopBar></TopBar>
<div className="flex w-full h-full justify-center items-center p-2">
{websocketAPI.isFistConnection
? 'Connecting to the server'
: 'Connection lost to the server. Trying to reconnect...'}
</div>
</>
)}
{websocketAPI.isConnected && <Layout></Layout>}
</div>
</div>
</OnboardingContextProvider>
</AppContextProvider>
</WebSocketApiContext.Provider>
</ConfigContextProvider>
</Router>
);
}
export default App;

View File

@@ -0,0 +1,30 @@
import { useState } from 'react';
import { RpcMessage } from 'solarxr-protocol';
import { RecordBVHRequestT } from 'solarxr-protocol/protocol/typescript/dist/solarxr-protocol/rpc/record-bvhrequest';
import { RecordBVHStatusT } from 'solarxr-protocol/protocol/typescript/dist/solarxr-protocol/rpc/record-bvhstatus';
import { useWebsocketAPI } from '../hooks/websocket-api';
import { BigButton } from './commons/BigButton';
import { RecordIcon } from './commons/icon/RecordIcon';
export function BVHButton() {
const { useRPCPacket, sendRPCPacket } = useWebsocketAPI();
const [recording, setRecording] = useState(false);
const toggleBVH = () => {
const record = new RecordBVHRequestT();
record.stop = recording;
sendRPCPacket(RpcMessage.RecordBVHRequest, record);
};
useRPCPacket(RpcMessage.RecordBVHStatus, (data: RecordBVHStatusT) => {
setRecording(data.recording);
});
return (
<BigButton
text={recording ? 'Recording...' : 'Record BVH'}
icon={<RecordIcon width={20} />}
onClick={toggleBVH}
></BigButton>
);
}

View File

@@ -0,0 +1,60 @@
import { ReactNode } from 'react';
import { ResetType } from 'solarxr-protocol';
import { useLayout } from '../hooks/layout';
import { BVHButton } from './BVHButton';
import { Navbar } from './Navbar';
import { ResetButton } from './home/ResetButton';
import { TopBar } from './TopBar';
import classNames from 'classnames';
import { OverlayWidget } from './widgets/OverlayWidget';
export function MainLayoutRoute({
children,
background = true,
widgets = true,
}: {
children: ReactNode;
background?: boolean;
widgets?: boolean;
}) {
const { layoutHeight, ref } = useLayout<HTMLDivElement>();
const { layoutWidth, ref: refw } = useLayout<HTMLDivElement>();
return (
<>
<TopBar></TopBar>
<div ref={ref} className="flex-grow" style={{ height: layoutHeight }}>
<div className="flex h-full pb-3">
<Navbar></Navbar>
<div
className="flex gap-2 pr-3 w-full"
ref={refw}
style={{ minWidth: layoutWidth }}
>
<div
className={classNames(
'flex flex-col rounded-xl w-full overflow-hidden',
background && 'bg-background-70'
)}
>
{children}
</div>
{widgets && (
<div className="flex flex-col px-2 min-w-[274px] w-[274px] gap-2 pt-2 rounded-xl overflow-y-auto bg-background-70">
<div className="grid grid-cols-2 gap-2 w-full">
<ResetButton type={ResetType.Quick}></ResetButton>
<ResetButton type={ResetType.Full}></ResetButton>
<ResetButton type={ResetType.Mounting}></ResetButton>
<BVHButton></BVHButton>
</div>
<div className="w-full">
<OverlayWidget></OverlayWidget>
</div>
</div>
)}
</div>
</div>
</div>
</>
);
}

View File

@@ -0,0 +1,102 @@
import classnames from 'classnames';
import { ReactChild } from 'react';
import { useMatch, NavLink } from 'react-router-dom';
import { CubeIcon } from './commons/icon/CubeIcon';
import { GearIcon } from './commons/icon/GearIcon';
export function NavButton({
to,
children,
match,
state = {},
icon,
}: {
to: string;
children: ReactChild;
match?: string;
state?: any;
icon: ReactChild;
}) {
const doesMatch = useMatch({
path: match || to,
});
return (
<NavLink
to={to}
state={state}
className={classnames(
'flex flex-col justify-center gap-4 w-[85px] h-[85px] rounded-md group select-text',
{
'bg-accent-background-50 fill-accent-background-20': doesMatch,
'hover:bg-background-70': !doesMatch,
}
)}
>
<div className="flex justify-around">
<div
className={classnames('scale-150', {
'fill-accent-lighter': doesMatch,
'fill-background-50': !doesMatch,
})}
>
{icon}
</div>
</div>
<div
className={classnames('text-center', {
'text-accent-background-10': doesMatch,
'text-background-10': !doesMatch,
})}
>
{children}
</div>
</NavLink>
);
}
export function Navbar() {
return (
<div className="flex flex-col px-2 pt-2">
<div className="flex flex-col flex-grow gap-2">
<NavButton to="/" icon={<CubeIcon></CubeIcon>}>
Home
</NavButton>
<NavButton
to="/onboarding/body-proportions/auto"
match="/onboarding/body-proportions/*"
state={{ alonePage: true }}
icon={<GearIcon></GearIcon>}
>
Body proportions
</NavButton>
<NavButton
to="/onboarding/trackers-assign"
state={{ alonePage: true }}
icon={<GearIcon></GearIcon>}
>
Tracker assignment
</NavButton>
<NavButton
to="/onboarding/mounting/auto"
match="/onboarding/mounting/*"
state={{ alonePage: true }}
icon={<GearIcon></GearIcon>}
>
Mounting Calibration
</NavButton>
<NavButton to="/onboarding/home" icon={<GearIcon></GearIcon>}>
Setup Wizard
</NavButton>
</div>
<NavButton
to="/settings/trackers"
match="/settings/*"
state={{ scrollTo: 'steamvr' }}
icon={<GearIcon></GearIcon>}
>
Settings
</NavButton>
</div>
);
}

View File

@@ -0,0 +1,81 @@
import { ReactChild } from 'react';
import { NavLink } from 'react-router-dom';
import { CloseIcon } from './commons/icon/CloseIcon';
import { MaximiseIcon } from './commons/icon/MaximiseIcon';
import { MinimiseIcon } from './commons/icon/MinimiseIcon';
import { SlimeVRIcon } from './commons/icon/SimevrIcon';
import { appWindow } from '@tauri-apps/api/window';
import { ProgressBar } from './commons/ProgressBar';
import { Typography } from './commons/Typography';
import packagejson from '../../package.json';
export function TopBar({
progress,
}: {
children?: ReactChild;
progress?: number;
}) {
return (
<div data-tauri-drag-region className="flex gap-2 h-[38px] z-50">
<div
className="flex px-2 pb-1 mt-3 justify-around z-50"
data-tauri-drag-region
>
<div className="flex gap-1" data-tauri-drag-region>
<NavLink
to="/"
className="flex justify-around flex-col select-all"
data-tauri-drag-region
>
<SlimeVRIcon></SlimeVRIcon>
</NavLink>
<div className="flex justify-around flex-col" data-tauri-drag-region>
<Typography>SlimeVR</Typography>
</div>
<div
className="mx-2 flex justify-around flex-col text-standard-bold text-status-success bg-status-success bg-opacity-20 rounded-lg px-3"
data-tauri-drag-region
>
v{packagejson.version}
</div>
</div>
</div>
<div
className="flex flex-grow items-center h-full justify-center z-50"
data-tauri-drag-region
>
<div
className="flex max-w-xl h-full items-center w-full"
data-tauri-drag-region
>
{progress !== undefined && (
<ProgressBar progress={progress} height={3} parts={3}></ProgressBar>
)}
</div>
</div>
<div
className="flex justify-end items-center px-2 gap-2 z-50"
data-tauri-drag-region
>
<div
className="flex items-center justify-center hover:bg-background-60 rounded-full w-7 h-7"
onClick={() => appWindow.minimize()}
>
<MinimiseIcon></MinimiseIcon>
</div>
<div
className="flex items-center justify-center hover:bg-background-60 rounded-full w-7 h-7"
onClick={() => appWindow.toggleMaximize()}
>
<MaximiseIcon></MaximiseIcon>
</div>
<div
className="flex items-center justify-center hover:bg-background-60 rounded-full w-7 h-7"
onClick={() => appWindow.close()}
>
<CloseIcon></CloseIcon>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,45 @@
import classNames from 'classnames';
import { ReactChild, useMemo } from 'react';
import { NavLink } from 'react-router-dom';
import { ArrowLeftIcon, ArrowRightIcon } from './icon/ArrowIcons';
export function ArrowLink({
to,
children,
direction = 'left',
variant = 'flat',
}: {
to: string;
children: ReactChild;
direction?: 'left' | 'right';
variant?: 'flat' | 'boxed';
}) {
const classes = useMemo(() => {
const variantsMap = {
flat: classNames('justify-start'),
boxed: classNames(
'justify-between bg-background-70 rounded-md hover:bg-background-60 p-3'
),
};
return classNames(
variantsMap[variant],
'flex gap-2 hover:fill-background-10 hover:text-background-10 fill-background-30 text-background-30'
);
}, [variant]);
return (
<NavLink to={to} className={classes}>
{direction === 'left' && (
<div className="flex flex-col justify-center">
<ArrowLeftIcon></ArrowLeftIcon>
</div>
)}
{children}
{direction === 'right' && (
<div className="flex flex-col justify-center">
<ArrowRightIcon></ArrowRightIcon>
</div>
)}
</NavLink>
);
}

View File

@@ -0,0 +1,36 @@
import classNames from 'classnames';
import React, { ReactChild } from 'react';
export function BigButton({
text,
icon,
disabled,
onClick,
...props
}: {
text: string;
disabled?: boolean;
icon: ReactChild;
} & React.HTMLAttributes<HTMLButtonElement>) {
return (
<button
disabled={disabled}
onClick={onClick}
{...props}
type="button"
className={classNames(
'flex flex-col justify-center rounded-md py-3 gap-1 px-3 cursor-pointer items-center ',
{
'bg-background-60 hover:bg-background-60 cursor-not-allowed text-background-40 fill-background-40':
disabled,
'bg-background-60 hover:bg-background-50 text-standard fill-background-10':
!disabled,
},
props.className
)}
>
<div className="flex justify-around">{icon}</div>
<div className="flex text-default flex-grow">{text}</div>
</button>
);
}

View File

@@ -0,0 +1,197 @@
import classNames from 'classnames';
import {
ReactChild,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import { BodyPart, TrackerDataT } from 'solarxr-protocol';
import { FlatDeviceTracker } from '../../hooks/app';
import { useTracker } from '../../hooks/tracker';
import { PersonFrontIcon } from './PersonFrontIcon';
import { Typography } from './Typography';
interface SlotDot {
id: string;
left: number;
top: number;
height: number;
width: number;
buttonOffset: {
left: number;
top: number;
};
}
type DotParams = {
dotSize: number;
trackers: FlatDeviceTracker[];
} & SlotDot;
function Tracker({
tracker,
updateVelocity,
}: {
tracker: TrackerDataT;
updateVelocity: (velocity: number) => void;
}) {
const { useVelocity } = useTracker(tracker);
const velocity = useVelocity();
useEffect(() => {
updateVelocity(velocity);
}, [velocity]);
return <></>;
}
function Dot({
top,
height,
width,
buttonOffset,
id,
left,
dotSize,
trackers,
}: DotParams) {
const [velocities, setVelocities] = useState<number[]>([]);
const updateVelocity = (vel: number) => {
if (velocities.length > 3) {
velocities.shift();
}
velocities.push(vel);
setVelocities(velocities);
};
const globalVelocity = useMemo(
() => velocities.reduce((curr, v) => curr + v, 0) / (trackers?.length || 1),
[velocities, trackers]
);
return (
<div
key={id}
className="absolute z-10"
style={{
top: top + height / 2 - dotSize / 2 + buttonOffset.top,
left: left + width / 2 - dotSize / 2 + buttonOffset.left,
}}
>
<div
className={classNames(
'rounded-full outline outline-2 outline-accent-background-20 bg-background-10 transition-transform'
)}
style={{
width: dotSize,
height: dotSize,
outlineWidth: globalVelocity * 2 + 2,
}}
></div>
{trackers?.map(({ tracker }, index) => (
<Tracker
tracker={tracker}
key={index}
updateVelocity={(vel) => updateVelocity(vel)}
/>
))}
</div>
);
}
export function BodyDisplay({
leftControls,
rightControls,
trackers,
width = 228,
dotsSize = 20,
variant = 'tracker-select',
}: {
leftControls?: ReactChild;
rightControls?: ReactChild;
width?: number;
dotsSize?: number;
variant?: 'dots' | 'tracker-select';
trackers: FlatDeviceTracker[];
}) {
const personRef = useRef<HTMLDivElement | null>(null);
const [slotsButtonsPos, setSlotsButtonPos] = useState<SlotDot[]>([]);
const getSlotsPos = () => {
return (
(personRef.current && [
...(personRef.current.querySelectorAll('.body-part-circle') as any),
]) ||
[]
);
};
const getOffset = (el: HTMLDivElement, offset = { left: 0, top: 0 }) => {
const rect = el.getBoundingClientRect();
return {
left: rect.left - (offset.left || 0),
top: rect.top - (offset.top || 0),
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight,
};
};
useLayoutEffect(() => {
if (!personRef.current) return;
const slotsPos = getSlotsPos();
const personBox = personRef.current.getBoundingClientRect();
const slots = slotsPos.map((slot: HTMLDivElement) => {
const slotPosition = getOffset(slot, personBox);
return {
...slotPosition,
id: slot.id,
buttonOffset: {
left: personBox.left - personBox.left,
top: personBox.top - personBox.top,
},
};
});
setSlotsButtonPos(slots);
}, [leftControls, rightControls, variant]);
const trackerPartGrouped = useMemo(
() =>
trackers.reduce<{ [key: number]: FlatDeviceTracker[] }>((curr, td) => {
if (!td) return curr;
const key = td.tracker.info?.bodyPart || BodyPart.NONE;
return {
...curr,
[key]: [...(curr[key] || []), td],
};
}, {}),
[trackers]
);
return (
<div className="flex">
<div
ref={personRef}
className={classNames(
'relative w-full flex justify-center',
variant === 'tracker-select' && 'mx-10'
)}
>
<PersonFrontIcon width={width}></PersonFrontIcon>
{slotsButtonsPos.map((dotData) => (
<Dot
{...dotData}
dotSize={dotsSize}
key={dotData.id}
trackers={trackerPartGrouped[(BodyPart as any)[dotData.id]]}
/>
))}
</div>
</div>
);
}

View File

@@ -0,0 +1,200 @@
import classNames from 'classnames';
import {
ReactChild,
useEffect,
useLayoutEffect,
useMemo,
useRef,
useState,
} from 'react';
import { BodyPart } from 'solarxr-protocol';
import { PersonFrontIcon } from './PersonFrontIcon';
export function BodyInteractions({
leftControls,
rightControls,
assignedRoles,
width = 228,
dotsSize = 20,
variant = 'tracker-select',
}: {
leftControls?: ReactChild;
rightControls?: ReactChild;
width?: number;
dotsSize?: number;
variant?: 'dots' | 'tracker-select';
assignedRoles: BodyPart[];
}) {
const personRef = useRef<HTMLDivElement | null>(null);
const leftContainerRef = useRef<HTMLDivElement | null>(null);
const rightContainerRef = useRef<HTMLDivElement | null>(null);
const canvasRefRef = useRef<HTMLCanvasElement | null>(null);
const [slotsButtonsPos, setSlotsButtonPos] = useState<
{
id: string;
left: number;
top: number;
height: number;
width: number;
hidden: boolean;
buttonOffset: {
left: number;
top: number;
};
}[]
>([]);
const getSlotsPos = () => {
return (
(personRef.current && [
...(personRef.current.querySelectorAll('.body-part-circle') as any),
]) ||
[]
);
};
const getControlsPos = () => {
const pos = (container: HTMLDivElement) =>
[...(container.querySelectorAll('.control') as any)].filter(
({ id }) => !!id
);
const left =
(leftContainerRef.current && pos(leftContainerRef.current)) || [];
const right =
(rightContainerRef.current && pos(rightContainerRef.current)) || [];
return [...left, ...right];
};
const getOffset = (el: HTMLDivElement, offset = { left: 0, top: 0 }) => {
const rect = el.getBoundingClientRect();
return {
left: rect.left - (offset.left || 0),
top: rect.top - (offset.top || 0),
width: rect.width || el.offsetWidth,
height: rect.height || el.offsetHeight,
};
};
useLayoutEffect(() => {
if (
!(
personRef.current &&
canvasRefRef.current &&
rightContainerRef.current &&
leftContainerRef.current
)
)
return;
const ctx = canvasRefRef.current.getContext('2d');
if (!ctx) return;
const slotsPos = getSlotsPos();
const controlsPos = getControlsPos();
canvasRefRef.current.width = canvasRefRef.current.offsetWidth;
canvasRefRef.current.height = canvasRefRef.current.offsetHeight;
ctx.strokeStyle = '#608AAB';
ctx.lineWidth = 1;
const canvasBox = canvasRefRef.current.getBoundingClientRect();
const personBox = personRef.current.getBoundingClientRect();
const controlsPosIds = controlsPos.map(({ id: cid }) => cid);
const slots = slotsPos.map((slot: HTMLDivElement) => {
const slotPosition = getOffset(slot, canvasBox);
return {
...slotPosition,
id: slot.id,
hidden:
variant === 'tracker-select' && !controlsPosIds.includes(slot.id),
buttonOffset: {
left: canvasBox.left - personBox.left,
top: canvasBox.top - personBox.top,
},
};
});
if (variant === 'tracker-select') {
slots.forEach((slot) => {
const controls = controlsPos.filter(({ id }) => id === slot.id);
controls.forEach((control) => {
const controlPosition = getOffset(control, canvasBox);
const offsetX =
controlPosition.left < slot.left ? controlPosition.width : 0;
const constolLeft = controlPosition.left + offsetX;
const LINE_BREAK_WIDTH = 40;
const leftOffsetX =
LINE_BREAK_WIDTH * (controlPosition.left < slot.left ? -1 : 1);
ctx.beginPath();
ctx.moveTo(
constolLeft,
controlPosition.top + controlPosition.height / 2
);
ctx.lineTo(
constolLeft - leftOffsetX,
controlPosition.top + controlPosition.height / 2
);
ctx.lineTo(slot.left + slot.width / 2, slot.top + slot.height / 2);
ctx.stroke();
});
});
}
setSlotsButtonPos(slots);
}, [leftControls, rightControls, variant]);
return (
<div className="relative">
<canvas
ref={canvasRefRef}
className="absolute w-full h-full top-0 z-10"
width="100%"
height="100%"
></canvas>
<div className="flex">
<div ref={leftContainerRef} className="z-10">
{leftControls}
</div>
<div
ref={personRef}
className={classNames(
'relative w-full flex justify-center',
variant === 'tracker-select' && 'mx-10'
)}
>
<PersonFrontIcon width={width}></PersonFrontIcon>
{slotsButtonsPos.map(
({ top, left, height, width, id, hidden, buttonOffset }) => (
<div
key={id}
className="absolute z-10"
style={{
top: top + height / 2 - dotsSize / 2 + buttonOffset.top,
left: left + width / 2 - dotsSize / 2 + buttonOffset.left,
}}
>
<div
className={classNames(
'rounded-full outline outline-2 outline-background-20 transition-opacity',
(assignedRoles.includes((BodyPart as any)[id]) &&
'bg-background-70') ||
'bg-background-10',
(hidden && 'opacity-0') || 'opacity-100'
)}
style={{ width: dotsSize, height: dotsSize }}
></div>
</div>
)
)}
</div>
<div ref={rightContainerRef} className="z-10">
{rightControls}
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,103 @@
import classNames from 'classnames';
import React, { ReactChild, useMemo } from 'react';
import { NavLink } from 'react-router-dom';
import { LoaderIcon } from './icon/LoaderIcon';
function ButtonContent({
loading,
icon,
children,
}: {
loading: boolean;
icon?: ReactChild;
children: ReactChild;
}) {
return (
<>
<div
className={classNames(
{ 'opacity-0': loading },
'flex flex-row gap-2 justify-center'
)}
>
{icon && (
<div className="flex justify-center items-center fill-background-10 w-5 h-5">
{icon}
</div>
)}
{children}
</div>
{loading && (
<div className="absolute top-0 left-0 w-full h-full flex justify-center items-center fill-background-10">
<LoaderIcon youSpinMeRightRoundBabyRightRound></LoaderIcon>
</div>
)}
</>
);
}
export function Button({
children,
variant,
disabled,
to,
loading = false,
state = {},
icon,
rounded = false,
...props
}: {
children: ReactChild;
icon?: ReactChild;
variant: 'primary' | 'secondary' | 'tierciary';
to?: string;
loading?: boolean;
rounded?: boolean;
state?: any;
} & React.ButtonHTMLAttributes<HTMLButtonElement>) {
const classes = useMemo(() => {
const variantsMap = {
primary: classNames({
'bg-accent-background-30 hover:bg-accent-background-20 text-standard text-background-10':
!disabled,
'bg-accent-background-40 hover:bg-accent-background-40 cursor-not-allowed text-accent-background-10':
disabled,
}),
secondary: classNames({
'bg-background-60 hover:bg-background-50 text-standard text-background-10':
!disabled,
'bg-background-60 hover:bg-background-60 cursor-not-allowed text-background-40':
disabled,
}),
tierciary: classNames({
'bg-background-50 hover:bg-background-40 text-standard text-background-10':
!disabled,
'bg-background-50 hover:bg-background-50 cursor-not-allowed text-background-40':
disabled,
}),
};
return classNames(
variantsMap[variant],
'focus:ring-4 text-center relative',
{
'rounded-full p-2 text-center min-h-[35px] min-w-[35px]': rounded,
'rounded-md px-5 py-2.5': !rounded,
},
props.className
);
}, [variant, disabled, rounded]);
return to ? (
<NavLink to={to} className={classes} state={state}>
<ButtonContent icon={icon} loading={loading}>
{children}
</ButtonContent>
</NavLink>
) : (
<button type="button" {...props} className={classes} disabled={disabled}>
<ButtonContent icon={icon} loading={loading}>
{children}
</ButtonContent>
</button>
);
}

View File

@@ -0,0 +1,87 @@
import classNames from 'classnames';
import { ReactChild, useMemo } from 'react';
import { Control, Controller } from 'react-hook-form';
export function CheckBox({
label,
variant = 'checkbox',
control,
outlined,
name,
...props
}: {
label: string | ReactChild;
control: Control<any>;
name: string;
variant?: 'checkbox' | 'toggle';
outlined?: boolean;
}) {
const classes = useMemo(() => {
const vriantsMap = {
checkbox: {
checkbox: classNames(
'bg-background-50 border-background-50 rounded-md w-5 h-5 text-accent-background-30 focus:border-accent-background-40 focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent'
),
toggle: '',
pin: '',
},
toggle: {
checkbox: classNames('hidden'),
toggle: classNames('w-10 h-4 rounded-full relative transition-colors'),
pin: classNames('h-2 w-2 bg-background-10 rounded-full absolute m-1'),
},
};
return vriantsMap[variant];
}, [variant]);
return (
<Controller
control={control}
name={name}
render={({ field: { onChange, value, ref, onBlur, name } }) => (
<div
className={classNames(
{
'bg-background-60 rounded-lg text-white': outlined,
'text-background-30': !outlined,
},
'flex items-center gap-2 w-full'
)}
>
<label
className={classNames(
'w-full py-3 flex gap-2 items-center text-standard-bold',
{ 'px-3': outlined }
)}
>
<input
ref={ref}
onChange={onChange}
checked={value}
name={name}
className={classes.checkbox}
type="checkbox"
{...props}
/>
{variant === 'toggle' && (
<div
className={classNames(classes.toggle, {
'bg-accent-background-30': value,
'bg-background-50': !value,
})}
>
<div
className={classNames(classes.pin, {
'left-0': !value,
'right-0': value,
})}
></div>
</div>
)}
{label}
</label>
</div>
)}
/>
);
}

View File

@@ -0,0 +1,54 @@
import classNames from 'classnames';
import {
forwardRef,
HTMLInputTypeAttribute,
MouseEvent,
useState,
} from 'react';
import { EyeIcon } from './icon/EyeIcon';
export interface InputProps {
type: HTMLInputTypeAttribute;
placeholder?: string;
label?: string;
autocomplete?: boolean;
}
export const Input = forwardRef<HTMLInputElement, InputProps>(function AppInput(
{ type, placeholder, label, autocomplete, ...props },
ref
) {
const [forceText, setForceText] = useState(false);
const togglePassword = (e: MouseEvent<HTMLDivElement>) => {
e.preventDefault();
setForceText(!forceText);
};
return (
<label className="flex flex-col gap-1">
{label}
<div className="relative w-full">
<input
type={forceText ? 'text' : type}
ref={ref}
className={classNames(
'w-full focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent rounded-md bg-background-60 border-background-60 focus:border-accent-background-40 placeholder:text-background-30 text-standard relative',
{ 'pr-10': type === 'password' }
)}
placeholder={placeholder}
autoComplete={autocomplete ? 'off' : 'on'}
{...props}
></input>
{type === 'password' && (
<div
className="fill-background-10 absolute top-0 h-full flex flex-col justify-center right-0 p-4"
onClick={togglePassword}
>
<EyeIcon></EyeIcon>
</div>
)}
</div>
</label>
);
});

View File

@@ -0,0 +1,25 @@
import classNames from 'classnames';
import { ReactChild } from 'react';
import ReactModal from 'react-modal';
export function EmptyModal({
children,
...props
}: { children?: ReactChild } & ReactModal.Props) {
return (
<ReactModal
{...props}
shouldCloseOnOverlayClick
shouldCloseOnEsc
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col justify-center items-center w-full h-full bg-background-90 bg-opacity-60 z-20'
)}
className={classNames(
props.className as string,
'items-center focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none'
)}
>
{children}
</ReactModal>
);
}

View File

@@ -0,0 +1,64 @@
import { Control, Controller } from 'react-hook-form';
import { Button } from './Button';
import { Typography } from './Typography';
export function NumberSelector({
label,
valueLabelFormat,
control,
name,
min,
max,
step,
}: {
label: string;
valueLabelFormat?: (value: number) => string;
control: Control<any>;
name: string;
min: number;
max: number;
step: number | ((value: number, add: boolean) => number);
}) {
const stepFn =
typeof step === 'function'
? step
: (value: number, add: boolean) =>
+(add ? value + step : value - step).toFixed(2);
return (
<Controller
control={control}
name={name}
render={({ field: { onChange, value } }) => (
<div className="flex flex-col gap-1 w-full">
<Typography bold>{label}</Typography>
<div className="flex gap-2 bg-background-60 p-2 rounded-lg">
<div className="flex">
<Button
variant="tierciary"
rounded
onClick={() => onChange(stepFn(value, false))}
disabled={stepFn(value, false) < min}
>
-
</Button>
</div>
<div className="flex flex-grow justify-center items-center w-10">
{valueLabelFormat ? valueLabelFormat(value) : value}
</div>
<div className="flex">
<Button
variant="tierciary"
rounded
onClick={() => onChange(stepFn(value, true))}
disabled={stepFn(value, true) > max}
>
+
</Button>
</div>
</div>
</div>
)}
/>
);
}

View File

@@ -0,0 +1,151 @@
import { BodyPart } from 'solarxr-protocol';
export function PersonFrontIcon({ width }: { width?: number }) {
const CIRCLE_RADIUS = 0.0001;
return (
<svg
width={width || 240}
viewBox="0 0 165 392"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M84.53 224.074C83.953 230.874 88.569 266.874 90.951 280.984C92.085 287.671 95.195 298.565 94.076 304.349C92.476 312.411 92.017 322.843 92.896 328.918C93.451 332.607 95.196 349.618 92.696 355.845C91.389 359.108 88.996 375.832 88.996 375.832C82.756 391.587 86.278 390.812 86.278 390.812C88.21 393.183 91.519 390.998 91.519 390.998C92.1549 391.464 92.9388 391.682 93.7241 391.612C94.5094 391.542 95.2421 391.188 95.785 390.616C97.949 392.407 100.471 390.396 100.471 390.396C103.189 391.807 105.71 389.205 105.71 389.205C107.271 389.991 107.653 388.998 107.653 388.998C112.337 388.698 105.039 373.706 105.039 373.706C103.291 360.242 106.773 352.748 106.773 352.748C118.178 318.926 118.758 309.948 114.199 297.204C112.915 293.524 112.59 292.067 113.181 290.47C114.547 286.783 113.551 271.953 115.217 266.064C118.431 254.706 121.602 225.903 123.254 212.464C125.475 194.364 115.388 170.088 115.388 170.088C113.179 160.21 116.418 125.016 116.418 125.016C120.941 132.054 120.768 144.477 120.768 144.477C120.05 157.506 131.294 177.42 131.294 177.42C136.694 185.649 138.742 193.456 138.742 194.036C138.742 196.407 138.223 202.145 138.223 202.145L138.43 207.145C138.803 209.721 139.034 212.316 139.123 214.918C138.28 227.953 140.35 225.501 140.35 225.501C142.098 225.501 144.018 215.011 144.018 215.011C144.018 217.711 143.357 225.811 144.818 228.869C146.564 232.512 147.848 228.244 147.871 227.387C148.333 210.787 149.33 215.138 149.33 215.138C150.301 228.602 151.494 231.644 153.63 230.591C155.25 229.818 153.769 214.433 153.769 214.433C156.544 223.572 158.649 225.027 158.649 225.027C163.229 228.243 160.397 219.361 159.76 217.602C156.371 208.256 156.267 205.017 156.267 205.017C160.501 213.417 163.692 213.104 163.692 213.104C167.822 211.786 160.083 199.894 155.548 194.197C153.234 191.297 150.248 187.408 149.384 185.097C147.973 181.188 146.907 168.62 146.907 168.62C146.48 153.79 142.813 147.348 142.813 147.348C136.544 137.314 135.365 118.598 135.365 118.598L135.09 87C132.89 65.445 117.01 65.29 117.01 65.29C100.957 62.9 98.723 57.714 98.723 57.714C95.323 52.821 97.266 43.44 97.266 43.44C100.087 41.145 101.175 35.053 101.175 35.053C105.859 31.461 105.63 26.205 103.466 26.262C101.73 26.308 102.123 24.87 102.123 24.87C105.052 1.208 84.046 0 84.046 0H80.836C80.836 0 59.821 1.208 62.746 24.864C62.746 24.864 63.139 26.304 61.388 26.256C59.23 26.199 59.029 31.456 63.696 35.047C63.696 35.047 64.783 41.137 67.605 43.434C67.605 43.434 69.548 52.814 66.148 57.708C66.148 57.708 63.922 62.894 47.861 65.284C47.861 65.284 31.952 65.44 29.788 86.994L29.488 118.594C29.488 118.594 28.331 137.311 22.038 147.344C22.038 147.344 18.389 153.787 17.967 168.616C17.967 168.616 16.898 181.184 15.492 185.093C14.635 187.393 11.653 191.276 9.32001 194.193C4.74601 199.878 -2.94199 211.745 1.17101 213.1C1.17101 213.1 4.37901 213.412 8.59601 205.013C8.59601 205.013 8.50901 208.229 5.12501 217.598C4.46001 219.334 1.63201 228.217 6.21301 225.024C6.21301 225.024 8.33501 223.567 11.093 214.43C11.093 214.43 9.61301 229.815 11.26 230.588C13.412 231.642 14.586 228.599 15.56 215.135C15.56 215.135 16.56 210.787 17.017 227.384C17.04 228.241 18.295 232.509 20.049 228.866C21.529 225.811 20.864 217.727 20.864 215.008C20.864 215.008 22.764 225.498 24.536 225.498C24.536 225.498 26.624 227.95 25.767 214.915C25.628 212.786 26.375 208.415 26.467 207.142L26.667 202.142C26.667 202.142 26.146 196.417 26.146 194.033C26.146 193.442 28.194 185.646 33.594 177.417C33.594 177.417 44.826 157.494 44.103 144.474C44.103 144.474 43.947 132.051 48.47 125.013C48.47 125.013 51.68 160.205 49.505 170.085C49.505 170.085 39.405 194.358 41.629 212.461C43.27 225.937 46.435 254.702 49.657 266.061C51.34 271.938 50.345 286.761 51.693 290.467C52.301 292.076 51.982 293.558 50.675 297.201C46.141 309.947 46.718 318.925 58.123 352.745C58.123 352.745 61.633 360.239 59.859 373.703C59.859 373.703 52.572 388.695 57.239 388.995C57.239 388.995 57.604 389.988 59.182 389.202C59.182 389.202 61.703 391.802 64.427 390.393C64.427 390.393 66.95 392.407 69.106 390.613C69.6451 391.185 70.3751 391.54 71.158 391.61C71.9409 391.681 72.7225 391.462 73.355 390.995C73.355 390.995 76.664 393.227 78.63 390.809C78.63 390.809 82.123 391.584 75.904 375.829C75.904 375.829 73.522 359.129 72.209 355.842C69.709 349.621 71.474 332.57 72.009 328.915C72.87 322.806 72.409 312.398 70.835 304.346C69.684 298.575 72.801 287.679 73.952 280.981C76.317 266.881 80.952 230.881 80.373 224.071L82.288 224.743C83.0863 224.756 83.8692 224.522 84.53 224.074Z" />
<circle
className="body-part-circle"
cx="82.004"
cy="120"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.CHEST]}
/>
<circle
className="body-part-circle"
cx="82.004"
cy="181"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.HIP]}
/>
<circle
className="body-part-circle"
cx="82.004"
cy="181"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.WAIST]}
/>
<circle
className="body-part-circle"
cx="82"
cy="50"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.NECK]}
/>
<circle
className="body-part-circle"
cx="82"
cy="50"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.HEAD]}
/>
<circle
className="body-part-circle"
cx="139.004"
cy="170"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_HAND]}
/>
<circle
className="body-part-circle"
cx="122"
cy="93"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_UPPER_ARM]}
/>
<circle
className="body-part-circle"
cx="122"
cy="93"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_SHOULDER]}
/>
<circle
className="body-part-circle"
cx="139.004"
cy="170"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_LOWER_ARM]}
/>
<circle
className="body-part-circle"
cx="97.004"
cy="360"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_LOWER_LEG]}
/>
<circle
className="body-part-circle"
cx="103.004"
cy="260"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_UPPER_LEG]}
/>
<circle
className="body-part-circle"
cx="97.004"
cy="360"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.LEFT_FOOT]}
/>
<circle
className="body-part-circle"
cx="26.004"
cy="170"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_HAND]}
/>
<circle
className="body-part-circle"
cx="43"
cy="93"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_UPPER_ARM]}
/>
<circle
className="body-part-circle"
cx="43"
cy="93"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_SHOULDER]}
/>
<circle
className="body-part-circle"
cx="26.004"
cy="170"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_LOWER_ARM]}
/>
<circle
className="body-part-circle"
cx="67.004"
cy="360"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_LOWER_LEG]}
/>
<circle
className="body-part-circle"
cx="61.004"
cy="260"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_UPPER_LEG]}
/>
<circle
className="body-part-circle"
cx="67.004"
cy="360"
r={CIRCLE_RADIUS}
id={BodyPart[BodyPart.RIGHT_FOOT]}
/>
</svg>
);
}

View File

@@ -0,0 +1,43 @@
import classNames from 'classnames';
import { useMemo } from 'react';
export function ProgressBar({
progress,
parts = 1,
height = 10,
}: {
progress: number;
parts?: number;
height?: number;
}) {
const Bar = ({ index }: { index: number }) => {
const value = useMemo(
() => Math.min(Math.max((progress * parts) / 1 - index, 0), 1),
[index, progress]
);
return (
<div
className="flex relative flex-grow bg-background-50 rounded-lg overflow-hidden"
style={{ height: `${height}px` }}
>
<div
className={classNames(
'bg-accent-background-20 rounded-lg overflow-hidden absolute top-0'
)}
style={{
width: `${value * 100}%`,
height: `${height}px`,
}}
></div>
</div>
);
};
return (
<div className="flex w-full flex-row gap-2">
{Array.from({ length: parts }).map((_, key) => (
<Bar index={key} key={key}></Bar>
))}
</div>
);
}

View File

@@ -0,0 +1,53 @@
import classNames from 'classnames';
import { Control, Controller } from 'react-hook-form';
import { Typography } from './Typography';
export function Radio({
control,
name,
label,
value,
desciption,
}: {
control: Control<any>;
name: string;
label: string;
value: string | number;
desciption?: string;
}) {
return (
<Controller
control={control}
name={name}
render={({ field: { onChange, ref, name, value: checked } }) => (
<label
className={classNames(
'w-full bg-background-60 p-3 rounded-md flex gap-3 border-2',
{
'border-accent-background-30': value == checked,
'border-transparent': value != checked,
}
)}
>
<input
type="radio"
className="text-accent-background-30 focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent"
name={name}
ref={ref}
onChange={onChange}
value={value}
checked={value == checked}
></input>
<div className="flex flex-col gap-2">
<Typography bold>{label}</Typography>
{desciption && (
<Typography variant="standard" color="secondary">
{desciption}
</Typography>
)}
</div>
</label>
)}
/>
);
}

View File

@@ -0,0 +1,16 @@
import { ReactChild } from 'react';
import { BulbIcon } from './icon/BulbIcon';
import { Typography } from './Typography';
export function TipBox({ children }: { children: ReactChild }) {
return (
<div className="flex flex-row gap-4 bg-accent-background-50 p-4 rounded-md">
<div className="fill-accent-background-20 flex flex-col justify-center">
<BulbIcon></BulbIcon>
</div>
<div className="flex flex-col">
<Typography color="text-accent-background-10">{children}</Typography>
</div>
</div>
);
}

View File

@@ -0,0 +1,43 @@
import classNames from 'classnames';
import { createElement, ReactNode, useMemo } from 'react';
export function Typography({
variant = 'standard',
bold = false,
color = 'primary',
children,
}: {
variant?: 'main-title' | 'section-title' | 'standard' | 'vr-accessible';
bold?: boolean;
block?: boolean;
color?: 'primary' | 'secondary' | string;
children: ReactNode;
}) {
const tag = useMemo(() => {
const tags = {
'main-title': 'h1',
'section-title': 'h2',
standard: 'p',
'vr-accessible': 'p',
};
return tags[variant];
}, [variant]);
return createElement(
tag,
{
className: classNames([
variant === 'main-title' && 'text-main-title',
variant === 'section-title' && 'text-section-title',
variant === 'standard' &&
(bold ? 'text-standard-bold' : 'text-standard'),
variant === 'vr-accessible' &&
(bold ? 'text-vr-accesible-bold' : 'text-vr-accesible'),
color === 'primary' && 'text-background-10',
color === 'secondary' && 'text-background-30',
typeof color === 'string' && color,
]),
},
children
);
}

View File

@@ -0,0 +1,48 @@
export function ArrowDownIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
xmlnsXlink="http://www.w3.org/1999/xlink"
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
>
<path d="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
</svg>
);
}
export function ArrowLeftIcon() {
return (
<svg
width="12"
height="10"
viewBox="0 0 12 10"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 5C12 5.18941 11.921 5.37106 11.7804 5.50499C11.6397 5.63892 11.449 5.71416 11.2501 5.71416H2.56155L5.7817 8.77932C5.85142 8.84572 5.90673 8.92455 5.94446 9.0113C5.9822 9.09805 6.00162 9.19104 6.00162 9.28494C6.00162 9.37884 5.9822 9.47183 5.94446 9.55858C5.90673 9.64534 5.85142 9.72417 5.7817 9.79056C5.71197 9.85696 5.6292 9.90964 5.5381 9.94557C5.447 9.98151 5.34936 10 5.25075 10C5.15215 10 5.05451 9.98151 4.96341 9.94557C4.87231 9.90964 4.78954 9.85696 4.71981 9.79056L0.220316 5.50562C0.150479 5.43928 0.0950707 5.36048 0.0572652 5.27371C0.0194598 5.18695 0 5.09394 0 5C0 4.90606 0.0194598 4.81305 0.0572652 4.72629C0.0950707 4.63952 0.150479 4.56072 0.220316 4.49438L4.71981 0.209436C4.86063 0.0753365 5.05161 0 5.25075 0C5.4499 0 5.64088 0.0753365 5.7817 0.209436C5.92251 0.343536 6.00162 0.525414 6.00162 0.715059C6.00162 0.904705 5.92251 1.08658 5.7817 1.22068L2.56155 4.28584H11.2501C11.449 4.28584 11.6397 4.36108 11.7804 4.49502C11.921 4.62895 12 4.81059 12 5Z"
/>
</svg>
);
}
export function ArrowRightIcon() {
return (
<svg
width="12"
height="10"
viewBox="0 0 12 10"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M-3.2717e-07 5C-3.2717e-07 4.81059 0.0790079 4.62894 0.219644 4.49501C0.360281 4.36108 0.551026 4.28584 0.749916 4.28584L9.43845 4.28584L6.2183 1.22068C6.14858 1.15428 6.09327 1.07545 6.05554 0.9887C6.0178 0.901945 5.99838 0.808961 5.99838 0.715058C5.99838 0.621155 6.0178 0.528172 6.05554 0.441417C6.09327 0.354662 6.14858 0.275834 6.2183 0.209435C6.28803 0.143036 6.3708 0.0903648 6.4619 0.0544297C6.553 0.0184946 6.65064 -2.87569e-07 6.74925 -2.87569e-07C6.84785 -2.87569e-07 6.94549 0.0184946 7.03659 0.0544297C7.12769 0.0903648 7.21046 0.143036 7.28019 0.209435L11.7797 4.49438C11.8495 4.56072 11.9049 4.63952 11.9427 4.72629C11.9805 4.81305 12 4.90606 12 5C12 5.09394 11.9805 5.18695 11.9427 5.27371C11.9049 5.36048 11.8495 5.43928 11.7797 5.50562L7.28019 9.79056C7.13937 9.92466 6.94839 10 6.74925 10C6.5501 10 6.35912 9.92466 6.2183 9.79056C6.07749 9.65646 5.99838 9.47459 5.99838 9.28494C5.99838 9.0953 6.07749 8.91342 6.2183 8.77932L9.43845 5.71416L0.749916 5.71416C0.551026 5.71416 0.360281 5.63891 0.219644 5.50498C0.0790079 5.37105 -3.2717e-07 5.18941 -3.2717e-07 5Z"
/>
</svg>
);
}

View File

@@ -0,0 +1,64 @@
import classNames from 'classnames';
import { useMemo } from 'react';
export function BatteryIcon({
value,
disabled = false,
}: {
value: number;
disabled?: boolean;
}) {
const col = useMemo(() => {
const colorsMap: { [key: number]: string } = {
0.4: 'fill-status-success',
0.2: 'fill-status-warning',
0: 'fill-status-critical',
};
const val = Object.keys(colorsMap)
.filter((key) => +key < value)
.sort((a, b) => +b - +a)[0];
return disabled
? 'fill-background-40'
: colorsMap[+val] || 'fill-background-10';
}, [value, disabled]);
return (
<svg
width="19"
height="9"
viewBox="0 0 19 9"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M11.0833 0H1.31203C0.995003 0.00131561 0.691347 0.121213 0.467167 0.333594C0.242986 0.545976 0.116428 0.83365 0.115039 1.134V7.383C0.114754 7.68458 0.240506 7.97399 0.464808 8.18799C0.689109 8.40198 0.993714 8.52315 1.31203 8.525H11.0833V0Z"
fill="#3D6381"
/>
<path
d="M15.0005 8.525C15.3175 8.52368 15.6212 8.40379 15.8454 8.19141C16.0696 7.97902 16.1961 7.69135 16.1975 7.391V5.968H17.9972V2.558H16.1975V1.134C16.1961 0.83365 16.0696 0.545976 15.8454 0.333594C15.6212 0.121213 15.3175 0.00131561 15.0005 0H10.9672V8.525H15.0005Z"
fill="#3D6381"
/>
<mask
id="mask0_4_39"
style={{ maskType: 'alpha' }}
maskUnits="userSpaceOnUse"
x="0"
y="0"
width="18"
height="9"
>
<path
d="M11.0833 0H1.31203C0.995003 0.00131561 0.691347 0.121213 0.467167 0.333594C0.242986 0.545976 0.116428 0.83365 0.115039 1.134V7.383C0.114754 7.68458 0.240506 7.97399 0.464808 8.18799C0.689109 8.40198 0.993714 8.52315 1.31203 8.525H11.0833V0Z"
fill="#3D6381"
/>
<path
d="M15.0005 8.525C15.3175 8.52368 15.6212 8.40379 15.8454 8.19141C16.0696 7.97902 16.1961 7.69135 16.1975 7.391V5.968H17.9972V2.558H16.1975V1.134C16.1961 0.83365 16.0696 0.545976 15.8454 0.333594C15.6212 0.121213 15.3175 0.00131561 15.0005 0H10.9672V8.525H15.0005Z"
fill="#3D6381"
/>
</mask>
<g mask="url(#mask0_4_39)" className={classNames(col, 'opacity-100')}>
<rect width={value * 18} height="9" />
</g>
</svg>
);
}

View File

@@ -0,0 +1,12 @@
export function BulbIcon() {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width={20}
height={20}
viewBox="0 0 352 512"
>
<path d="M96.06 454.35c.01 6.29 1.87 12.45 5.36 17.69l17.09 25.69a31.99 31.99 0 0 0 26.64 14.28h61.71a31.99 31.99 0 0 0 26.64-14.28l17.09-25.69a31.989 31.989 0 0 0 5.36-17.69l.04-38.35H96.01l.05 38.35zM0 176c0 44.37 16.45 84.85 43.56 115.78 16.52 18.85 42.36 58.23 52.21 91.45.04.26.07.52.11.78h160.24c.04-.26.07-.51.11-.78 9.85-33.22 35.69-72.6 52.21-91.45C335.55 260.85 352 220.37 352 176 352 78.61 272.91-.3 175.45 0 73.44.31 0 82.97 0 176zm176-80c-44.11 0-80 35.89-80 80 0 8.84-7.16 16-16 16s-16-7.16-16-16c0-61.76 50.24-112 112-112 8.84 0 16 7.16 16 16s-7.16 16-16 16z" />
</svg>
);
}

View File

@@ -0,0 +1,19 @@
export function CheckIcon(props: any) {
return (
<svg
width="9"
height="7"
viewBox="0 0 9 7"
xmlns="http://www.w3.org/2000/svg"
>
<g clipPath="url(#clip0_548_761)">
<path d="M3.05666 6.86296L0.132685 3.81321C0.0906355 3.76962 0.0572652 3.71778 0.034494 3.66068C0.0117228 3.60358 0 3.54235 0 3.48051C0 3.41867 0.0117228 3.35744 0.034494 3.30035C0.0572652 3.24325 0.0906355 3.19141 0.132685 3.14781L0.770644 2.48241C0.812442 2.43856 0.862143 2.40375 0.916885 2.38C0.971628 2.35625 1.03033 2.34402 1.08962 2.34402C1.14891 2.34402 1.20762 2.35625 1.26236 2.38C1.3171 2.40375 1.3668 2.43856 1.4086 2.48241L3.37883 4.53739L7.59946 0.135219C7.64126 0.0913603 7.69096 0.0565546 7.7457 0.0328039C7.80044 0.00905319 7.85915 -0.00317383 7.91844 -0.00317383C7.97773 -0.00317383 8.03643 0.00905319 8.09117 0.0328039C8.14592 0.0565546 8.19562 0.0913603 8.23742 0.135219L8.87537 0.800618C8.91742 0.844214 8.95079 0.896052 8.97357 0.95315C8.99634 1.01025 9.00806 1.07148 9.00806 1.13332C9.00806 1.19516 8.99634 1.25639 8.97357 1.31349C8.95079 1.37058 8.91742 1.42242 8.87537 1.46602L3.69303 6.86296C3.65126 6.90657 3.60166 6.94116 3.54706 6.96477C3.49246 6.98837 3.43394 7.00052 3.37484 7.00052C3.31574 7.00052 3.25722 6.98837 3.20263 6.96477C3.14803 6.94116 3.09843 6.90657 3.05666 6.86296Z" />
</g>
<defs>
<clipPath id="clip0_548_761">
<rect width="9" height="7" />
</clipPath>
</defs>
</svg>
);
}

View File

@@ -0,0 +1,13 @@
export function CircleIcon(props: any) {
return (
<svg
{...props}
width="10"
height="10"
viewBox="0 0 6 6"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M3 6C4.65685 6 6 4.65685 6 3C6 1.34315 4.65685 0 3 0C1.34315 0 0 1.34315 0 3C0 4.65685 1.34315 6 3 6Z" />
</svg>
);
}

View File

@@ -0,0 +1,29 @@
export function CloseIcon({
className,
size = 35,
}: {
className?: string;
size?: number;
}) {
return (
<svg
width={size}
height={size}
className={className}
viewBox="0 0 31 29"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M19.3804 17.8804L12.619 11.119"
stroke="#C0A1D8"
strokeLinecap="round"
/>
<path
d="M12.6196 17.8804L19.381 11.119"
stroke="#C0A1D8"
strokeLinecap="round"
/>
</svg>
);
}

View File

@@ -0,0 +1,11 @@
export function CrossIcon() {
return (
<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
<path
fillRule="evenodd"
d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z"
clipRule="evenodd"
></path>
</svg>
);
}

View File

@@ -0,0 +1,15 @@
export function CubeIcon(props: any) {
return (
<svg
{...props}
width="20"
height="20"
viewBox="0 0 16 16"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M14.835 3.752L8.377 0.852002C8.31295 0.823464 8.24362 0.808716 8.1735 0.808716C8.10338 0.808716 8.03405 0.823464 7.97 0.852002L1.509 3.752C1.45917 3.77586 1.4169 3.81302 1.38684 3.85938C1.35678 3.90573 1.34011 3.95949 1.33867 4.01472C1.33722 4.06995 1.35105 4.12451 1.37863 4.17237C1.40622 4.22024 1.44649 4.25956 1.495 4.286L7.938 7.679C8.00997 7.71812 8.09058 7.73862 8.1725 7.73862C8.25442 7.73862 8.33503 7.71812 8.407 7.679L14.85 4.286C14.8985 4.25947 14.9387 4.22008 14.9662 4.17215C14.9937 4.12423 15.0074 4.06964 15.0059 4.01441C15.0043 3.95918 14.9875 3.90545 14.9574 3.85915C14.9272 3.81284 14.8849 3.77577 14.835 3.752Z" />
<path d="M9.04301 15.774L15.537 12.338C15.5774 12.3112 15.6104 12.2748 15.6331 12.232C15.6558 12.1892 15.6674 12.1414 15.667 12.093V5.429C15.6697 5.38221 15.6601 5.33552 15.6392 5.29359C15.6182 5.25166 15.5867 5.21596 15.5476 5.19006C15.5085 5.16415 15.4634 5.14894 15.4166 5.14595C15.3698 5.14296 15.3231 5.15228 15.281 5.173L8.78701 8.519C8.74073 8.54365 8.70214 8.58059 8.6755 8.62576C8.64886 8.67092 8.63519 8.72257 8.63601 8.775V15.529C8.63442 15.5774 8.64577 15.6253 8.6689 15.6679C8.69203 15.7104 8.7261 15.746 8.76758 15.771C8.80907 15.796 8.85647 15.8094 8.90489 15.8099C8.95331 15.8105 9.00099 15.7981 9.04301 15.774Z" />
<path d="M0.67101 5.428V12.088C0.670579 12.1364 0.682243 12.1842 0.704943 12.227C0.727644 12.2698 0.760664 12.3062 0.80101 12.333L7.29601 15.769C7.33755 15.7933 7.38493 15.8059 7.43307 15.8055C7.48122 15.805 7.52834 15.7915 7.5694 15.7663C7.61046 15.7412 7.64392 15.7053 7.66622 15.6627C7.68851 15.62 7.69881 15.5721 7.69601 15.524V8.771C7.69683 8.71856 7.68317 8.66692 7.65652 8.62175C7.62988 8.57659 7.59129 8.53965 7.54501 8.515L1.05501 5.169C1.01276 5.14923 0.966102 5.14076 0.919596 5.14439C0.87309 5.14802 0.828319 5.16364 0.789646 5.18973C0.750973 5.21581 0.719718 5.25147 0.698927 5.29323C0.678135 5.33498 0.668517 5.38142 0.67101 5.428Z" />
</svg>
);
}

View File

@@ -0,0 +1,12 @@
export function EyeIcon() {
return (
<svg
width="14"
height="10"
viewBox="0 0 14 10"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M9.09817 4.99914C9.09817 6.11133 8.15709 7.01294 6.9962 7.01294C5.83532 7.01294 4.89424 6.11133 4.89424 4.99914C4.89424 3.88693 5.83532 2.98533 6.9962 2.98533C8.15709 2.98532 9.09817 3.88694 9.09817 4.99914ZM7 0.806091C5.79804 0.811423 4.55217 1.10403 3.37279 1.66426C2.49711 2.09735 1.64372 2.70838 0.90293 3.46257C0.539093 3.84756 0.0750283 4.40501 0 4.99979C0.00886667 5.515 0.561517 6.15093 0.90293 6.53703C1.5976 7.2616 2.42877 7.85557 3.37279 8.33578C4.47262 8.86954 5.68997 9.17685 7 9.19395C8.2031 9.18853 9.44869 8.89255 10.6268 8.33578C11.5024 7.90269 12.3563 7.29122 13.0971 6.53703C13.4609 6.15204 13.925 5.59457 14 4.99979C13.9911 4.48458 13.4385 3.84863 13.0971 3.46254C12.4024 2.73797 11.5708 2.14446 10.6268 1.66423C9.52751 1.13088 8.30716 0.82568 7 0.806091ZM6.99911 1.84732C8.8205 1.84732 10.297 3.25891 10.297 5.00025C10.297 6.74157 8.8205 8.15316 6.99911 8.15316C5.17773 8.15316 3.70124 6.74156 3.70124 5.00025C3.70124 3.25891 5.17773 1.84732 6.99911 1.84732Z" />
</svg>
);
}

View File

@@ -0,0 +1,12 @@
export function FootIcon({ width }: { width?: number }) {
return (
<svg
width={width || 28}
viewBox="0 0 28 28"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="28" height="28" rx="2" fill="#56407B" />
<path d="M18.5981 6.05798L18.1461 7.57104C18.0991 7.72904 18.0361 7.92496 18.0061 8.00696C17.8731 8.3476 17.7678 8.69847 17.6911 9.05603C17.6078 9.35662 17.595 9.67231 17.6538 9.97864C17.7126 10.285 17.8414 10.5737 18.0301 10.822C18.0651 10.866 18.2771 11.2161 18.5031 11.6021C18.7291 11.9881 18.9321 12.3339 18.9581 12.3719C19.0375 12.4967 19.1065 12.6279 19.1641 12.764C19.2954 13.1107 19.3199 13.4887 19.2346 13.8494C19.1492 14.2101 18.9578 14.5369 18.6851 14.788C18.3588 15.1236 17.9785 15.4021 17.5601 15.6119C16.885 15.93 16.3258 16.4504 15.9601 17.101C15.8219 17.345 15.6665 17.579 15.4951 17.801C15.3751 17.967 15.1531 18.292 15.0011 18.524C14.7241 18.945 14.5201 19.2441 14.3791 19.4301C14.0713 19.8357 13.7085 20.1964 13.3011 20.502L12.9011 20.796C12.4511 21.131 12.4491 21.132 12.2011 21.146C12.0364 21.1349 11.8735 21.1855 11.7441 21.288C11.6483 21.3637 11.5381 21.4192 11.4201 21.451C11.3022 21.4829 11.179 21.4904 11.0581 21.473C10.8581 21.473 10.8231 21.4731 10.7951 21.451C10.7435 21.4122 10.7026 21.3609 10.6761 21.302C10.6746 21.2885 10.6682 21.276 10.6581 21.267C10.6411 21.254 10.6301 21.26 10.5821 21.306C10.5023 21.376 10.4081 21.4276 10.3061 21.457C10.2078 21.4797 10.1066 21.4871 10.0061 21.479H9.7921L9.7121 21.438C9.67073 21.4185 9.63235 21.3933 9.5981 21.363L9.5641 21.328H9.3391C9.0311 21.328 8.9941 21.32 8.8991 21.228C8.84921 21.1797 8.79222 21.1392 8.7301 21.108C8.61137 21.0413 8.50891 20.9491 8.4301 20.838C8.41279 20.7935 8.40728 20.7453 8.4141 20.698L8.4201 20.604L8.5061 20.515C8.5961 20.423 8.6061 20.39 8.5811 20.337C8.53854 20.293 8.48119 20.2662 8.4201 20.262C8.32553 20.2388 8.24225 20.1828 8.1851 20.104C8.09834 20.0317 8.03903 19.9318 8.0171 19.821C7.98191 19.6196 8.00125 19.4124 8.0731 19.2209C8.1321 19.0639 8.1321 19.064 8.3671 19.063C8.57004 19.0815 8.77415 19.0437 8.9571 18.954C9.02435 18.9097 9.10263 18.8851 9.1831 18.8829C9.2331 18.8829 9.2711 18.862 9.5831 18.671C9.83458 18.5055 10.1027 18.3666 10.3831 18.257L10.4881 18.223L10.5591 18.0229C10.7588 17.4891 10.9019 16.9357 10.9861 16.3719C11.0496 15.9465 11.1422 15.5259 11.2631 15.113C11.3728 14.7304 11.5064 14.355 11.6631 13.989C12.0182 13.0652 12.2417 12.096 12.3271 11.11C12.3801 10.764 12.4431 10.3661 12.4661 10.2271C12.4891 10.0881 12.5171 9.89894 12.5281 9.80994C12.5391 9.72094 12.5631 9.51606 12.5821 9.35706C12.6011 9.19806 12.6291 8.96499 12.6421 8.83899C12.6551 8.71299 12.6771 8.51101 12.6901 8.38501C12.7441 7.88501 12.8191 7.11596 12.8711 6.53796C12.8901 6.31196 12.9111 6.09799 12.9151 6.06299L12.9221 6H18.6161L18.5981 6.05798Z" />
</svg>
);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,12 @@
export function GearIcon() {
return (
<svg
width="20"
height="20"
viewBox="0 0 14 13"
xmlns="http://www.w3.org/2000/svg"
>
<path d="M7.00099 11.9C7.31948 11.9003 7.63041 11.997 7.89283 12.1775C8.15524 12.3579 8.35682 12.6137 8.47099 12.911C9.11419 12.757 9.72885 12.5018 10.292 12.155C10.2026 11.9531 10.1559 11.7348 10.155 11.514C10.1546 11.2516 10.2198 10.9933 10.3448 10.7626C10.4697 10.5319 10.6505 10.3362 10.8705 10.1932C11.0905 10.0503 11.3427 9.96464 11.6043 9.94417C11.8659 9.92369 12.1284 9.96902 12.368 10.076C12.7147 9.51424 12.9699 8.90091 13.124 8.259C12.8268 8.1447 12.5711 7.9431 12.3906 7.68071C12.2102 7.41833 12.1134 7.10745 12.113 6.789C12.1134 6.47055 12.2102 6.15968 12.3906 5.89729C12.5711 5.6349 12.8268 5.4333 13.124 5.319C12.97 4.6758 12.7148 4.06115 12.368 3.498C12.1284 3.60499 11.8659 3.65031 11.6043 3.62983C11.3427 3.60936 11.0905 3.52374 10.8705 3.38078C10.6505 3.23782 10.4697 3.04207 10.3448 2.81138C10.2198 2.58068 10.1546 2.32237 10.155 2.06C10.1543 1.83899 10.201 1.62041 10.292 1.419C9.72669 1.07498 9.11135 0.820948 8.46799 0.666C8.35405 0.963474 8.15253 1.21938 7.89007 1.39989C7.6276 1.5804 7.31654 1.67703 6.99799 1.677C6.67886 1.67742 6.36711 1.581 6.10393 1.40049C5.84075 1.21998 5.63853 0.963872 5.52399 0.666C4.882 0.821335 4.26872 1.07752 3.70699 1.425C3.83599 1.71551 3.87394 2.03828 3.81586 2.35079C3.75778 2.66329 3.60638 2.95087 3.38162 3.17563C3.15686 3.40039 2.86928 3.55178 2.55678 3.60987C2.24427 3.66795 1.9215 3.62999 1.63099 3.501C1.28471 4.06442 1.02957 4.67899 0.874993 5.322C1.17184 5.43574 1.42719 5.63685 1.60733 5.89878C1.78746 6.1607 1.8839 6.47111 1.8839 6.789C1.8839 7.10689 1.78746 7.4173 1.60733 7.67922C1.42719 7.94115 1.17184 8.14226 0.874993 8.256C1.02899 8.8992 1.28417 9.51385 1.63099 10.077C1.92149 9.94858 2.24405 9.91106 2.55627 9.96935C2.86849 10.0276 3.15577 10.179 3.38036 10.4036C3.60495 10.6282 3.75634 10.9155 3.81464 11.2277C3.87294 11.5399 3.83541 11.8625 3.70699 12.153C4.26924 12.4985 4.88243 12.7533 5.52399 12.908C5.6399 12.6107 5.84296 12.3554 6.10653 12.1755C6.37011 11.9956 6.68189 11.8996 7.00099 11.9ZM4.45399 6.817C4.4536 6.31238 4.60287 5.81897 4.88294 5.3992C5.16301 4.97942 5.56128 4.65214 6.02738 4.45876C6.49348 4.26537 7.00646 4.21457 7.50144 4.31277C7.99642 4.41098 8.45115 4.65378 8.80811 5.01046C9.16508 5.36715 9.40824 5.82169 9.50683 6.31659C9.60542 6.81149 9.55502 7.32451 9.362 7.79076C9.16898 8.25701 8.84201 8.65554 8.42246 8.93594C8.00291 9.21634 7.50962 9.366 7.00499 9.366C6.67012 9.36613 6.3385 9.3003 6.02907 9.17228C5.71964 9.04425 5.43846 8.85653 5.20158 8.61983C4.96469 8.38313 4.77675 8.1021 4.64848 7.79277C4.52021 7.48344 4.45412 7.15187 4.45399 6.817Z" />
</svg>
);
}

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