Compare commits

..
4 Commits
Author SHA1 Message Date
Lncvrt 6734b47d71 Fix versions url 2025-11-03 11:40:42 -07:00
Lncvrt fdcaf6a137 Fix 2025-11-03 11:22:31 -07:00
Lncvrt a3aa1915d4 1.1.2 2025-11-03 11:20:07 -07:00
Lncvrt 2d764448af 1.1.1 2025-11-02 20:50:49 -07:00
16 changed files with 155 additions and 279 deletions

No files matched your search

+8 -8
View File
@@ -25,7 +25,7 @@
"@tailwindcss/postcss": "4.1.16",
"@tauri-apps/cli": "2.9.2",
"@types/crypto-js": "4.2.2",
"@types/node": "24.9.2",
"@types/node": "24.10.0",
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"crypto-js": "4.2.0",
@@ -71,9 +71,9 @@
"@babel/types": ["@babel/types@7.28.5", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA=="],
"@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="],
"@emnapi/core": ["@emnapi/core@1.7.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" } }, "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw=="],
"@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@emnapi/runtime": ["@emnapi/runtime@1.7.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q=="],
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
@@ -279,7 +279,7 @@
"@types/json5": ["@types/json5@0.0.29", "", {}, "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ=="],
"@types/node": ["@types/node@24.9.2", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA=="],
"@types/node": ["@types/node@24.10.0", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A=="],
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
@@ -387,7 +387,7 @@
"balanced-match": ["balanced-match@1.0.2", "", {}, "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.21", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-JU0h5APyQNsHOlAM7HnQnPToSDQoEBZqzu/YBlqDnEeymPnZDREeXJA3KBMQee+dKteAxZ2AtvQEvVYdZf241Q=="],
"baseline-browser-mapping": ["baseline-browser-mapping@2.8.23", "", { "bin": { "baseline-browser-mapping": "dist/cli.js" } }, "sha512-616V5YX4bepJFzNyOfce5Fa8fDJMfoxzOIzDCZwaGL8MKVpFrXqfNUoIpRn9YMI5pXf/VKgzjB4htFMsFKKdiQ=="],
"brace-expansion": ["brace-expansion@1.1.12", "", { "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg=="],
@@ -403,7 +403,7 @@
"callsites": ["callsites@3.1.0", "", {}, "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="],
"caniuse-lite": ["caniuse-lite@1.0.30001751", "", {}, "sha512-A0QJhug0Ly64Ii3eIqHu5X51ebln3k4yTUkY1j8drqpWHVreg/VLijN48cZ1bYPiqOQuqpkIKnzr/Ul8V+p6Cw=="],
"caniuse-lite": ["caniuse-lite@1.0.30001753", "", {}, "sha512-Bj5H35MD/ebaOV4iDLqPEtiliTN29qkGtEHCwawWn4cYm+bPJM2NsaP30vtZcnERClMzp52J4+aw2UNbK4o+zw=="],
"chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="],
@@ -927,9 +927,9 @@
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.6.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-zq/ay+9fNIJJtJiZxdTnXS20PllcYMX3OE23ESc4HK/bdYu3cOWYVhsOhVnXALfU/uqJIxn5NBPd9z4v+SfoSg=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/core": ["@emnapi/core@1.7.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.1.0", "tslib": "^2.4.0" }, "bundled": true }, "sha512-pJdKGq/1iquWYtv1RRSljZklxHCOCAJFJrImO5ZLKPJVJlVUcs8yFwNQlqS0Lo8xT1VAXXTCZocF9n26FWEKsw=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/runtime": ["@emnapi/runtime@1.7.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-oAYoQnCYaQZKVS53Fq23ceWMRxq5EhQsE0x0RdQ55jT7wagMu5k+fS39v1fiSLrtrLQlXwVINenqhLMtTrV/1Q=="],
"@tailwindcss/oxide-wasm32-wasi/@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.1.0", "", { "dependencies": { "tslib": "^2.4.0" }, "bundled": true }, "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ=="],
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "lncvrt-games-launcher",
"private": true,
"version": "1.1.0",
"version": "1.1.2",
"type": "module",
"scripts": {
"dev": "next dev",
@@ -34,7 +34,7 @@
"@types/react": "19.2.2",
"@types/react-dom": "19.2.2",
"crypto-js": "4.2.0",
"@types/node": "24.9.2",
"@types/node": "24.10.0",
"tailwindcss": "4.1.16",
"typescript": "5.9.3",
"eslint": "9.39.0",
+2 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "lncvrt-games-launcher"
version = "1.1.0"
version = "1.1.2"
authors = ["Lncvrt"]
edition = "2024"
@@ -27,6 +27,7 @@ libc = "0.2.177"
tauri-plugin-dialog = "2.4.2"
tauri-plugin-notification = "2.3.3"
sysinfo = "0.37.2"
sha2 = "0.10.9"
[target.'cfg(target_os = "linux")'.dependencies]
shlex = "1.3.0"
+47 -55
View File
@@ -1,4 +1,5 @@
use futures_util::stream::StreamExt;
use sha2::{Digest, Sha512};
use std::{
fs::{File, create_dir_all},
io::{BufReader, copy},
@@ -62,7 +63,13 @@ async fn unzip_to_dir(zip_path: PathBuf, out_dir: PathBuf) -> String {
#[allow(unused_variables)]
#[tauri::command]
async fn download(app: AppHandle, url: String, name: String, executable: String) -> String {
async fn download(
app: AppHandle,
url: String,
name: String,
executable: String,
hash: String,
) -> String {
let client = reqwest::Client::new();
let resp = match client.get(&url).send().await {
Ok(r) => r,
@@ -90,7 +97,9 @@ async fn download(app: AppHandle, url: String, name: String, executable: String)
let _ = tokio::fs::remove_dir_all(&game_path.join(name.clone())).await;
}
let _ = tokio::fs::create_dir_all(&game_path.join(&name)).await;
let mut file = tokio::fs::File::create(download_part_path).await.unwrap();
let mut file = tokio::fs::File::create(download_part_path.clone())
.await
.unwrap();
while let Ok(Some(chunk_result)) = timeout(Duration::from_secs(5), stream.next()).await {
let chunk = match chunk_result {
@@ -120,12 +129,23 @@ async fn download(app: AppHandle, url: String, name: String, executable: String)
return "-1".to_string();
}
tokio::fs::rename(
downloads_path.join(format!("{}.part", name)),
download_zip_path.clone(),
)
.await
.unwrap();
app.emit("download-hash-checking", format!("{}", &name))
.unwrap();
let mut hasher = Sha512::new();
hasher.update(&tokio::fs::read(download_part_path.clone()).await.unwrap());
let download_hash = format!("{:x}", hasher.finalize());
if hash != download_hash {
tokio::fs::remove_file(download_part_path.clone())
.await
.unwrap();
return "-1".to_string();
}
app.emit("download-finishing", format!("{}", &name))
.unwrap();
tokio::fs::rename(download_part_path.clone(), download_zip_path.clone())
.await
.unwrap();
let unzip_res = unzip_to_dir(download_zip_path.clone(), game_path.join(&name)).await;
tokio::fs::remove_file(download_zip_path.clone())
.await
@@ -167,7 +187,7 @@ async fn download(app: AppHandle, url: String, name: String, executable: String)
#[allow(unused_variables)]
#[tauri::command]
fn launch_game(app: AppHandle, name: String, executable: String, wine: bool, wine_command: String) {
fn launch_game(app: AppHandle, name: String, executable: String) {
let game_folder = app
.path()
.app_local_data_dir()
@@ -183,54 +203,26 @@ fn launch_game(app: AppHandle, name: String, executable: String, wine: bool, win
.show(|_| {});
return;
}
let result = if wine && platform() == "linux" {
#[cfg(target_os = "linux")]
{
let wine_cmd_to_use =
wine_command.replace("%path%", &format!("\"{}\"", game_path.to_string_lossy()));
if is_running_by_path(&game_path) {
app.dialog()
.message(format!("The version {} is already running.", name))
.kind(MessageDialogKind::Error)
.title("Game already running")
.show(|_| {});
return;
}
let parts = shlex::split(&wine_cmd_to_use).expect("failed to split command");
let exe = &parts[0];
let args = &parts[1..];
Command::new(exe)
.args(args)
.current_dir(&game_folder)
.spawn()
}
#[cfg(not(target_os = "linux"))]
{
Err(std::io::Error::new(std::io::ErrorKind::Other, "not linux"))
}
if platform() == "macos" {
Command::new("open")
.arg(&game_path)
.current_dir(&game_folder)
.spawn()
.unwrap();
} else {
if is_running_by_path(&game_path) {
app.dialog()
.message(format!("The version {} is already running.", name))
.kind(MessageDialogKind::Error)
.title("Game already running")
.show(|_| {});
return;
}
if platform() == "macos" {
Command::new("open")
.arg(&game_path)
.current_dir(&game_folder)
.spawn()
} else {
Command::new(&game_path).current_dir(&game_folder).spawn()
}
};
match result {
Ok(_) => println!("Game launched successfully."),
Err(e) => {
app.dialog()
.message(format!("Failed to load game:\n{}\n\nTry reinstalling the game or make a support request in the Community link on the sidebar.", e))
.kind(MessageDialogKind::Error)
.title("Failed to launch game")
.show(|_| {});
}
Command::new(&game_path)
.current_dir(&game_folder)
.spawn()
.unwrap();
}
}
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.1.0",
"version": "1.1.2",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.1.0",
"version": "1.1.2",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.1.0",
"version": "1.1.2",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -1,7 +1,7 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Lncvrt Games Launcher",
"version": "1.1.0",
"version": "1.1.2",
"identifier": "xyz.lncvrt.games-launcher",
"build": {
"beforeDevCommand": "next dev",
+1 -1
View File
@@ -18,7 +18,7 @@
}
.nav-links {
@apply flex flex-col p-4 space-y-1;
@apply flex flex-col p-4 space-y-1 overflow-y-auto overflow-x-hidden;
}
.link {
+6 -1
View File
@@ -20,6 +20,7 @@ import { usePathname, useSearchParams } from 'next/navigation'
export default function Sidebar () {
const {
normalConfig,
getListOfGames,
setShowPopup,
setPopupMode,
@@ -88,7 +89,11 @@ export default function Sidebar () {
? 'active'
: ''
} ml-auto w-50 ${
pathname === '/' || pathname === '/game' ? '' : 'hidden'
normalConfig?.settings.alwaysShowGamesInSidebar ||
pathname === '/' ||
pathname === '/game'
? ''
: 'hidden'
}`}
>
<FontAwesomeIcon icon={faGamepad} className='mr-1' />{' '}
+1 -45
View File
@@ -1,11 +1,9 @@
'use client'
import { useEffect } from 'react'
import { platform } from '@tauri-apps/plugin-os'
import '../Installs.css'
import { format } from 'date-fns'
import { invoke } from '@tauri-apps/api/core'
import { message } from '@tauri-apps/plugin-dialog'
import { useGlobal } from '../GlobalProvider'
import { useSearchParams } from 'next/navigation'
@@ -58,14 +56,6 @@ export default function Installs () {
if (!info) return false
return info.game === Number(params.get('id') || 0)
})
.sort((a, b) => {
const infoA = getVersionInfo(a)
const infoB = getVersionInfo(b)
if (!infoA && !infoB) return 0
if (!infoA) return 1
if (!infoB) return -1
return infoB.place - infoA.place
})
.map((entry, i) => (
<div key={i} className='downloads-entry'>
<div className='flex flex-col'>
@@ -100,43 +90,9 @@ export default function Installs () {
onClick={async () => {
const verInfo = getVersionInfo(entry)
if (verInfo == undefined) return
let plat = platform()
let willUseWine = false
let cfg = null
while (normalConfig != null) {
cfg = normalConfig
break
}
if (plat === 'macos' || plat === 'linux') {
if (
!verInfo.platforms.includes(plat) &&
verInfo.platforms.includes('windows')
) {
if (
cfg != null &&
!cfg.settings.useWineOnUnixWhenNeeded
) {
await message(
'Wine support is disabled in settings and this version requires wine',
{
title: 'Wine is needed to load this version',
kind: 'error'
}
)
return
}
plat = 'windows'
willUseWine = true
}
}
invoke('launch_game', {
name: verInfo.id,
executable:
verInfo.executables[
verInfo.platforms.indexOf(plat)
],
wine: willUseWine,
wineCommand: cfg?.settings.wineOnUnixCommand
executable: verInfo.executable
})
}}
>
+54 -125
View File
@@ -4,7 +4,6 @@ import { useCallback, useEffect, useState } from 'react'
import Sidebar from './componets/Sidebar'
import './Globals.css'
import { DownloadProgress } from './types/DownloadProgress'
import { arch, platform } from '@tauri-apps/plugin-os'
import { invoke } from '@tauri-apps/api/core'
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'
import {
@@ -39,6 +38,8 @@ import { ServerVersionsResponse } from './types/ServerVersionsResponse'
import { GameVersion } from './types/GameVersion'
import { Game } from './types/Game'
import { listen } from '@tauri-apps/api/event'
import { usePathname } from 'next/navigation'
import { arch, platform } from '@tauri-apps/plugin-os'
const roboto = Roboto({
subsets: ['latin']
@@ -78,6 +79,8 @@ export default function RootLayout ({
}
}
const pathname = usePathname()
const notifyUser = useCallback(
async (title: string, body: string) => {
if (!normalConfig?.settings.allowNotifications) return
@@ -111,6 +114,28 @@ export default function RootLayout ({
})
}).then(f => (unlistenProgress = f))
listen<string>('download-hash-checking', event => {
const versionName = event.payload
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === versionName)
if (i === -1) return prev
const copy = [...prev]
copy[i] = { ...copy[i], hash_checking: true }
return copy
})
}).then(f => (unlistenProgress = f))
listen<string>('download-finishing', event => {
const versionName = event.payload
setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === versionName)
if (i === -1) return prev
const copy = [...prev]
copy[i] = { ...copy[i], hash_checking: false, finishing: true }
return copy
})
}).then(f => (unlistenProgress = f))
listen<string>('version-uninstalled', event => {
const versionName = event.payload
setDownloadedVersionsConfig(prev => {
@@ -159,7 +184,7 @@ export default function RootLayout ({
setLoadingText('Downloading version list...')
try {
const res = await axios.get(
'https://games.lncvrt.xyz/api/launcher/versions'
`https://games.lncvrt.xyz/api/launcher/versions?platform=${platform()}&arch=${arch()}`
)
setServerVersionList(res.data)
} catch {
@@ -190,92 +215,18 @@ export default function RootLayout ({
function getSpecialVersionsList (game?: number): GameVersion[] {
if (!normalConfig || !serverVersionList) return []
const useWine = normalConfig.settings.useWineOnUnixWhenNeeded
const p = platform()
const a = arch()
return serverVersionList.versions
.filter(v => !downloadedVersionsConfig?.list.includes(v.id))
.filter(v => {
if (game && v.game != game) return false
if (p === 'macos' || p === 'linux') {
if (useWine) {
return (
v.platforms.includes('windows-x86') ||
v.platforms.includes('windows-x64') ||
v.platforms.includes(p)
)
}
return v.platforms.includes(p)
}
if (p === 'windows') {
if (a === 'x86_64')
return (
v.platforms.includes('windows-x86') ||
v.platforms.includes('windows-x64')
)
if (a === 'aarch64') return v.platforms.includes('windows-arm64')
}
return false
return true
})
.sort((a, b) => {
if (b.game !== a.game) return a.game - b.game
return b.place - a.place
return 0
})
}
function getDownloadLink (version: GameVersion): string | undefined {
const p = platform()
const a = arch()
const findUrl = (plat: string) => {
const i = version.platforms.indexOf(plat)
return i >= 0 ? version.downloadUrls[i] : undefined
}
if (p === 'windows') {
if (a === 'x86_64')
return findUrl('windows-x64') || findUrl('windows-x86')
if (a === 'aarch64') return findUrl('windows-arm64')
}
if (p === 'macos' || p === 'linux') {
if (normalConfig?.settings.useWineOnUnixWhenNeeded) {
return findUrl('windows-x86') || findUrl('windows-x64') || findUrl(p)
}
return findUrl(p)
}
return undefined
}
function getExecutableName (version: GameVersion): string | undefined {
const p = platform()
const a = arch()
const findUrl = (plat: string) => {
const i = version.platforms.indexOf(plat)
return i >= 0 ? version.executables[i] : undefined
}
if (p === 'windows') {
if (a === 'x86_64')
return findUrl('windows-x64') || findUrl('windows-x86')
if (a === 'aarch64') return findUrl('windows-arm64')
}
if (p === 'macos' || p === 'linux') {
if (normalConfig?.settings.useWineOnUnixWhenNeeded) {
return findUrl('windows-x86') || findUrl('windows-x64') || findUrl(p)
}
return findUrl(p)
}
return undefined
}
function getVersionInfo (id: string | undefined): GameVersion | undefined {
if (!id) return undefined
return serverVersionList?.versions.find(v => v.id === id)
@@ -307,7 +258,7 @@ export default function RootLayout ({
setSelectedVersionList([])
const newDownloads = list.map(
version => new DownloadProgress(version, 0, false, true)
version => new DownloadProgress(version, 0, false, true, false, false)
)
setDownloadProgress(newDownloads)
@@ -327,29 +278,16 @@ export default function RootLayout ({
)
return
}
const downloadLink = getDownloadLink(info)
if (!downloadLink) {
setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version)
)
return
}
const executableName = getExecutableName(info)
if (!executableName) {
setDownloadProgress(prev =>
prev.filter(d => d.version !== download.version)
)
return
}
setDownloadProgress(prev =>
prev.map(d =>
d.version === download.version ? { ...d, queued: false } : d
)
)
const res = await invoke<string>('download', {
url: downloadLink,
url: info.downloadUrl,
name: info.id,
executable: executableName
executable: info.executable,
hash: info.sha512sum
})
if (res == '1') {
setDownloadProgress(prev =>
@@ -391,38 +329,13 @@ export default function RootLayout ({
} | null {
if (!downloadedVersionsConfig || !serverVersionList) return null
const p = platform()
const a = arch()
const installed = downloadedVersionsConfig.list.filter(
v => getVersionGame(getVersionInfo(v)?.game)?.id === gameId
).length
const total = serverVersionList.versions
.filter(v => {
if (p === 'macos' || p === 'linux') {
if (normalConfig?.settings.useWineOnUnixWhenNeeded) {
return (
v.platforms.includes('windows-x86') ||
v.platforms.includes('windows-x64') ||
v.platforms.includes(p)
)
}
return v.platforms.includes(p)
}
if (p === 'windows') {
if (a === 'x86_64')
return (
v.platforms.includes('windows-x86') ||
v.platforms.includes('windows-x64')
)
if (a === 'aarch64') return v.platforms.includes('windows-arm64')
}
return false
})
.filter(v => getVersionGame(v?.game)?.id === gameId).length
const total = serverVersionList.versions.filter(
v => getVersionGame(v?.game)?.id === gameId
).length
return { installed, total }
}
@@ -512,7 +425,11 @@ export default function RootLayout ({
<button
className='close-button'
onClick={() => {
if (popupMode == 0 && selectedGame) {
if (
popupMode == 0 &&
selectedGame &&
pathname === '/'
) {
setSelectedGame(null)
setSelectedVersionList([])
} else {
@@ -523,7 +440,7 @@ export default function RootLayout ({
>
<FontAwesomeIcon
icon={
popupMode == 0 && selectedGame
popupMode == 0 && selectedGame && pathname === '/'
? faChevronLeft
: faXmark
}
@@ -683,6 +600,18 @@ export default function RootLayout ({
<span className='text-yellow-500'>
Queued…
</span>
) : v.queued ? (
<span className='text-yellow-500'>
Queued…
</span>
) : v.hash_checking ? (
<span className='text-blue-500'>
Checking hash...
</span>
) : v.finishing ? (
<span className='text-green-500'>
Finishing...
</span>
) : (
<span>
Downloading: {v.progress}% done
+23 -30
View File
@@ -3,24 +3,22 @@
import { useEffect, useState } from 'react'
import { Setting } from '../componets/Setting'
import { writeNormalConfig } from '../util/BazookaManager'
import { platform } from '@tauri-apps/plugin-os'
import { useGlobal } from '../GlobalProvider'
export default function Settings () {
const [allowNotifications, setAllowNotifications] = useState(false)
const [useWineOnUnixWhenNeeded, setUseWineOnUnixWhenNeeded] = useState(false)
const [wineOnUnixCommand, setWineOnUnixCommand] = useState('wine %path%')
const [alwaysShowGamesInSidebar, setAlwaysShowGamesInSidebar] =
useState(false)
const [loaded, setLoaded] = useState(false)
const { normalConfig } = useGlobal()
const { normalConfig, setNormalConfig } = useGlobal()
useEffect(() => {
;(async () => {
while (normalConfig != null) {
setUseWineOnUnixWhenNeeded(
normalConfig.settings.useWineOnUnixWhenNeeded
)
setWineOnUnixCommand(normalConfig.settings.wineOnUnixCommand)
setAllowNotifications(normalConfig.settings.allowNotifications)
setAlwaysShowGamesInSidebar(
normalConfig.settings.alwaysShowGamesInSidebar
)
setLoaded(true)
break
}
@@ -45,34 +43,29 @@ export default function Settings () {
}}
/>
<Setting
label='Use wine to launch Berry Dash when needed'
value={useWineOnUnixWhenNeeded}
label='Always show games in sidebar'
value={alwaysShowGamesInSidebar}
onChange={async () => {
while (normalConfig != null) {
setUseWineOnUnixWhenNeeded(!useWineOnUnixWhenNeeded)
normalConfig.settings.useWineOnUnixWhenNeeded =
!useWineOnUnixWhenNeeded
await writeNormalConfig(normalConfig)
setAlwaysShowGamesInSidebar(!alwaysShowGamesInSidebar)
setNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar
}
})
writeNormalConfig({
...normalConfig,
settings: {
...normalConfig.settings,
alwaysShowGamesInSidebar: !alwaysShowGamesInSidebar
}
})
break
}
}}
className={platform() == 'linux' ? '' : 'hidden'}
/>
<input
type='text'
value={wineOnUnixCommand}
onChange={async e => {
while (normalConfig != null) {
setWineOnUnixCommand(e.target.value)
normalConfig.settings.wineOnUnixCommand = e.target.value
await writeNormalConfig(normalConfig)
break
}
}}
className={`input-field ${
platform() == 'linux' && useWineOnUnixWhenNeeded ? '' : 'hidden'
}`}
></input>
</div>
)}
</>
+3 -1
View File
@@ -3,6 +3,8 @@ export class DownloadProgress {
public version: string,
public progress: number,
public failed: boolean,
public queued: boolean
public queued: boolean,
public hash_checking: boolean,
public finishing: boolean
) { }
}
+3 -4
View File
@@ -2,9 +2,8 @@ export interface GameVersion {
id: string
versionName: string
releaseDate: number
downloadUrls: string[]
platforms: string[]
executables: string[]
game: number
place: number
downloadUrl: string
executable: string
sha512sum: string
}
+1 -2
View File
@@ -1,7 +1,6 @@
export class SettingsType {
constructor(
public allowNotifications: boolean = true,
public useWineOnUnixWhenNeeded: boolean = false,
public wineOnUnixCommand: string = 'wine %path%'
public alwaysShowGamesInSidebar: boolean = true
) { }
}