Async downloader, better Proton support (#183)

* feat: async downloader + other fixes

* feat: windows command parsing + use library path for install path

* feat: better proton support

* feat: style fixes and store button now uses in-app

* feat: emulator rename + umu emulator fix

* feat: bring process creation inline with docs

* fix: clippy
This commit is contained in:
DecDuck
2026-02-06 23:24:14 +11:00
committed by GitHub
parent 1f74d35bdc
commit 16ef83228b
45 changed files with 1453 additions and 381 deletions
+16 -5
View File
@@ -48,6 +48,7 @@ pub struct FetchLibraryResponse {
library: Vec<Game>,
collections: Vec<Collection>,
other: Vec<Game>,
missing: Vec<Game>,
}
pub async fn fetch_library_logic(
@@ -60,11 +61,11 @@ pub async fn fetch_library_logic(
return Ok(library);
}
let client = DROP_CLIENT_ASYNC.clone();
let response = generate_url(&["/api/v1/client/user/library"], &[])?;
let response = client
let auth_header = generate_authorization_header();
let response = DROP_CLIENT_ASYNC
.get(response)
.header("Authorization", generate_authorization_header())
.header("Authorization", auth_header)
.send()
.await?;
@@ -111,6 +112,7 @@ pub async fn fetch_library_logic(
// Add games that are installed but no longer in library
let mut other = Vec::new();
let mut missing = Vec::new();
for meta in installed_metas {
if all_games.iter().any(|e| *e.id() == meta.id) {
continue;
@@ -132,13 +134,18 @@ pub async fn fetch_library_logic(
continue;
}
};
other.push(game);
if game.game_type == "Game" {
missing.push(game);
} else {
other.push(game);
}
}
let response = FetchLibraryResponse {
library,
collections,
other,
missing,
};
cache_object("library", &response)?;
@@ -167,6 +174,7 @@ pub async fn fetch_library_logic_offline(
response.library.retain(retain_filter);
response.other.retain(retain_filter);
response.missing.retain(retain_filter);
response.collections.iter_mut().for_each(|k| {
k.entries.retain(|object| {
matches!(
@@ -253,6 +261,7 @@ pub async fn fetch_game_logic(
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
struct VersionDownloadOptionRequiredContent {
game_id: String,
version_id: String,
name: String,
icon_object_id: String,
@@ -263,6 +272,7 @@ struct VersionDownloadOptionRequiredContent {
#[derive(Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct VersionDownloadOption {
game_id: String,
version_id: String,
display_name: Option<String>,
version_path: String,
@@ -397,7 +407,8 @@ pub fn update_game_configuration(
.clone();
// Add more options in here
existing_configuration.launch_template = options.launch_string().clone();
existing_configuration.user_configuration.launch_template = options.launch_string;
existing_configuration.user_configuration.override_proton_path = options.override_proton_path;
// Add no more options past here
+28 -4
View File
@@ -12,7 +12,12 @@ use std::{
sync::nonpoison::Mutex, time::SystemTime,
};
use ::client::{app_state::AppState, app_status::AppStatus, autostart::sync_autostart_on_startup};
use ::client::{
app_state::{AppState, UmuState},
app_status::AppStatus,
autostart::sync_autostart_on_startup,
compat::UMU_LAUNCHER_EXECUTABLE,
};
use ::download_manager::DownloadManagerWrapper;
use ::games::scan::scan_install_dirs;
use ::process::ProcessManagerWrapper;
@@ -96,6 +101,15 @@ async fn setup(handle: AppHandle) -> AppState {
ProcessManagerWrapper::init(handle.clone());
DownloadManagerWrapper::init(handle.clone());
#[cfg(not(target_os = "linux"))]
let umu_state = UmuState::NotNeeded;
#[cfg(target_os = "linux")]
let umu_state = match UMU_LAUNCHER_EXECUTABLE.is_some() {
true => UmuState::Installed,
false => UmuState::NotInstalled,
};
debug!("checking if database is set up");
let is_set_up = DB.database_is_set_up();
@@ -105,6 +119,7 @@ async fn setup(handle: AppHandle) -> AppState {
return AppState {
status: AppStatus::NotConfigured,
user: None,
umu_state,
};
}
@@ -166,6 +181,7 @@ async fn setup(handle: AppHandle) -> AppState {
AppState {
status: app_status,
user,
umu_state,
}
}
@@ -252,7 +268,15 @@ pub fn run() {
toggle_autostart,
get_autostart_enabled,
open_process_logs,
get_launch_options
get_launch_options,
#[cfg(target_os = "linux")]
::process::compat::fetch_proton_paths,
#[cfg(target_os = "linux")]
::process::compat::add_proton_layer,
#[cfg(target_os = "linux")]
::process::compat::remove_proton_layer,
#[cfg(target_os = "linux")]
::process::compat::set_default
])
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_dialog::init())
@@ -296,7 +320,7 @@ pub fn run() {
main_window
.add_child(
WebviewBuilder::new("frontned", WebviewUrl::App("main".into()))
WebviewBuilder::new("frontend", WebviewUrl::App("main".into()))
.auto_resize(),
LogicalPosition::new(0., 0.),
LogicalSize::new(width, height),
@@ -355,7 +379,7 @@ pub fn run() {
.on_menu_event(|app, event| match event.id.as_ref() {
"open" => {
app.webview_windows()
.get("main")
.get("frontend")
.expect("Failed to get webview")
.show()
.expect("Failed to show window");