diff --git a/Cargo.lock b/Cargo.lock index 9801f9885..17edd0a15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4567,7 +4567,7 @@ dependencies = [ [[package]] name = "theseus" -version = "0.1.0" +version = "0.2.0" dependencies = [ "async-tungstenite", "async_zip", @@ -4608,7 +4608,7 @@ dependencies = [ [[package]] name = "theseus_cli" -version = "0.1.0" +version = "0.2.0" dependencies = [ "argh", "color-eyre", @@ -4660,6 +4660,7 @@ dependencies = [ "tracing-subscriber 0.2.25", "url", "uuid", + "window-shadows", ] [[package]] @@ -4672,7 +4673,7 @@ dependencies = [ [[package]] name = "theseus_playground" -version = "0.1.0" +version = "0.0.0" dependencies = [ "daedalus", "dunce", @@ -5484,6 +5485,18 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "window-shadows" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29d30320647cfc3dc45554c8ad825b84831def81f967a2f7589931328ff9b16d" +dependencies = [ + "cocoa", + "objc", + "raw-window-handle", + "windows-sys 0.42.0", +] + [[package]] name = "windows" version = "0.37.0" diff --git a/theseus/Cargo.toml b/theseus/Cargo.toml index 40cae6412..2ff28c017 100644 --- a/theseus/Cargo.toml +++ b/theseus/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "theseus" -version = "0.1.0" +version = "0.2.0" authors = ["Jai A "] edition = "2018" diff --git a/theseus/src/api/jre.rs b/theseus/src/api/jre.rs index f8ac91fde..4729b75a0 100644 --- a/theseus/src/api/jre.rs +++ b/theseus/src/api/jre.rs @@ -18,9 +18,9 @@ pub const JAVA_18PLUS_KEY: &str = "JAVA_18PLUS"; // Autodetect JavaSettings default // Make a guess for what the default Java global settings should be pub async fn autodetect_java_globals() -> crate::Result { - let mut java_8 = find_java8_jres().await?; - let mut java_17 = find_java17_jres().await?; - let mut java_18plus = find_java18plus_jres().await?; + let mut java_8 = find_filtered_jres("1.8").await?; + let mut java_17 = find_filtered_jres("1.17").await?; + let mut java_18plus = find_filtered_jres("1.18").await?; // Simply select last one found for initial guess let mut java_globals = JavaGlobals::new(); @@ -37,55 +37,19 @@ pub async fn autodetect_java_globals() -> crate::Result { Ok(java_globals) } -// Searches for jres on the system that are 1.18 or higher -pub async fn find_java18plus_jres() -> crate::Result> { - let version = extract_java_majorminor_version("1.18")?; - let jres = jre::get_all_jre().await?; - // Filter out JREs that are not 1.17 or higher - Ok(jres - .into_iter() - .filter(|jre| { - let jre_version = extract_java_majorminor_version(&jre.version); - if let Ok(jre_version) = jre_version { - jre_version >= version - } else { - false - } - }) - .collect()) -} - -// Searches for jres on the system that are 1.8 exactly -pub async fn find_java8_jres() -> crate::Result> { - let version = extract_java_majorminor_version("1.8")?; +// Searches for jres on the system given a java version (ex: 1.8, 1.17, 1.18) +pub async fn find_filtered_jres( + version: &str, +) -> crate::Result> { + let version = extract_java_majorminor_version(version)?; let jres = jre::get_all_jre().await?; - // Filter out JREs that are not 1.8 Ok(jres .into_iter() .filter(|jre| { let jre_version = extract_java_majorminor_version(&jre.version); if let Ok(jre_version) = jre_version { - jre_version == version - } else { - false - } - }) - .collect()) -} - -// Searches for jres on the system that are 1.17 exactly -pub async fn find_java17_jres() -> crate::Result> { - let version = extract_java_majorminor_version("1.17")?; - let jres = jre::get_all_jre().await?; - - // Filter out JREs that are not 1.8 - Ok(jres - .into_iter() - .filter(|jre| { - let jre_version = extract_java_majorminor_version(&jre.version); - if let Ok(jre_version) = jre_version { - jre_version == version + jre_version >= version } else { false } @@ -157,16 +121,31 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result { )) })?; emit_loading(&loading_bar, 10.0, Some("Done extracting java")).await?; - Ok(path - .join( - download - .name - .file_stem() - .unwrap_or_default() - .to_string_lossy() - .to_string(), - ) - .join(format!("zulu-{}.jre/Contents/Home/bin/java", java_version))) + let mut base_path = path.join( + download + .name + .file_stem() + .unwrap_or_default() + .to_string_lossy() + .to_string(), + ); + + #[cfg(target_os = "macos")] + { + base_path = base_path + .join(format!("zulu-{}.jre", java_version)) + .join("Contents") + .join("Home") + .join("bin") + .join("java") + } + + #[cfg(not(target_os = "macos"))] + { + base_path = base_path.join("bin").join(jre::JAVA_BIN) + } + + Ok(base_path) } else { Err(crate::ErrorKind::LauncherError(format!( "No Java Version found for Java version {}, OS {}, and Architecture {}", diff --git a/theseus/src/state/settings.rs b/theseus/src/state/settings.rs index b88702dc1..b99720bcf 100644 --- a/theseus/src/state/settings.rs +++ b/theseus/src/state/settings.rs @@ -32,6 +32,8 @@ pub struct Settings { pub opt_out_analytics: bool, #[serde(default)] pub advanced_rendering: bool, + #[serde(default)] + pub onboarded: bool, } impl Default for Settings { @@ -52,6 +54,7 @@ impl Default for Settings { developer_mode: false, opt_out_analytics: false, advanced_rendering: true, + onboarded: false, } } } diff --git a/theseus/src/util/jre.rs b/theseus/src/util/jre.rs index e1da33078..d7318c516 100644 --- a/theseus/src/util/jre.rs +++ b/theseus/src/util/jre.rs @@ -31,7 +31,7 @@ pub async fn get_all_jre() -> Result, JREError> { let mut jre_paths = HashSet::new(); // Add JRES directly on PATH - jre_paths.extend(get_all_jre_path().await?); + jre_paths.extend(get_all_jre_path().await); jre_paths.extend(get_all_autoinstalled_jre_path().await?); if let Ok(java_home) = env::var("JAVA_HOME") { jre_paths.insert(PathBuf::from(java_home)); @@ -47,8 +47,10 @@ pub async fn get_all_jre() -> Result, JREError> { for java_path in java_paths { let Ok(java_subpaths) = std::fs::read_dir(java_path) else {continue }; for java_subpath in java_subpaths { - let path = java_subpath?.path(); - jre_paths.insert(path.join("bin")); + if let Ok(java_subpath) = java_subpath { + let path = java_subpath.path(); + jre_paths.insert(path.join("bin")); + } } } @@ -68,18 +70,18 @@ pub async fn get_all_jre() -> Result, JREError> { if let Ok(jre_key) = RegKey::predef(HKEY_LOCAL_MACHINE) .open_subkey_with_flags(key, KEY_READ | KEY_WOW64_32KEY) { - jre_paths.extend(get_paths_from_jre_winregkey(jre_key)?); + jre_paths.extend(get_paths_from_jre_winregkey(jre_key)); } if let Ok(jre_key) = RegKey::predef(HKEY_LOCAL_MACHINE) .open_subkey_with_flags(key, KEY_READ | KEY_WOW64_64KEY) { - jre_paths.extend(get_paths_from_jre_winregkey(jre_key)?); + jre_paths.extend(get_paths_from_jre_winregkey(jre_key)); } } // Get JRE versions from potential paths concurrently let j = check_java_at_filepaths(jre_paths) - .await? + .await .into_iter() .collect(); Ok(j) @@ -88,27 +90,26 @@ pub async fn get_all_jre() -> Result, JREError> { // Gets paths rather than search directly as RegKeys should not be passed asynchronously (do not impl Send) #[cfg(target_os = "windows")] #[tracing::instrument] -pub fn get_paths_from_jre_winregkey( - jre_key: RegKey, -) -> Result, JREError> { +pub fn get_paths_from_jre_winregkey(jre_key: RegKey) -> HashSet { let mut jre_paths = HashSet::new(); for subkey in jre_key.enum_keys() { - let subkey = subkey?; - let subkey = jre_key.open_subkey(subkey)?; - - let subkey_value_names = - [r"JavaHome", r"InstallationPath", r"\\hotspot\\MSI"]; - - for subkey_value in subkey_value_names { - let path: Result = - subkey.get_value(subkey_value); - let Ok(path) = path else {continue}; - - jre_paths.insert(PathBuf::from(path).join("bin")); + if let Ok(subkey) = subkey { + if let Ok(subkey) = jre_key.open_subkey(subkey) { + let subkey_value_names = + [r"JavaHome", r"InstallationPath", r"\\hotspot\\MSI"]; + + for subkey_value in subkey_value_names { + let path: Result = + subkey.get_value(subkey_value); + let Ok(path) = path else {continue}; + + jre_paths.insert(PathBuf::from(path).join("bin")); + } + } } } - Ok(jre_paths) + jre_paths } // Entrypoint function (Mac) @@ -120,7 +121,7 @@ pub async fn get_all_jre() -> Result, JREError> { let mut jre_paths = HashSet::new(); // Add JREs directly on PATH - jre_paths.extend(get_all_jre_path().await?); + jre_paths.extend(get_all_jre_path().await); jre_paths.extend(get_all_autoinstalled_jre_path().await?); // Hard paths for locations for commonly installed .exes @@ -134,16 +135,18 @@ pub async fn get_all_jre() -> Result, JREError> { } // Iterate over JavaVirtualMachines/(something)/Contents/Home/bin let base_path = PathBuf::from("/Library/Java/JavaVirtualMachines/"); - if base_path.is_dir() { - for entry in std::fs::read_dir(base_path)? { - let entry = entry?.path().join("Contents/Home/bin"); - jre_paths.insert(entry); + if let Ok(dir) = std::fs::read_dir(base_path) { + for entry in dir { + if let Ok(entry) = entry { + let entry = entry.path().join("Contents/Home/bin"); + jre_paths.insert(entry); + } } } // Get JRE versions from potential paths concurrently let j = check_java_at_filepaths(jre_paths) - .await? + .await .into_iter() .collect(); Ok(j) @@ -158,7 +161,7 @@ pub async fn get_all_jre() -> Result, JREError> { let mut jre_paths = HashSet::new(); // Add JREs directly on PATH - jre_paths.extend(get_all_jre_path().await?); + jre_paths.extend(get_all_jre_path().await); jre_paths.extend(get_all_autoinstalled_jre_path().await?); // Hard paths for locations for commonly installed locations @@ -174,18 +177,20 @@ pub async fn get_all_jre() -> Result, JREError> { let path = PathBuf::from(path); jre_paths.insert(PathBuf::from(&path).join("jre").join("bin")); jre_paths.insert(PathBuf::from(&path).join("bin")); - if path.is_dir() { - for entry in std::fs::read_dir(&path)? { - let entry_path = entry?.path(); - jre_paths.insert(entry_path.join("jre").join("bin")); - jre_paths.insert(entry_path.join("bin")); + if let Ok(dir) = std::fs::read_dir(path) { + for entry in dir { + if let Ok(entry) = entry { + let entry_path = entry.path(); + jre_paths.insert(entry_path.join("jre").join("bin")); + jre_paths.insert(entry_path.join("bin")); + } } } } // Get JRE versions from potential paths concurrently let j = check_java_at_filepaths(jre_paths) - .await? + .await .into_iter() .collect(); Ok(j) @@ -203,13 +208,25 @@ async fn get_all_autoinstalled_jre_path() -> Result, JREError> let base_path = state.directories.java_versions_dir(); if base_path.is_dir() { - for entry in std::fs::read_dir(base_path)? { - let entry = entry?; - let file_path = entry.path().join("bin"); - let contents = std::fs::read_to_string(file_path)?; - - let entry = entry.path().join(contents); - jre_paths.insert(entry); + if let Ok(dir) = std::fs::read_dir(base_path) { + for entry in dir { + if let Ok(entry) = entry { + let file_path = entry.path().join("bin"); + + if let Ok(contents) = + std::fs::read_to_string(file_path.clone()) + { + let entry = entry.path().join(contents); + jre_paths.insert(entry); + } else { + #[cfg(not(target_os = "macos"))] + { + let file_path = file_path.join(JAVA_BIN); + jre_paths.insert(file_path); + } + } + } + } } } @@ -220,26 +237,27 @@ async fn get_all_autoinstalled_jre_path() -> Result, JREError> // Gets all JREs from the PATH env variable #[tracing::instrument] -async fn get_all_jre_path() -> Result, JREError> { +async fn get_all_jre_path() -> HashSet { // Iterate over values in PATH variable, where accessible JREs are referenced - let paths = env::var("PATH")?; - Ok(env::split_paths(&paths).collect()) + let paths = + env::var("PATH").map(|x| env::split_paths(&x).collect::>()); + paths.unwrap_or_else(|_| HashSet::new()) } #[cfg(target_os = "windows")] #[allow(dead_code)] -const JAVA_BIN: &str = "javaw.exe"; +pub const JAVA_BIN: &str = "javaw.exe"; #[cfg(not(target_os = "windows"))] #[allow(dead_code)] -const JAVA_BIN: &str = "java"; +pub const JAVA_BIN: &str = "java"; // For each example filepath in 'paths', perform check_java_at_filepath, checking each one concurrently // and returning a JavaVersion for every valid path that points to a java bin #[tracing::instrument] pub async fn check_java_at_filepaths( paths: HashSet, -) -> Result, JREError> { +) -> HashSet { let jres = stream::iter(paths.into_iter()) .map(|p: PathBuf| { tokio::task::spawn(async move { check_java_at_filepath(&p).await }) @@ -248,8 +266,7 @@ pub async fn check_java_at_filepaths( .collect::>() .await; - let jres: Result, JoinError> = jres.into_iter().collect(); - Ok(jres?.into_iter().flatten().collect()) + jres.into_iter().flat_map(|x| x.ok()).flatten().collect() } // For example filepath 'path', attempt to resolve it and get a Java version at this path @@ -380,19 +397,3 @@ pub enum JREError { #[error("Error getting launcher sttae")] StateError, } - -#[cfg(test)] -mod tests { - use super::extract_java_majorminor_version; - - #[test] - pub fn java_version_parsing() { - assert_eq!(extract_java_majorminor_version("1.8").unwrap(), (1, 8)); - assert_eq!(extract_java_majorminor_version("17.0.6").unwrap(), (1, 17)); - assert_eq!(extract_java_majorminor_version("20").unwrap(), (1, 20)); - assert_eq!( - extract_java_majorminor_version("1.8.0_361").unwrap(), - (1, 8) - ); - } -} diff --git a/theseus_cli/Cargo.toml b/theseus_cli/Cargo.toml index 46927e83f..6ef7fd903 100644 --- a/theseus_cli/Cargo.toml +++ b/theseus_cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "theseus_cli" -version = "0.1.0" +version = "0.2.0" authors = ["Jai A "] edition = "2018" diff --git a/theseus_gui/package.json b/theseus_gui/package.json index bd845eb3c..4f8d69f49 100644 --- a/theseus_gui/package.json +++ b/theseus_gui/package.json @@ -18,8 +18,9 @@ "floating-vue": "^2.0.0-beta.20", "mixpanel-browser": "^2.47.0", "ofetch": "^1.0.1", - "omorphia": "^0.4.28", + "omorphia": "^0.4.31", "pinia": "^2.1.3", + "tauri-plugin-window-state-api": "github:tauri-apps/tauri-plugin-window-state#v1", "vite-svg-loader": "^4.0.0", "vue": "^3.3.4", "vue-multiselect": "^3.0.0-beta.2", diff --git a/theseus_gui/pnpm-lock.yaml b/theseus_gui/pnpm-lock.yaml index 73e185d4c..251c9dac2 100644 --- a/theseus_gui/pnpm-lock.yaml +++ b/theseus_gui/pnpm-lock.yaml @@ -17,11 +17,14 @@ dependencies: specifier: ^1.0.1 version: 1.0.1 omorphia: - specifier: ^0.4.28 - version: 0.4.28 + specifier: ^0.4.31 + version: 0.4.31 pinia: specifier: ^2.1.3 version: 2.1.3(vue@3.3.4) + tauri-plugin-window-state-api: + specifier: github:tauri-apps/tauri-plugin-window-state#v1 + version: github.com/tauri-apps/tauri-plugin-window-state/56fd671f8d5ac2d8b826a358af486f220a125c3d vite-svg-loader: specifier: ^4.0.0 version: 4.0.0 @@ -1333,8 +1336,8 @@ packages: ufo: 1.1.2 dev: false - /omorphia@0.4.28: - resolution: {integrity: sha512-ZTUgBD3ZL+aymS7u5pLaPo8I5FUI8fkoz2dZLtAS5ksGRI5wrWkwIi/kxjpC95A2oDxNQvZaylfwUTK3Z6a2Sw==} + /omorphia@0.4.31: + resolution: {integrity: sha512-xeb9bD42VFRDKCkKz678hBYCIS//Atd4/hx6/YmboJLMEIjIJfS2Ocf9G53G52XkfS4DWs9CIzKz71NDh86kxQ==} dependencies: dayjs: 1.11.7 floating-vue: 2.0.0-beta.20(vue@3.3.4) @@ -1787,3 +1790,11 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} dev: true + + github.com/tauri-apps/tauri-plugin-window-state/56fd671f8d5ac2d8b826a358af486f220a125c3d: + resolution: {tarball: https://codeload.github.com/tauri-apps/tauri-plugin-window-state/tar.gz/56fd671f8d5ac2d8b826a358af486f220a125c3d} + name: tauri-plugin-window-state-api + version: 0.0.0 + dependencies: + '@tauri-apps/api': 1.3.0 + dev: false diff --git a/theseus_gui/src-tauri/Cargo.toml b/theseus_gui/src-tauri/Cargo.toml index 253a91e90..e93dfc13f 100644 --- a/theseus_gui/src-tauri/Cargo.toml +++ b/theseus_gui/src-tauri/Cargo.toml @@ -18,7 +18,7 @@ theseus = { path = "../../theseus", features = ["tauri"] } serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } -tauri = { version = "1.3", features = ["devtools", "dialog", "dialog-open", "macos-private-api", "os-all", "protocol-asset", "shell-open", "updater", "window-close", "window-create", "window-hide", "window-maximize", "window-minimize", "window-set-decorations", "window-show", "window-start-dragging", "window-unmaximize", "window-unminimize"] } +tauri = { version = "1.3", features = ["app-all", "devtools", "dialog", "dialog-open", "macos-private-api", "os-all", "protocol-asset", "shell-open", "updater", "window-close", "window-create", "window-hide", "window-maximize", "window-minimize", "window-set-decorations", "window-show", "window-start-dragging", "window-unmaximize", "window-unminimize"] } tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" } tokio = { version = "1", features = ["full"] } @@ -39,6 +39,8 @@ tracing-error = "0.1" sentry = "0.30" sentry-rust-minidump = "0.5" +window-shadows = "0.2.1" + [target.'cfg(target_os = "macos")'.dependencies] cocoa = "0.24.1" objc = "0.2.7" diff --git a/theseus_gui/src-tauri/src/api/jre.rs b/theseus_gui/src-tauri/src/api/jre.rs index e9bfe293e..e56486d3d 100644 --- a/theseus_gui/src-tauri/src/api/jre.rs +++ b/theseus_gui/src-tauri/src/api/jre.rs @@ -10,22 +10,22 @@ pub async fn jre_get_all_jre() -> Result> { Ok(jre::get_all_jre().await?) } -// Finds the isntallation of Java 7, if it exists +// Finds the installation of Java 8, if it exists #[tauri::command] pub async fn jre_find_jre_8_jres() -> Result> { - Ok(jre::find_java8_jres().await?) + Ok(jre::find_filtered_jres("1.8").await?) } // finds the installation of Java 17, if it exists #[tauri::command] pub async fn jre_find_jre_17_jres() -> Result> { - Ok(jre::find_java17_jres().await?) + Ok(jre::find_filtered_jres("1.17").await?) } // Finds the highest version of Java 18+, if it exists #[tauri::command] pub async fn jre_find_jre_18plus_jres() -> Result> { - Ok(jre::find_java18plus_jres().await?) + Ok(jre::find_filtered_jres("1.18").await?) } // Autodetect Java globals, by searching the users computer. diff --git a/theseus_gui/src-tauri/src/main.rs b/theseus_gui/src-tauri/src/main.rs index 880f63d59..9f81fdea3 100644 --- a/theseus_gui/src-tauri/src/main.rs +++ b/theseus_gui/src-tauri/src/main.rs @@ -5,7 +5,10 @@ use theseus::prelude::*; -use tauri::{Manager, WindowEvent}; +use tauri::Manager; + +use window_shadows::set_shadow; + use tracing_error::ErrorLayer; use tracing_subscriber::EnvFilter; @@ -78,13 +81,21 @@ fn main() { { builder = builder.setup(|app| { let win = app.get_window("main").unwrap(); - win.set_decorations(false); + win.set_decorations(false).unwrap(); Ok(()) }) } + builder = builder.setup(|app| { + let win = app.get_window("main").unwrap(); + set_shadow(&win, true).unwrap(); + Ok(()) + }); + #[cfg(target_os = "macos")] { + use tauri::WindowEvent; + builder = builder .setup(|app| { use api::window_ext::WindowExt; diff --git a/theseus_gui/src-tauri/tauri.conf.json b/theseus_gui/src-tauri/tauri.conf.json index 76c020741..439575f18 100644 --- a/theseus_gui/src-tauri/tauri.conf.json +++ b/theseus_gui/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "Modrinth App", - "version": "0.0.1" + "version": "0.2.0" }, "tauri": { "allowlist": { @@ -40,6 +40,9 @@ }, "os": { "all": true + }, + "app": { + "all": true } }, "macOSPrivateApi": true, @@ -72,7 +75,7 @@ "windows": { "certificateThumbprint": null, "digestAlgorithm": "sha256", - "timestampUrl": "" + "timestampUrl": "http://timestamp.digicert.com" } }, "security": { @@ -92,7 +95,7 @@ "height": 650, "resizable": true, "title": "Modrinth App", - "width": 1140, + "width": 1280, "minHeight": 630, "minWidth": 1100 } diff --git a/theseus_gui/src/App.vue b/theseus_gui/src/App.vue index 08b8ffc61..8dd49f0b8 100644 --- a/theseus_gui/src/App.vue +++ b/theseus_gui/src/App.vue @@ -1,5 +1,5 @@