feat: more ui tweaks

This commit is contained in:
neoapps-dev
2026-09-04 15:51:09 +03:00
parent f92e1e77de
commit 9b24dcb53f
24 changed files with 352 additions and 113 deletions
+9 -9
View File
@@ -45,14 +45,16 @@ fn get_raw_url(host: &str, owner: &str, repo: &str, branch: &str, path: &str, is
#[tauri::command]
pub async fn list_git_directory(
app: tauri::AppHandle,
repo_url: String,
branch: String,
path: String,
) -> Result<Vec<GitEntry>, String> {
list_git_directory_inner(repo_url, branch, path).await
list_git_directory_inner(app, repo_url, branch, path).await
}
fn list_git_directory_inner(
app: tauri::AppHandle,
repo_url: String,
branch: String,
path: String,
@@ -60,9 +62,8 @@ fn list_git_directory_inner(
Box::pin(async move {
let (owner, repo, host, is_github) = parse_git_url(&repo_url)?;
let api_url = get_api_url(&host, &owner, &repo, &path, &branch, is_github);
let client = reqwest::Client::new();
let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?;
let response = client.get(&api_url)
.header("User-Agent", "Emerald-Launcher")
.send()
.await
.map_err(|e| format!("Failed to fetch directory listing: {}", e))?;
@@ -82,7 +83,7 @@ fn list_git_directory_inner(
let is_dir = json.get("type").and_then(|v| v.as_str()) == Some("dir");
if is_dir {
let sub_path = json.get("path").and_then(|v| v.as_str()).unwrap_or("").to_string();
return list_git_directory_inner(repo_url, branch, sub_path).await;
return list_git_directory_inner(app, repo_url, branch, sub_path).await;
}
return Ok(Vec::new());
}
@@ -107,6 +108,7 @@ fn list_git_directory_inner(
}
async fn collect_files(
app: &tauri::AppHandle,
host: &str,
owner: &str,
repo: &str,
@@ -116,11 +118,10 @@ async fn collect_files(
) -> Result<Vec<String>, String> {
let mut files = Vec::new();
let mut dirs_to_list = vec![root_path.to_string()];
let client = reqwest::Client::new();
let client = util::build_http_client_from_app(app).map_err(|e| e.to_string())?;
while let Some(dir) = dirs_to_list.pop() {
let api_url = get_api_url(host, owner, repo, &dir, branch, is_github);
let response = client.get(&api_url)
.header("User-Agent", "Emerald-Launcher")
.send()
.await
.map_err(|e| format!("Failed to list {}: {}", dir, e))?;
@@ -174,18 +175,17 @@ pub async fn download_dlc_files(
let instance_dir = util::get_instance_working_dir(&app, &instance_id);
let dlc_dest = instance_dir.join("Windows64Media").join("DLC").join(&dlc_folder);
let (owner, repo, host, is_github) = parse_git_url(&repo_url)?;
let files_to_download = collect_files(&host, &owner, &repo, &branch, &dlc_folder, is_github).await?;
let files_to_download = collect_files(&app, &host, &owner, &repo, &branch, &dlc_folder, is_github).await?;
if files_to_download.is_empty() {
return Err(format!("No files found in '{}' folder", dlc_folder));
}
fs::create_dir_all(&dlc_dest).map_err(|e| e.to_string())?;
let client = reqwest::Client::new();
let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?;
let total = files_to_download.len();
for (i, file_path) in files_to_download.iter().enumerate() {
let raw_url = get_raw_url(&host, &owner, &repo, &branch, file_path, is_github);
let response = client.get(&raw_url)
.header("User-Agent", "Emerald-Launcher")
.send()
.await
.map_err(|e| format!("Failed to download {}: {}", file_path, e))?;
+4 -3
View File
@@ -28,7 +28,8 @@ async fn stream_download(
lock.insert(instance_id.to_string(), token);
}
let response = reqwest::Client::new().get(url).header(reqwest::header::USER_AGENT, "Emerald-Launcher").send().await.map_err(|e| e.to_string())?;
let client = util::build_http_client_from_app(app).map_err(|e| e.to_string())?;
let response = client.get(url).send().await.map_err(|e| e.to_string())?;
if !response.status().is_success() {
{ state.tokens.lock().await.remove(instance_id); }
return Err(format!("Download failed: {}", response.status()));
@@ -300,9 +301,9 @@ pub async fn check_game_update(
return Ok(true);
}
let response = reqwest::Client::new()
let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?;
let response = client
.head(&url)
.header(reqwest::header::USER_AGENT, "Emerald-Launcher")
.send()
.await
.map_err(|e| e.to_string())?;
+3 -1
View File
@@ -15,6 +15,8 @@ use serde::Deserialize;
#[cfg(target_os = "macos")]
use crate::platform::macos;
#[cfg(target_os = "macos")]
use crate::util;
#[cfg(target_os = "macos")]
use std::fs;
#[tauri::command]
@@ -71,7 +73,7 @@ pub async fn setup_macos_runtime(window: tauri::Window, app: AppHandle) -> Resul
None,
);
let client = reqwest::Client::new();
let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?;
let release_text = client
.get(format!("https://api.github.com/repos/{}/releases/latest", repo))
.header("User-Agent", "Emerald-Legacy-Launcher")
+3 -1
View File
@@ -1,12 +1,14 @@
use crate::types::HttpResponse;
use crate::util;
#[tauri::command]
pub async fn http_proxy_request(
app: tauri::AppHandle,
method: String,
url: String,
body: Option<String>,
headers: std::collections::HashMap<String, String>,
) -> Result<HttpResponse, String> {
let client = reqwest::Client::new();
let client = util::build_http_client_from_app(&app)?;
let mut req = match method.to_uppercase().as_str() {
"GET" => client.get(&url),
"POST" => client.post(&url),
+4 -3
View File
@@ -7,8 +7,8 @@ use crate::types::ScreenshotInfo;
use crate::config;
use crate::util;
#[tauri::command]
pub async fn fetch_skin(username: String) -> Result<(String, String), String> {
let client = reqwest::Client::new();
pub async fn fetch_skin(app: AppHandle, username: String) -> Result<(String, String), String> {
let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?;
let mojang_url = format!("https://api.mojang.com/users/profiles/minecraft/{}", username);
let mojang_res = client.get(&mojang_url).send().await.map_err(|e| format!("Failed request to mojang: {}", e))?;
if !mojang_res.status().is_success() {
@@ -47,7 +47,8 @@ pub async fn download_logo(app: AppHandle, id: String, url: String) -> Result<St
let filename = format!("{}.{}", id, file_ext);
let dest_path = logos_dir.join(&filename);
let response = reqwest::get(&url).await.map_err(|e| e.to_string())?;
let client = util::build_http_client_from_app(&app).map_err(|e| e.to_string())?;
let response = client.get(&url).send().await.map_err(|e| e.to_string())?;
if !response.status().is_success() {
return Err(format!("Failed to download logo: {}", response.status()));
}
+2 -1
View File
@@ -70,7 +70,8 @@ async fn download_and_assemble(
let mut downloaded: Vec<PathBuf> = Vec::new();
for part in parts {
let url = format!("{}/{}", raw_base, part);
let response = reqwest::get(&url).await.map_err(|e| e.to_string())?;
let client = util::build_http_client_from_app(app).map_err(|e| e.to_string())?;
let response = client.get(&url).send().await.map_err(|e| e.to_string())?;
if !response.status().is_success() {
return Err(format!("Failed to download {}: HTTP {}", part, response.status()));
}
+1
View File
@@ -42,6 +42,7 @@ pub fn load_config_raw(app: AppHandle) -> AppConfig {
android_audio_backend: None,
goldmapper_enabled: Some(true),
goldmapper_mappings: None,
http_proxy: None,
}
}
+1
View File
@@ -77,6 +77,7 @@ pub struct AppConfig {
pub android_audio_backend: Option<String>,
pub goldmapper_enabled: Option<bool>,
pub goldmapper_mappings: Option<Vec<GoldMapperMapping>>,
pub http_proxy: Option<String>,
}
#[derive(Serialize, Deserialize, Clone, Debug)]
+18
View File
@@ -44,6 +44,24 @@ pub fn copy_dir_all(src: impl AsRef<std::path::Path>, dst: impl AsRef<std::path:
Ok(())
}
pub fn build_http_client(proxy: Option<&str>) -> Result<reqwest::Client, String> {
let mut builder = reqwest::Client::builder();
builder = builder.user_agent("Emerald-Launcher");
if let Some(p) = proxy {
let trimmed = p.trim();
if !trimmed.is_empty() {
let proxy = reqwest::Proxy::all(trimmed).map_err(|e| format!("Invalid proxy: {e}"))?;
builder = builder.proxy(proxy);
}
}
builder.build().map_err(|e| e.to_string())
}
pub fn build_http_client_from_app(app: &AppHandle) -> Result<reqwest::Client, String> {
let config = config::load_config_raw(app.clone());
build_http_client(config.http_proxy.as_deref())
}
#[cfg(unix)]
pub fn unix_path_to_wine_z_path(unix_path: &PathBuf) -> String {
let p = unix_path.to_string_lossy();
+7 -7
View File
@@ -1,10 +1,8 @@
use once_cell::sync::Lazy;
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufReader};
use tokio::net::TcpListener;
use tokio_util::sync::CancellationToken;
use tauri::{AppHandle, Emitter};
const REGISTRY_URL: &str = "https://raw.githubusercontent.com/LCE-Hub/LCE-Workshop/refs/heads/main"; //neo: more hardcoding!
static CLIENT: Lazy<reqwest::Client> = Lazy::new(|| reqwest::Client::new());
pub struct Guard {
cancel: Option<CancellationToken>,
}
@@ -48,7 +46,8 @@ async fn serve(app: AppHandle, cancel: CancellationToken) {
result = listener.accept() => {
match result {
Ok((stream, _)) => {
tokio::spawn(handle(stream));
let handle_app = app.clone();
tokio::spawn(handle(stream, handle_app));
}
Err(e) => {
let _ = app.emit("backend-error", format!("Workshop server accept error: {e}"));
@@ -61,7 +60,7 @@ async fn serve(app: AppHandle, cancel: CancellationToken) {
}
}
async fn handle(stream: tokio::net::TcpStream) {
async fn handle(stream: tokio::net::TcpStream, app: AppHandle) {
let (reader, mut writer) = stream.into_split();
let mut buf_reader = BufReader::new(reader);
let mut request_line = String::new();
@@ -81,7 +80,7 @@ async fn handle(stream: tokio::net::TcpStream) {
if request_line.starts_with("GET /workshop/") && request_line.ends_with(" HTTP/1.1") {
let path = &request_line["GET /workshop/".len()..request_line.len() - " HTTP/1.1".len()];
match fetch_workshop_file(path).await {
match fetch_workshop_file(&app, path).await {
Ok(body) => {
let body_bytes = &body;
let content_type = if path.ends_with(".json") {
@@ -123,9 +122,10 @@ async fn handle(stream: tokio::net::TcpStream) {
}
}
async fn fetch_workshop_file(path: &str) -> Result<Vec<u8>, String> {
async fn fetch_workshop_file(app: &AppHandle, path: &str) -> Result<Vec<u8>, String> {
let url = format!("{}/{}", REGISTRY_URL, path);
let resp = CLIENT.get(&url).send().await.map_err(|e| e.to_string())?;
let client = crate::util::build_http_client_from_app(app)?;
let resp = client.get(&url).send().await.map_err(|e| e.to_string())?;
if resp.status().is_success() {
resp.bytes().await.map(|b| b.to_vec()).map_err(|e| e.to_string())
} else {