Compare commits

...
12 Commits
15 changed files with 321 additions and 120 deletions

No files matched your search

+25 -25
View File
@@ -8,7 +8,7 @@
"@fortawesome/fontawesome-svg-core": "7.1.0", "@fortawesome/fontawesome-svg-core": "7.1.0",
"@fortawesome/free-brands-svg-icons": "7.1.0", "@fortawesome/free-brands-svg-icons": "7.1.0",
"@fortawesome/free-solid-svg-icons": "7.1.0", "@fortawesome/free-solid-svg-icons": "7.1.0",
"@fortawesome/react-fontawesome": "3.1.1", "@fortawesome/react-fontawesome": "3.2.0",
"@tauri-apps/api": "2.10.1", "@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2", "@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-dialog": "2.6.0", "@tauri-apps/plugin-dialog": "2.6.0",
@@ -17,7 +17,7 @@
"@tauri-apps/plugin-opener": "2.5.3", "@tauri-apps/plugin-opener": "2.5.3",
"@tauri-apps/plugin-os": "2.3.2", "@tauri-apps/plugin-os": "2.3.2",
"@tauri-apps/plugin-window-state": "2.4.1", "@tauri-apps/plugin-window-state": "2.4.1",
"axios": "1.13.4", "axios": "1.13.5",
"next": "16.1.6", "next": "16.1.6",
"pretty-bytes": "7.1.0", "pretty-bytes": "7.1.0",
"react": "19.2.4", "react": "19.2.4",
@@ -28,8 +28,8 @@
"@tailwindcss/postcss": "4.1.18", "@tailwindcss/postcss": "4.1.18",
"@tauri-apps/cli": "2.10.0", "@tauri-apps/cli": "2.10.0",
"@types/crypto-js": "4.2.2", "@types/crypto-js": "4.2.2",
"@types/node": "25.2.0", "@types/node": "25.2.2",
"@types/react": "19.2.10", "@types/react": "19.2.13",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"eslint": "9.39.2", "eslint": "9.39.2",
@@ -48,7 +48,7 @@
"@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="], "@babel/core": ["@babel/core@7.29.0", "", { "dependencies": { "@babel/code-frame": "^7.29.0", "@babel/generator": "^7.29.0", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", "@babel/helpers": "^7.28.6", "@babel/parser": "^7.29.0", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/remapping": "^2.3.5", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", "semver": "^6.3.1" } }, "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA=="],
"@babel/generator": ["@babel/generator@7.29.0", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-vSH118/wwM/pLR38g/Sgk05sNtro6TlTJKuiMXDaZqPUfjTFcudpCOt00IhOfj+1BFAX+UFAlzCU+6WXr3GLFQ=="], "@babel/generator": ["@babel/generator@7.29.1", "", { "dependencies": { "@babel/parser": "^7.29.0", "@babel/types": "^7.29.0", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" } }, "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw=="],
"@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="], "@babel/helper-compilation-targets": ["@babel/helper-compilation-targets@7.28.6", "", { "dependencies": { "@babel/compat-data": "^7.28.6", "@babel/helper-validator-option": "^7.27.1", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" } }, "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA=="],
@@ -106,7 +106,7 @@
"@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@7.1.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" } }, "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA=="], "@fortawesome/free-solid-svg-icons": ["@fortawesome/free-solid-svg-icons@7.1.0", "", { "dependencies": { "@fortawesome/fontawesome-common-types": "7.1.0" } }, "sha512-Udu3K7SzAo9N013qt7qmm22/wo2hADdheXtBfxFTecp+ogsc0caQNRKEb7pkvvagUGOpG9wJC1ViH6WXs8oXIA=="],
"@fortawesome/react-fontawesome": ["@fortawesome/react-fontawesome@3.1.1", "", { "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~6 || ~7", "react": "^18.0.0 || ^19.0.0" } }, "sha512-EDllr9hpodc21odmUywHS1alXNiCd4E8sp5GJ5s7wYINz8vSmMiNWpALTiuYODb865YyQ/NlyiN4mbXp7HCNqg=="], "@fortawesome/react-fontawesome": ["@fortawesome/react-fontawesome@3.2.0", "", { "peerDependencies": { "@fortawesome/fontawesome-svg-core": "~6 || ~7", "react": "^18.0.0 || ^19.0.0" } }, "sha512-E9Gu1hqd6JussVO26EC4WqRZssXMnQr2ol7ZNWkkFOH8jZUaxDJ9Z9WF9wIVkC+kJGXUdY3tlffpDwEKfgQrQw=="],
"@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="], "@humanfs/core": ["@humanfs/core@0.19.1", "", {}, "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA=="],
@@ -290,31 +290,31 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="], "@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/node": ["@types/node@25.2.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-DZ8VwRFUNzuqJ5khrvwMXHmvPe+zGayJhr2CDNiKB1WBE1ST8Djl00D0IC4vvNmHMdj6DlbYRIaFE7WHjlDl5w=="], "@types/node": ["@types/node@25.2.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-BkmoP5/FhRYek5izySdkOneRyXYN35I860MFAGupTdebyE66uZaR+bXLHq8k4DirE5DwQi3NuhvRU1jqTVwUrQ=="],
"@types/react": ["@types/react@19.2.10", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-WPigyYuGhgZ/cTPRXB2EwUw+XvsRA3GqHlsP4qteqrnnjDrApbS7MxcGr/hke5iUoeB7E/gQtrs9I37zAJ0Vjw=="], "@types/react": ["@types/react@19.2.13", "", { "dependencies": { "csstype": "^3.2.2" } }, "sha512-KkiJeU6VbYbUOp5ITMIc7kBfqlYkKA5KhEHVrGMmUUMt7NeaZg65ojdPk+FtNrBAOXNVM5QM72jnADjM+XVRAQ=="],
"@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="], "@types/react-dom": ["@types/react-dom@19.2.3", "", { "peerDependencies": { "@types/react": "^19.2.0" } }, "sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ=="],
"@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.54.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/type-utils": "8.54.0", "@typescript-eslint/utils": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.54.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ=="], "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.55.0", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/type-utils": "8.55.0", "@typescript-eslint/utils": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.55.0", "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1y/MVSz0NglV1ijHC8OT49mPJ4qhPYjiK08YUQVbIOyu+5k862LKUHFkpKHWu//zmr7hDR2rhwUm6gnCGNmGBQ=="],
"@typescript-eslint/parser": ["@typescript-eslint/parser@8.54.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA=="], "@typescript-eslint/parser": ["@typescript-eslint/parser@8.55.0", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-4z2nCSBfVIMnbuu8uinj+f0o4qOeggYJLbjpPHka3KH1om7e+H9yLKTYgksTaHcGco+NClhhY2vyO3HsMH1RGw=="],
"@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.54.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.54.0", "@typescript-eslint/types": "^8.54.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g=="], "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.55.0", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.55.0", "@typescript-eslint/types": "^8.55.0", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-zRcVVPFUYWa3kNnjaZGXSu3xkKV1zXy8M4nO/pElzQhFweb7PPtluDLQtKArEOGmjXoRjnUZ29NjOiF0eCDkcQ=="],
"@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0" } }, "sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg=="], "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.55.0", "", { "dependencies": { "@typescript-eslint/types": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0" } }, "sha512-fVu5Omrd3jeqeQLiB9f1YsuK/iHFOwb04bCtY4BSCLgjNbOD33ZdV6KyEqplHr+IlpgT0QTZ/iJ+wT7hvTx49Q=="],
"@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.54.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw=="], "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.55.0", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-1R9cXqY7RQd7WuqSN47PK9EDpgFUK3VqdmbYrvWJZYDd0cavROGn+74ktWBlmJ13NXUQKlZ/iAEQHI/V0kKe0Q=="],
"@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA=="], "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.55.0", "", { "dependencies": { "@typescript-eslint/types": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/utils": "8.55.0", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-x1iH2unH4qAt6I37I2CGlsNs+B9WGxurP2uyZLRz6UJoZWDBx9cJL1xVN/FiOmHEONEg6RIufdvyT0TEYIgC5g=="],
"@typescript-eslint/types": ["@typescript-eslint/types@8.54.0", "", {}, "sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA=="], "@typescript-eslint/types": ["@typescript-eslint/types@8.55.0", "", {}, "sha512-ujT0Je8GI5BJWi+/mMoR0wxwVEQaxM+pi30xuMiJETlX80OPovb2p9E8ss87gnSVtYXtJoU9U1Cowcr6w2FE0w=="],
"@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.54.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.54.0", "@typescript-eslint/tsconfig-utils": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/visitor-keys": "8.54.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA=="], "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.55.0", "", { "dependencies": { "@typescript-eslint/project-service": "8.55.0", "@typescript-eslint/tsconfig-utils": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/visitor-keys": "8.55.0", "debug": "^4.4.3", "minimatch": "^9.0.5", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-EwrH67bSWdx/3aRQhCoxDaHM+CrZjotc2UCCpEDVqfCE+7OjKAGWNY2HsCSTEVvWH2clYQK8pdeLp42EVs+xQw=="],
"@typescript-eslint/utils": ["@typescript-eslint/utils@8.54.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.54.0", "@typescript-eslint/types": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA=="], "@typescript-eslint/utils": ["@typescript-eslint/utils@8.55.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.55.0", "@typescript-eslint/types": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-BqZEsnPGdYpgyEIkDC1BadNY8oMwckftxBT+C8W0g1iKPdeqKZBtTfnvcq0nf60u7MkjFO8RBvpRGZBPw4L2ow=="],
"@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.54.0", "", { "dependencies": { "@typescript-eslint/types": "8.54.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA=="], "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.55.0", "", { "dependencies": { "@typescript-eslint/types": "8.55.0", "eslint-visitor-keys": "^4.2.1" } }, "sha512-AxNRwEie8Nn4eFS1FzDMJWIISMGoXMb037sgCBJ3UR6o0fQTzr2tqN9WT+DkWJPhIdQCfV7T6D387566VtnCJA=="],
"@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="], "@unrs/resolver-binding-android-arm-eabi": ["@unrs/resolver-binding-android-arm-eabi@1.11.1", "", { "os": "android", "cpu": "arm" }, "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw=="],
@@ -392,7 +392,7 @@
"axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="], "axe-core": ["axe-core@4.11.1", "", {}, "sha512-BASOg+YwO2C+346x3LZOeoovTIoTrRqEsqMa6fmfAV0P+U9mFr9NsyOEpiYvFjbc64NMrSswhV50WdXzdb/Z5A=="],
"axios": ["axios@1.13.4", "", { "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.4", "proxy-from-env": "^1.1.0" } }, "sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg=="], "axios": ["axios@1.13.5", "", { "dependencies": { "follow-redirects": "^1.15.11", "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q=="],
"axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="], "axobject-query": ["axobject-query@4.1.0", "", {}, "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ=="],
@@ -414,7 +414,7 @@
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="], "callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001767", "", {}, "sha512-34+zUAMhSH+r+9eKmYG+k2Rpt8XttfE4yXAjoZvkAPs15xcYQhyBYdalJ65BzivAvGRMViEjy6oKr/S91loekQ=="], "caniuse-lite": ["caniuse-lite@1.0.30001769", "", {}, "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
@@ -562,7 +562,7 @@
"get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="], "get-symbol-description": ["get-symbol-description@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.6" } }, "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg=="],
"get-tsconfig": ["get-tsconfig@4.13.1", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-EoY1N2xCn44xU6750Sx7OjOIT59FkmstNc3X6y5xpz7D5cBtZRe/3pSlTkDJgqsOk3WwZPkWfonhhUJfttQo3w=="], "get-tsconfig": ["get-tsconfig@4.13.6", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw=="],
"glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="], "glob-parent": ["glob-parent@6.0.2", "", { "dependencies": { "is-glob": "^4.0.3" } }, "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="],
@@ -900,7 +900,7 @@
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
"typescript-eslint": ["typescript-eslint@8.54.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.54.0", "@typescript-eslint/parser": "8.54.0", "@typescript-eslint/typescript-estree": "8.54.0", "@typescript-eslint/utils": "8.54.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ=="], "typescript-eslint": ["typescript-eslint@8.55.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.55.0", "@typescript-eslint/parser": "8.55.0", "@typescript-eslint/typescript-estree": "8.55.0", "@typescript-eslint/utils": "8.55.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-HE4wj+r5lmDVS9gdaN0/+iqNvPZwGfnJ5lZuz7s5vLlg9ODw0bIiiETaios9LvFI1U94/VBXGm3CB2Y5cNFMpw=="],
"unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="], "unbox-primitive": ["unbox-primitive@1.1.0", "", { "dependencies": { "call-bound": "^1.0.3", "has-bigints": "^1.0.2", "has-symbols": "^1.1.0", "which-boxed-primitive": "^1.1.1" } }, "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw=="],
@@ -952,7 +952,7 @@
"@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="], "@typescript-eslint/typescript-estree/minimatch": ["minimatch@9.0.5", "", { "dependencies": { "brace-expansion": "^2.0.1" } }, "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow=="],
"@typescript-eslint/typescript-estree/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "@typescript-eslint/typescript-estree/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"eslint-config-next/globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="], "eslint-config-next/globals": ["globals@16.4.0", "", {}, "sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw=="],
@@ -966,13 +966,13 @@
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="], "fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
"is-bun-module/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "is-bun-module/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="], "micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
"next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="], "next/postcss": ["postcss@8.4.31", "", { "dependencies": { "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" } }, "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ=="],
"sharp/semver": ["semver@7.7.3", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q=="], "sharp/semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
"@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="], "@typescript-eslint/typescript-estree/minimatch/brace-expansion": ["brace-expansion@2.0.2", "", { "dependencies": { "balanced-match": "^1.0.0" } }, "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ=="],
} }
File renamed without changes.
+5 -5
View File
@@ -1,7 +1,7 @@
{ {
"name": "lncvrt-games-launcher", "name": "lncvrt-games-launcher",
"private": true, "private": true,
"version": "1.5.5", "version": "1.5.7",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "next dev", "dev": "next dev",
@@ -14,7 +14,7 @@
"@fortawesome/fontawesome-svg-core": "7.1.0", "@fortawesome/fontawesome-svg-core": "7.1.0",
"@fortawesome/free-brands-svg-icons": "7.1.0", "@fortawesome/free-brands-svg-icons": "7.1.0",
"@fortawesome/free-solid-svg-icons": "7.1.0", "@fortawesome/free-solid-svg-icons": "7.1.0",
"@fortawesome/react-fontawesome": "3.1.1", "@fortawesome/react-fontawesome": "3.2.0",
"@tauri-apps/api": "2.10.1", "@tauri-apps/api": "2.10.1",
"@tauri-apps/plugin-clipboard-manager": "2.3.2", "@tauri-apps/plugin-clipboard-manager": "2.3.2",
"@tauri-apps/plugin-dialog": "2.6.0", "@tauri-apps/plugin-dialog": "2.6.0",
@@ -23,7 +23,7 @@
"@tauri-apps/plugin-opener": "2.5.3", "@tauri-apps/plugin-opener": "2.5.3",
"@tauri-apps/plugin-os": "2.3.2", "@tauri-apps/plugin-os": "2.3.2",
"@tauri-apps/plugin-window-state": "2.4.1", "@tauri-apps/plugin-window-state": "2.4.1",
"axios": "1.13.4", "axios": "1.13.5",
"next": "16.1.6", "next": "16.1.6",
"pretty-bytes": "7.1.0", "pretty-bytes": "7.1.0",
"react": "19.2.4", "react": "19.2.4",
@@ -34,8 +34,8 @@
"@tailwindcss/postcss": "4.1.18", "@tailwindcss/postcss": "4.1.18",
"@tauri-apps/cli": "2.10.0", "@tauri-apps/cli": "2.10.0",
"@types/crypto-js": "4.2.2", "@types/crypto-js": "4.2.2",
"@types/node": "25.2.0", "@types/node": "25.2.2",
"@types/react": "19.2.10", "@types/react": "19.2.13",
"@types/react-dom": "19.2.3", "@types/react-dom": "19.2.3",
"crypto-js": "4.2.0", "crypto-js": "4.2.0",
"eslint": "9.39.2", "eslint": "9.39.2",
+8 -8
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "lncvrt-games-launcher" name = "lncvrt-games-launcher"
version = "1.5.5" version = "1.5.7"
authors = ["Lncvrt"] authors = ["Lncvrt"]
edition = "2024" edition = "2024"
@@ -9,24 +9,24 @@ name = "lncvrt_games_launcher_lib"
crate-type = ["staticlib", "cdylib", "rlib"] crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.5.4", features = [] } tauri-build = { version = "2.5.5", features = [] }
[dependencies] [dependencies]
tauri = { version = "2.10.1", features = ["macos-private-api"] } tauri = { version = "2.10.2", features = ["macos-private-api"] }
tauri-plugin-opener = "2.5.3" tauri-plugin-opener = "2.5.3"
serde = { version = "1.0.228", features = ["derive"] } serde = { version = "1.0.228", features = ["derive"] }
serde_json = "1.0.149" serde_json = "1.0.149"
tauri-plugin-os = "2.3.2" tauri-plugin-os = "2.3.2"
reqwest = { version = "0.13.1", default-features = false, features = ["stream", "rustls"] } reqwest = { version = "0.13.2", default-features = false, features = ["stream", "rustls"] }
tokio = "1.49.0" tokio = "1.49.0"
futures-util = { version = "0.3.31", features = ["io"] } futures-util = { version = "0.3.31", features = ["io"] }
tauri-plugin-decorum = "1.1.1" tauri-plugin-decorum = "1.1.1"
tauri-plugin-fs = "2.4.5" tauri-plugin-fs = "2.4.5"
zip = "7.2.0" zip = "7.4.0"
libc = "0.2.180" libc = "0.2.181"
tauri-plugin-dialog = "2.6.0" tauri-plugin-dialog = "2.6.0"
tauri-plugin-notification = "2.3.3" tauri-plugin-notification = "2.3.3"
sysinfo = "0.38.0" sysinfo = "0.38.1"
sha2 = "0.10.9" sha2 = "0.10.9"
tauri-plugin-clipboard-manager = "2.3.2" tauri-plugin-clipboard-manager = "2.3.2"
@@ -34,7 +34,7 @@ tauri-plugin-clipboard-manager = "2.3.2"
shlex = "1.3.0" shlex = "1.3.0"
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] [target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
tauri-plugin-single-instance = "2.3.7" tauri-plugin-single-instance = "2.4.0"
tauri-plugin-window-state = "2.4.1" tauri-plugin-window-state = "2.4.1"
+31 -29
View File
@@ -22,6 +22,9 @@ use zip::ZipArchive;
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
use tauri_plugin_decorum::WebviewWindowExt; use tauri_plugin_decorum::WebviewWindowExt;
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;
#[allow(unused)] #[allow(unused)]
fn is_running_by_path(path: &Path) -> bool { fn is_running_by_path(path: &Path) -> bool {
let sys = System::new_all(); let sys = System::new_all();
@@ -37,23 +40,47 @@ fn is_running_by_path(path: &Path) -> bool {
}) })
} }
fn should_skip(name: &str) -> bool {
name.starts_with("__MACOSX/")
|| name == "__MACOSX"
|| name.ends_with("/.DS_Store")
|| name.ends_with(".DS_Store")
}
async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String { async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String {
let res = tauri::async_runtime::spawn_blocking(move || { let res = tauri::async_runtime::spawn_blocking(move || {
let file = File::open(zip_path)?; let file = File::open(zip_path)?;
let mut archive = ZipArchive::new(BufReader::new(file))?; let mut archive = ZipArchive::new(BufReader::new(file))?;
for i in 0..archive.len() { for i in 0..archive.len() {
let mut file = archive.by_index(i)?; let mut entry = archive.by_index(i)?;
let outpath = out_dir.join(file.name()); let name = entry.name();
if file.is_dir() { if should_skip(name) {
continue;
}
let outpath = out_dir.join(name);
if entry.is_dir() {
create_dir_all(&outpath)?; create_dir_all(&outpath)?;
#[cfg(unix)]
if let Some(mode) = entry.unix_mode() {
std::fs::set_permissions(&outpath, std::fs::Permissions::from_mode(mode))?;
}
} else { } else {
if let Some(parent) = outpath.parent() { if let Some(parent) = outpath.parent() {
create_dir_all(parent)?; create_dir_all(parent)?;
} }
let mut outfile = File::create(&outpath)?; let mut outfile = File::create(&outpath)?;
copy(&mut file, &mut outfile)?; copy(&mut entry, &mut outfile)?;
#[cfg(unix)]
if let Some(mode) = entry.unix_mode() {
std::fs::set_permissions(&outpath, std::fs::Permissions::from_mode(mode))?;
}
} }
} }
@@ -225,31 +252,6 @@ async fn download(
return "-1".to_string(); return "-1".to_string();
} }
#[cfg(any(target_os = "linux", target_os = "macos"))]
{
use std::{fs, os::unix::fs::PermissionsExt};
let executable_path = if cfg!(target_os = "linux") {
game_path.join(&name).join(&executable)
} else {
game_path
.join(&name)
.join(&executable)
.join("Contents")
.join("MacOS")
.join(
&executable
.chars()
.take(executable.chars().count() - 4)
.collect::<String>(),
)
};
let mut perms = fs::metadata(&executable_path).unwrap().permissions();
perms.set_mode(0o755);
fs::set_permissions(&executable_path, perms).unwrap();
}
return "1".to_string(); return "1".to_string();
} }
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.5.5", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.5.5", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.5.5", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher", "productName": "Lncvrt Games Launcher",
"version": "1.5.5", "version": "1.5.7",
"identifier": "xyz.lncvrt.games-launcher", "identifier": "xyz.lncvrt.games-launcher",
"build": { "build": {
"beforeDevCommand": "next dev", "beforeDevCommand": "next dev",
+19 -12
View File
@@ -1,6 +1,12 @@
'use client' 'use client'
import { createContext, useContext, ReactNode } from 'react' import {
createContext,
useContext,
ReactNode,
Dispatch,
SetStateAction
} from 'react'
import { DownloadProgress } from './types/DownloadProgress' import { DownloadProgress } from './types/DownloadProgress'
import { VersionsConfig } from './types/VersionsConfig' import { VersionsConfig } from './types/VersionsConfig'
import { NormalConfig } from './types/NormalConfig' import { NormalConfig } from './types/NormalConfig'
@@ -11,31 +17,32 @@ import { Game } from './types/Game'
type GlobalCtxType = { type GlobalCtxType = {
serverVersionList: ServerVersionsResponse | null serverVersionList: ServerVersionsResponse | null
selectedVersionList: string[] selectedVersionList: string[]
setSelectedVersionList: (v: string[]) => void setSelectedVersionList: (value: SetStateAction<string[]>) => void
downloadProgress: DownloadProgress[] downloadProgress: DownloadProgress[]
setDownloadProgress: (v: DownloadProgress[]) => void setDownloadProgress: Dispatch<SetStateAction<DownloadProgress[]>>
showPopup: boolean showPopup: boolean
setShowPopup: (v: boolean) => void setShowPopup: Dispatch<SetStateAction<boolean>>
popupMode: number | null popupMode: number | null
setPopupMode: (v: number | null) => void setPopupMode: Dispatch<SetStateAction<number | null>>
fadeOut: boolean fadeOut: boolean
setFadeOut: (v: boolean) => void setFadeOut: Dispatch<SetStateAction<boolean>>
downloadedVersionsConfig: VersionsConfig | null downloadedVersionsConfig: VersionsConfig | null
setDownloadedVersionsConfig: (v: VersionsConfig | null) => void setDownloadedVersionsConfig: Dispatch<SetStateAction<VersionsConfig | null>>
normalConfig: NormalConfig | null normalConfig: NormalConfig | null
setNormalConfig: (v: NormalConfig | null) => void setNormalConfig: Dispatch<SetStateAction<NormalConfig | null>>
managingVersion: string | null managingVersion: string | null
setManagingVersion: (v: string | null) => void setManagingVersion: Dispatch<SetStateAction<string | null>>
setSelectedGame: (v: number | null) => void setSelectedGame: Dispatch<SetStateAction<number | null>>
getVersionInfo: (id: string | undefined) => GameVersion | undefined getVersionInfo: (id: string | undefined) => GameVersion | undefined
getGameInfo: (id: number | undefined) => Game | undefined getGameInfo: (game: number | undefined) => Game | undefined
getListOfGames: () => Game[] getListOfGames(): Game[]
getVersionsAmountData: (gameId: number) => { getVersionsAmountData: (gameId: number) => {
installed: number installed: number
total: number total: number
} | null } | null
viewingInfoFromDownloads: boolean viewingInfoFromDownloads: boolean
version: string | null version: string | null
downloadVersions: (list: string[]) => Promise<void>
} }
const GlobalCtx = createContext<GlobalCtxType | null>(null) const GlobalCtx = createContext<GlobalCtxType | null>(null)
+4 -4
View File
@@ -23,13 +23,13 @@ export default function VersionInfo () {
viewingInfoFromDownloads, viewingInfoFromDownloads,
setPopupMode setPopupMode
} = useGlobal() } = useGlobal()
const [versionSize, setVersionSize] = useState<number | null>(null) const [versionSize, setVersionSize] = useState<number>(0)
useEffect(() => { useEffect(() => {
invoke<string>('folder_size', { invoke<string>('folder_size', {
version: managingVersion version: managingVersion
}).then(size => { }).then(size => {
setVersionSize(parseInt(size, 10)) setVersionSize(Number(size))
}) })
}, [managingVersion, setVersionSize]) }, [managingVersion, setVersionSize])
@@ -91,12 +91,12 @@ export default function VersionInfo () {
<FontAwesomeIcon icon={faHardDrive} color='lightgray' /> <FontAwesomeIcon icon={faHardDrive} color='lightgray' />
<p> <p>
Size on disk:{' '} Size on disk:{' '}
{versionSize !== null {versionSize > 0
? prettyBytes(versionSize, { ? prettyBytes(versionSize, {
minimumFractionDigits: 2, minimumFractionDigits: 2,
maximumFractionDigits: 2 maximumFractionDigits: 2
}) })
: 'Loading...'} : 'N/A'}
</p> </p>
</div> </div>
<div className='entry-info-item btntheme2' hidden={!versionInfo}> <div className='entry-info-item btntheme2' hidden={!versionInfo}>
+105
View File
@@ -0,0 +1,105 @@
'use client'
import { invoke } from '@tauri-apps/api/core'
import { useGlobal } from '../GlobalProvider'
import { BaseDirectory, exists, remove } from '@tauri-apps/plugin-fs'
import { writeVersionsConfig } from '../util/BazookaManager'
import { useState } from 'react'
export default function VersionUpdateWarning () {
const [confirmed, setConfirmed] = useState<-1 | 0>(-1)
const {
managingVersion,
setDownloadedVersionsConfig,
setManagingVersion,
setPopupMode,
setSelectedVersionList,
downloadVersions
} = useGlobal()
if (!managingVersion) return <p>Error</p>
return (
<>
<p className='text-xl text-center'>Warning!</p>
<div className='popup-content text-center p-2 relative'>
<p className='mb-2'>
Before proceeding, please note that any modifications to the
installation directory <b>(NOT THE SAVE DATA)</b> will be completely
wiped/reset.
</p>
<p>
If you do not want your installation directory wiped just yet, please
backup the files to another directory. When you click update, it will
be wiped.
</p>
<p className='my-2'>
Updating will have the same effect as clicking the uninstall button
then installing again.
</p>
<p>Revisions are not a frequent thing and rarely ever happen.</p>
<div className='flex flex-row gap-2 absolute bottom-2 left-1/2 -translate-x-1/2 w-max'>
<button
className='button btntheme2'
onClick={async () =>
invoke('open_folder', {
name: managingVersion
})
}
title="Click to browse the game's files."
>
Open Folder / Installation directory
</button>
<button
className='button btntheme2'
onClick={async () => {
if (confirmed == -1) {
setConfirmed(0)
return
}
//change popup to downloads
setManagingVersion(null)
setPopupMode(1)
//uninstall
setDownloadedVersionsConfig(prev => {
if (!prev) return prev
const updatedList = Object.fromEntries(
Object.entries(prev.list).filter(
([k]) => k !== managingVersion
)
)
const updatedConfig = {
...prev,
list: updatedList
}
writeVersionsConfig(updatedConfig)
return updatedConfig
})
if (
await exists('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + managingVersion, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
//reinstall
setSelectedVersionList([managingVersion])
downloadVersions([managingVersion])
}}
title='Click to update the game'
>
<span className='text-red-500 font-bold underline'>
{confirmed == -1 ? 'Update' : 'Are you sure?'}
</span>
</button>
</div>
</div>
</>
)
}
+89 -8
View File
@@ -45,6 +45,21 @@ export default function Installs () {
setCategory(-1) setCategory(-1)
} }
const needsRevisionUpdate = (
lastRevision: number | undefined,
version: string
) => {
if (!lastRevision) return false
return (
lastRevision > 0 &&
(downloadedVersionsConfig == undefined
? 0
: downloadedVersionsConfig?.list[version]) /
1000 <=
lastRevision
)
}
return ( return (
<div className='mx-4 mt-4'> <div className='mx-4 mt-4'>
<div className='flex justify-between items-center mb-4'> <div className='flex justify-between items-center mb-4'>
@@ -107,7 +122,7 @@ export default function Installs () {
.map(([key, value]) => { .map(([key, value]) => {
return ( return (
<div <div
key={value} key={key}
className={`downloads-entry ${ className={`downloads-entry ${
normalConfig?.settings.useLegacyInteractButtons normalConfig?.settings.useLegacyInteractButtons
? '' ? ''
@@ -203,17 +218,32 @@ export default function Installs () {
<div <div
key={entry} key={entry}
className={`downloads-entry ${ className={`downloads-entry ${
normalConfig?.settings.useLegacyInteractButtons normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
? '' ? ''
: 'cursor-pointer' : 'cursor-pointer'
}`} }`}
title={ title={
normalConfig?.settings.useLegacyInteractButtons normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
? '' ? ''
: 'Click to launch game. Right-click to manage this version install' : 'Click to launch game. Right-click to manage this version install'
} }
onClick={async () => { onClick={async () => {
if (normalConfig?.settings.useLegacyInteractButtons) return if (
normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
)
return
const verInfo = getVersionInfo(entry) const verInfo = getVersionInfo(entry)
if (verInfo == undefined) return if (verInfo == undefined) return
const gameInfo = getGameInfo(verInfo.game) const gameInfo = getGameInfo(verInfo.game)
@@ -232,7 +262,14 @@ export default function Installs () {
}} }}
onContextMenu={e => { onContextMenu={e => {
e.preventDefault() e.preventDefault()
if (normalConfig?.settings.useLegacyInteractButtons) return if (
normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
)
return
setManagingVersion(entry) setManagingVersion(entry)
setPopupMode(2) setPopupMode(2)
@@ -242,7 +279,7 @@ export default function Installs () {
> >
<div className='h-18 w-screen relative'> <div className='h-18 w-screen relative'>
<p className='text-2xl'> <p className='text-2xl'>
{getVersionInfo(entry)?.displayName} {getVersionInfo(entry)?.displayName}{' '}
</p> </p>
<div className='flex gap-2 absolute left-0 bottom-0'> <div className='flex gap-2 absolute left-0 bottom-0'>
@@ -272,6 +309,19 @@ export default function Installs () {
<FontAwesomeIcon icon={faWarning} color='#ffc800' /> <FontAwesomeIcon icon={faWarning} color='#ffc800' />
<p>Uses wine</p> <p>Uses wine</p>
</div> </div>
<div
className='entry-info-item'
onClick={e => e.stopPropagation()}
hidden={
!needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
}
>
<FontAwesomeIcon icon={faWarning} color='#ffc800' />
<p>Needs revision update!</p>
</div>
</div> </div>
<div className='flex gap-2 absolute right-0 bottom-0'> <div className='flex gap-2 absolute right-0 bottom-0'>
@@ -284,6 +334,10 @@ export default function Installs () {
setShowPopup(true) setShowPopup(true)
setFadeOut(false) setFadeOut(false)
}} }}
hidden={needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)}
title='Click to view version info' title='Click to view version info'
> >
View Info View Info
@@ -291,7 +345,11 @@ export default function Installs () {
<button <button
className='button' className='button'
hidden={ hidden={
!normalConfig?.settings.useLegacyInteractButtons !normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
} }
onClick={e => { onClick={e => {
e.stopPropagation() e.stopPropagation()
@@ -326,12 +384,35 @@ export default function Installs () {
}) })
}} }}
hidden={ hidden={
!normalConfig?.settings.useLegacyInteractButtons !normalConfig?.settings.useLegacyInteractButtons ||
needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
} }
title='Click to launch game' title='Click to launch game'
> >
Launch Launch
</button> </button>
<button
className='button'
onClick={e => {
e.stopPropagation()
setManagingVersion(entry)
setPopupMode(5)
setShowPopup(true)
setFadeOut(false)
}}
hidden={
!needsRevisionUpdate(
getVersionInfo(entry)?.lastRevision,
entry
)
}
title='Click to update the game'
>
Update
</button>
</div> </div>
</div> </div>
</div> </div>
+28 -24
View File
@@ -46,6 +46,7 @@ import {
} from '@tauri-apps/plugin-notification' } from '@tauri-apps/plugin-notification'
import VersionChangelog from './componets/VersionChangelog' import VersionChangelog from './componets/VersionChangelog'
import { BaseDirectory, exists, remove } from '@tauri-apps/plugin-fs' import { BaseDirectory, exists, remove } from '@tauri-apps/plugin-fs'
import VersionUpdateWarning from './componets/VersionUpdateWarning'
const roboto = Roboto({ const roboto = Roboto({
subsets: ['latin'] subsets: ['latin']
@@ -394,28 +395,26 @@ export default function RootLayout ({
if (!serverVersionList || !downloadedVersionsConfig) return if (!serverVersionList || !downloadedVersionsConfig) return
revisionCheck.current = true revisionCheck.current = true
;(async () => { ;(async () => {
const newConfig = {
...downloadedVersionsConfig,
list: { ...downloadedVersionsConfig.list }
}
const versionsToSelect: string[] = []
for (const [key, value] of Object.entries( for (const [key, value] of Object.entries(
downloadedVersionsConfig.list downloadedVersionsConfig.list
)) { )) {
const verInfo = serverVersionList.versions.find(item => item.id === key) const verInfo = serverVersionList.versions.find(item => item.id === key)
if (!verInfo || value / 1000 <= verInfo.lastRevision) { if (
delete newConfig.list[key] !verInfo ||
versionsToSelect.push(key) (verInfo.lastRevision > 0 && value / 1000 <= verInfo.lastRevision)
) {
if (
await exists('game/' + key + '/' + verInfo?.executable, {
baseDir: BaseDirectory.AppLocalData
})
)
await remove('game/' + key + '/' + verInfo?.executable, {
baseDir: BaseDirectory.AppLocalData,
recursive: true
})
} }
} }
setDownloadedVersionsConfig(newConfig)
writeVersionsConfig(newConfig)
setSelectedVersionList(prev => [...prev, ...versionsToSelect])
await downloadVersions(versionsToSelect)
})() })()
}, [serverVersionList, downloadedVersionsConfig, downloadVersions]) }, [serverVersionList, downloadedVersionsConfig, downloadVersions])
@@ -480,7 +479,8 @@ export default function RootLayout ({
setSelectedGame, setSelectedGame,
getVersionsAmountData, getVersionsAmountData,
viewingInfoFromDownloads, viewingInfoFromDownloads,
version version,
downloadVersions
}} }}
> >
<div <div
@@ -800,9 +800,6 @@ export default function RootLayout ({
list: updatedList list: updatedList
} }
writeVersionsConfig(updatedConfig) writeVersionsConfig(updatedConfig)
setManagingVersion(null)
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
return updatedConfig return updatedConfig
}) })
@@ -824,9 +821,11 @@ export default function RootLayout ({
className='button btntheme2' className='button btntheme2'
disabled={downloadProgress.length != 0} disabled={downloadProgress.length != 0}
onClick={async () => { onClick={async () => {
//uninstall //change popup to downloads
closePopup() setManagingVersion(null)
setPopupMode(1)
//uninstall
setDownloadedVersionsConfig(prev => { setDownloadedVersionsConfig(prev => {
if (!prev) return prev if (!prev) return prev
const updatedList = Object.fromEntries( const updatedList = Object.fromEntries(
@@ -839,9 +838,6 @@ export default function RootLayout ({
list: updatedList list: updatedList
} }
writeVersionsConfig(updatedConfig) writeVersionsConfig(updatedConfig)
setManagingVersion(null)
setFadeOut(true)
setTimeout(() => setShowPopup(false), 200)
return updatedConfig return updatedConfig
}) })
@@ -897,6 +893,14 @@ export default function RootLayout ({
No version selected No version selected
</p> </p>
) )
) : popupMode === 5 ? (
managingVersion && downloadedVersionsConfig ? (
<VersionUpdateWarning />
) : (
<p className='text-xl text-center'>
No version selected
</p>
)
) : null} ) : null}
{popupMode == 0 && {popupMode == 0 &&
selectedGame && selectedGame &&
+3 -1
View File
@@ -28,7 +28,9 @@
"**/*.tsx", "**/*.tsx",
".next/types/**/*.ts", ".next/types/**/*.ts",
".next/dev/types/**/*.ts", ".next/dev/types/**/*.ts",
"**/*.mts" "**/*.mts",
"next.config.ts",
"eslint.config.ts"
], ],
"exclude": ["node_modules"] "exclude": ["node_modules"]
} }