Onboarding (#132)

* Initial onboarding

* Update OnboardingModal.vue

* Add finish

* Animation

* Automatic opening

* Move onboarding icon to outside of main appbar

* Run lint

* run fmt

* mostly finish

* Finish onboarding

* fix onboarding bug + linux build

* fix build again

* Add back window shadows

---------

Co-authored-by: Geometrically <18202329+Geometrically@users.noreply.github.com>
Co-authored-by: Jai A <jaiagr+gpg@pm.me>
Co-authored-by: Jai A <jai@modrinth.com>
This commit is contained in:
Adrian O.V
2023-06-20 22:03:59 -04:00
committed by GitHub
parent bd697a02f5
commit 8e5a0b8ae2
27 changed files with 635 additions and 248 deletions

19
Cargo.lock generated
View File

@@ -4567,7 +4567,7 @@ dependencies = [
[[package]] [[package]]
name = "theseus" name = "theseus"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"async-tungstenite", "async-tungstenite",
"async_zip", "async_zip",
@@ -4608,7 +4608,7 @@ dependencies = [
[[package]] [[package]]
name = "theseus_cli" name = "theseus_cli"
version = "0.1.0" version = "0.2.0"
dependencies = [ dependencies = [
"argh", "argh",
"color-eyre", "color-eyre",
@@ -4660,6 +4660,7 @@ dependencies = [
"tracing-subscriber 0.2.25", "tracing-subscriber 0.2.25",
"url", "url",
"uuid", "uuid",
"window-shadows",
] ]
[[package]] [[package]]
@@ -4672,7 +4673,7 @@ dependencies = [
[[package]] [[package]]
name = "theseus_playground" name = "theseus_playground"
version = "0.1.0" version = "0.0.0"
dependencies = [ dependencies = [
"daedalus", "daedalus",
"dunce", "dunce",
@@ -5484,6 +5485,18 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 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]] [[package]]
name = "windows" name = "windows"
version = "0.37.0" version = "0.37.0"

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "theseus" name = "theseus"
version = "0.1.0" version = "0.2.0"
authors = ["Jai A <jaiagr+gpg@pm.me>"] authors = ["Jai A <jaiagr+gpg@pm.me>"]
edition = "2018" edition = "2018"

View File

@@ -18,9 +18,9 @@ pub const JAVA_18PLUS_KEY: &str = "JAVA_18PLUS";
// Autodetect JavaSettings default // Autodetect JavaSettings default
// Make a guess for what the default Java global settings should be // Make a guess for what the default Java global settings should be
pub async fn autodetect_java_globals() -> crate::Result<JavaGlobals> { pub async fn autodetect_java_globals() -> crate::Result<JavaGlobals> {
let mut java_8 = find_java8_jres().await?; let mut java_8 = find_filtered_jres("1.8").await?;
let mut java_17 = find_java17_jres().await?; let mut java_17 = find_filtered_jres("1.17").await?;
let mut java_18plus = find_java18plus_jres().await?; let mut java_18plus = find_filtered_jres("1.18").await?;
// Simply select last one found for initial guess // Simply select last one found for initial guess
let mut java_globals = JavaGlobals::new(); let mut java_globals = JavaGlobals::new();
@@ -37,11 +37,13 @@ pub async fn autodetect_java_globals() -> crate::Result<JavaGlobals> {
Ok(java_globals) Ok(java_globals)
} }
// Searches for jres on the system that are 1.18 or higher // Searches for jres on the system given a java version (ex: 1.8, 1.17, 1.18)
pub async fn find_java18plus_jres() -> crate::Result<Vec<JavaVersion>> { pub async fn find_filtered_jres(
let version = extract_java_majorminor_version("1.18")?; version: &str,
) -> crate::Result<Vec<JavaVersion>> {
let version = extract_java_majorminor_version(version)?;
let jres = jre::get_all_jre().await?; let jres = jre::get_all_jre().await?;
// Filter out JREs that are not 1.17 or higher
Ok(jres Ok(jres
.into_iter() .into_iter()
.filter(|jre| { .filter(|jre| {
@@ -55,44 +57,6 @@ pub async fn find_java18plus_jres() -> crate::Result<Vec<JavaVersion>> {
.collect()) .collect())
} }
// Searches for jres on the system that are 1.8 exactly
pub async fn find_java8_jres() -> crate::Result<Vec<JavaVersion>> {
let version = extract_java_majorminor_version("1.8")?;
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<Vec<JavaVersion>> {
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
} else {
false
}
})
.collect())
}
#[theseus_macros::debug_pin] #[theseus_macros::debug_pin]
pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> { pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
let state = State::get().await?; let state = State::get().await?;
@@ -157,16 +121,31 @@ pub async fn auto_install_java(java_version: u32) -> crate::Result<PathBuf> {
)) ))
})?; })?;
emit_loading(&loading_bar, 10.0, Some("Done extracting java")).await?; emit_loading(&loading_bar, 10.0, Some("Done extracting java")).await?;
Ok(path let mut base_path = path.join(
.join( download
download .name
.name .file_stem()
.file_stem() .unwrap_or_default()
.unwrap_or_default() .to_string_lossy()
.to_string_lossy() .to_string(),
.to_string(), );
)
.join(format!("zulu-{}.jre/Contents/Home/bin/java", java_version))) #[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 { } else {
Err(crate::ErrorKind::LauncherError(format!( Err(crate::ErrorKind::LauncherError(format!(
"No Java Version found for Java version {}, OS {}, and Architecture {}", "No Java Version found for Java version {}, OS {}, and Architecture {}",

View File

@@ -32,6 +32,8 @@ pub struct Settings {
pub opt_out_analytics: bool, pub opt_out_analytics: bool,
#[serde(default)] #[serde(default)]
pub advanced_rendering: bool, pub advanced_rendering: bool,
#[serde(default)]
pub onboarded: bool,
} }
impl Default for Settings { impl Default for Settings {
@@ -52,6 +54,7 @@ impl Default for Settings {
developer_mode: false, developer_mode: false,
opt_out_analytics: false, opt_out_analytics: false,
advanced_rendering: true, advanced_rendering: true,
onboarded: false,
} }
} }
} }

View File

@@ -31,7 +31,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
let mut jre_paths = HashSet::new(); let mut jre_paths = HashSet::new();
// Add JRES directly on PATH // 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?); jre_paths.extend(get_all_autoinstalled_jre_path().await?);
if let Ok(java_home) = env::var("JAVA_HOME") { if let Ok(java_home) = env::var("JAVA_HOME") {
jre_paths.insert(PathBuf::from(java_home)); jre_paths.insert(PathBuf::from(java_home));
@@ -47,8 +47,10 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
for java_path in java_paths { for java_path in java_paths {
let Ok(java_subpaths) = std::fs::read_dir(java_path) else {continue }; let Ok(java_subpaths) = std::fs::read_dir(java_path) else {continue };
for java_subpath in java_subpaths { for java_subpath in java_subpaths {
let path = java_subpath?.path(); if let Ok(java_subpath) = java_subpath {
jre_paths.insert(path.join("bin")); let path = java_subpath.path();
jre_paths.insert(path.join("bin"));
}
} }
} }
@@ -68,18 +70,18 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
if let Ok(jre_key) = RegKey::predef(HKEY_LOCAL_MACHINE) if let Ok(jre_key) = RegKey::predef(HKEY_LOCAL_MACHINE)
.open_subkey_with_flags(key, KEY_READ | KEY_WOW64_32KEY) .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) if let Ok(jre_key) = RegKey::predef(HKEY_LOCAL_MACHINE)
.open_subkey_with_flags(key, KEY_READ | KEY_WOW64_64KEY) .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 // Get JRE versions from potential paths concurrently
let j = check_java_at_filepaths(jre_paths) let j = check_java_at_filepaths(jre_paths)
.await? .await
.into_iter() .into_iter()
.collect(); .collect();
Ok(j) Ok(j)
@@ -88,27 +90,26 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
// Gets paths rather than search directly as RegKeys should not be passed asynchronously (do not impl Send) // Gets paths rather than search directly as RegKeys should not be passed asynchronously (do not impl Send)
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
#[tracing::instrument] #[tracing::instrument]
pub fn get_paths_from_jre_winregkey( pub fn get_paths_from_jre_winregkey(jre_key: RegKey) -> HashSet<PathBuf> {
jre_key: RegKey,
) -> Result<HashSet<PathBuf>, JREError> {
let mut jre_paths = HashSet::new(); let mut jre_paths = HashSet::new();
for subkey in jre_key.enum_keys() { for subkey in jre_key.enum_keys() {
let subkey = subkey?; if let Ok(subkey) = subkey {
let subkey = jre_key.open_subkey(subkey)?; if let Ok(subkey) = jre_key.open_subkey(subkey) {
let subkey_value_names =
[r"JavaHome", r"InstallationPath", r"\\hotspot\\MSI"];
let subkey_value_names = for subkey_value in subkey_value_names {
[r"JavaHome", r"InstallationPath", r"\\hotspot\\MSI"]; let path: Result<String, std::io::Error> =
subkey.get_value(subkey_value);
let Ok(path) = path else {continue};
for subkey_value in subkey_value_names { jre_paths.insert(PathBuf::from(path).join("bin"));
let path: Result<String, std::io::Error> = }
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) // Entrypoint function (Mac)
@@ -120,7 +121,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
let mut jre_paths = HashSet::new(); let mut jre_paths = HashSet::new();
// Add JREs directly on PATH // 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?); jre_paths.extend(get_all_autoinstalled_jre_path().await?);
// Hard paths for locations for commonly installed .exes // Hard paths for locations for commonly installed .exes
@@ -134,16 +135,18 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
} }
// Iterate over JavaVirtualMachines/(something)/Contents/Home/bin // Iterate over JavaVirtualMachines/(something)/Contents/Home/bin
let base_path = PathBuf::from("/Library/Java/JavaVirtualMachines/"); let base_path = PathBuf::from("/Library/Java/JavaVirtualMachines/");
if base_path.is_dir() { if let Ok(dir) = std::fs::read_dir(base_path) {
for entry in std::fs::read_dir(base_path)? { for entry in dir {
let entry = entry?.path().join("Contents/Home/bin"); if let Ok(entry) = entry {
jre_paths.insert(entry); let entry = entry.path().join("Contents/Home/bin");
jre_paths.insert(entry);
}
} }
} }
// Get JRE versions from potential paths concurrently // Get JRE versions from potential paths concurrently
let j = check_java_at_filepaths(jre_paths) let j = check_java_at_filepaths(jre_paths)
.await? .await
.into_iter() .into_iter()
.collect(); .collect();
Ok(j) Ok(j)
@@ -158,7 +161,7 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
let mut jre_paths = HashSet::new(); let mut jre_paths = HashSet::new();
// Add JREs directly on PATH // 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?); jre_paths.extend(get_all_autoinstalled_jre_path().await?);
// Hard paths for locations for commonly installed locations // Hard paths for locations for commonly installed locations
@@ -174,18 +177,20 @@ pub async fn get_all_jre() -> Result<Vec<JavaVersion>, JREError> {
let path = PathBuf::from(path); let path = PathBuf::from(path);
jre_paths.insert(PathBuf::from(&path).join("jre").join("bin")); jre_paths.insert(PathBuf::from(&path).join("jre").join("bin"));
jre_paths.insert(PathBuf::from(&path).join("bin")); jre_paths.insert(PathBuf::from(&path).join("bin"));
if path.is_dir() { if let Ok(dir) = std::fs::read_dir(path) {
for entry in std::fs::read_dir(&path)? { for entry in dir {
let entry_path = entry?.path(); if let Ok(entry) = entry {
jre_paths.insert(entry_path.join("jre").join("bin")); let entry_path = entry.path();
jre_paths.insert(entry_path.join("bin")); jre_paths.insert(entry_path.join("jre").join("bin"));
jre_paths.insert(entry_path.join("bin"));
}
} }
} }
} }
// Get JRE versions from potential paths concurrently // Get JRE versions from potential paths concurrently
let j = check_java_at_filepaths(jre_paths) let j = check_java_at_filepaths(jre_paths)
.await? .await
.into_iter() .into_iter()
.collect(); .collect();
Ok(j) Ok(j)
@@ -203,13 +208,25 @@ async fn get_all_autoinstalled_jre_path() -> Result<HashSet<PathBuf>, JREError>
let base_path = state.directories.java_versions_dir(); let base_path = state.directories.java_versions_dir();
if base_path.is_dir() { if base_path.is_dir() {
for entry in std::fs::read_dir(base_path)? { if let Ok(dir) = std::fs::read_dir(base_path) {
let entry = entry?; for entry in dir {
let file_path = entry.path().join("bin"); if let Ok(entry) = entry {
let contents = std::fs::read_to_string(file_path)?; let file_path = entry.path().join("bin");
let entry = entry.path().join(contents); if let Ok(contents) =
jre_paths.insert(entry); 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<HashSet<PathBuf>, JREError>
// Gets all JREs from the PATH env variable // Gets all JREs from the PATH env variable
#[tracing::instrument] #[tracing::instrument]
async fn get_all_jre_path() -> Result<HashSet<PathBuf>, JREError> { async fn get_all_jre_path() -> HashSet<PathBuf> {
// Iterate over values in PATH variable, where accessible JREs are referenced // Iterate over values in PATH variable, where accessible JREs are referenced
let paths = env::var("PATH")?; let paths =
Ok(env::split_paths(&paths).collect()) env::var("PATH").map(|x| env::split_paths(&x).collect::<HashSet<_>>());
paths.unwrap_or_else(|_| HashSet::new())
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]
#[allow(dead_code)] #[allow(dead_code)]
const JAVA_BIN: &str = "javaw.exe"; pub const JAVA_BIN: &str = "javaw.exe";
#[cfg(not(target_os = "windows"))] #[cfg(not(target_os = "windows"))]
#[allow(dead_code)] #[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 // 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 // and returning a JavaVersion for every valid path that points to a java bin
#[tracing::instrument] #[tracing::instrument]
pub async fn check_java_at_filepaths( pub async fn check_java_at_filepaths(
paths: HashSet<PathBuf>, paths: HashSet<PathBuf>,
) -> Result<HashSet<JavaVersion>, JREError> { ) -> HashSet<JavaVersion> {
let jres = stream::iter(paths.into_iter()) let jres = stream::iter(paths.into_iter())
.map(|p: PathBuf| { .map(|p: PathBuf| {
tokio::task::spawn(async move { check_java_at_filepath(&p).await }) tokio::task::spawn(async move { check_java_at_filepath(&p).await })
@@ -248,8 +266,7 @@ pub async fn check_java_at_filepaths(
.collect::<Vec<_>>() .collect::<Vec<_>>()
.await; .await;
let jres: Result<Vec<_>, JoinError> = jres.into_iter().collect(); jres.into_iter().flat_map(|x| x.ok()).flatten().collect()
Ok(jres?.into_iter().flatten().collect())
} }
// For example filepath 'path', attempt to resolve it and get a Java version at this path // 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")] #[error("Error getting launcher sttae")]
StateError, 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)
);
}
}

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "theseus_cli" name = "theseus_cli"
version = "0.1.0" version = "0.2.0"
authors = ["Jai A <jaiagr+gpg@pm.me>"] authors = ["Jai A <jaiagr+gpg@pm.me>"]
edition = "2018" edition = "2018"

View File

@@ -18,8 +18,9 @@
"floating-vue": "^2.0.0-beta.20", "floating-vue": "^2.0.0-beta.20",
"mixpanel-browser": "^2.47.0", "mixpanel-browser": "^2.47.0",
"ofetch": "^1.0.1", "ofetch": "^1.0.1",
"omorphia": "^0.4.28", "omorphia": "^0.4.31",
"pinia": "^2.1.3", "pinia": "^2.1.3",
"tauri-plugin-window-state-api": "github:tauri-apps/tauri-plugin-window-state#v1",
"vite-svg-loader": "^4.0.0", "vite-svg-loader": "^4.0.0",
"vue": "^3.3.4", "vue": "^3.3.4",
"vue-multiselect": "^3.0.0-beta.2", "vue-multiselect": "^3.0.0-beta.2",

View File

@@ -17,11 +17,14 @@ dependencies:
specifier: ^1.0.1 specifier: ^1.0.1
version: 1.0.1 version: 1.0.1
omorphia: omorphia:
specifier: ^0.4.28 specifier: ^0.4.31
version: 0.4.28 version: 0.4.31
pinia: pinia:
specifier: ^2.1.3 specifier: ^2.1.3
version: 2.1.3(vue@3.3.4) 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: vite-svg-loader:
specifier: ^4.0.0 specifier: ^4.0.0
version: 4.0.0 version: 4.0.0
@@ -1333,8 +1336,8 @@ packages:
ufo: 1.1.2 ufo: 1.1.2
dev: false dev: false
/omorphia@0.4.28: /omorphia@0.4.31:
resolution: {integrity: sha512-ZTUgBD3ZL+aymS7u5pLaPo8I5FUI8fkoz2dZLtAS5ksGRI5wrWkwIi/kxjpC95A2oDxNQvZaylfwUTK3Z6a2Sw==} resolution: {integrity: sha512-xeb9bD42VFRDKCkKz678hBYCIS//Atd4/hx6/YmboJLMEIjIJfS2Ocf9G53G52XkfS4DWs9CIzKz71NDh86kxQ==}
dependencies: dependencies:
dayjs: 1.11.7 dayjs: 1.11.7
floating-vue: 2.0.0-beta.20(vue@3.3.4) floating-vue: 2.0.0-beta.20(vue@3.3.4)
@@ -1787,3 +1790,11 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'} engines: {node: '>=10'}
dev: true 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

View File

@@ -18,7 +18,7 @@ theseus = { path = "../../theseus", features = ["tauri"] }
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } 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-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" } tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v1" }
tokio = { version = "1", features = ["full"] } tokio = { version = "1", features = ["full"] }
@@ -39,6 +39,8 @@ tracing-error = "0.1"
sentry = "0.30" sentry = "0.30"
sentry-rust-minidump = "0.5" sentry-rust-minidump = "0.5"
window-shadows = "0.2.1"
[target.'cfg(target_os = "macos")'.dependencies] [target.'cfg(target_os = "macos")'.dependencies]
cocoa = "0.24.1" cocoa = "0.24.1"
objc = "0.2.7" objc = "0.2.7"

View File

@@ -10,22 +10,22 @@ pub async fn jre_get_all_jre() -> Result<Vec<JavaVersion>> {
Ok(jre::get_all_jre().await?) 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] #[tauri::command]
pub async fn jre_find_jre_8_jres() -> Result<Vec<JavaVersion>> { pub async fn jre_find_jre_8_jres() -> Result<Vec<JavaVersion>> {
Ok(jre::find_java8_jres().await?) Ok(jre::find_filtered_jres("1.8").await?)
} }
// finds the installation of Java 17, if it exists // finds the installation of Java 17, if it exists
#[tauri::command] #[tauri::command]
pub async fn jre_find_jre_17_jres() -> Result<Vec<JavaVersion>> { pub async fn jre_find_jre_17_jres() -> Result<Vec<JavaVersion>> {
Ok(jre::find_java17_jres().await?) Ok(jre::find_filtered_jres("1.17").await?)
} }
// Finds the highest version of Java 18+, if it exists // Finds the highest version of Java 18+, if it exists
#[tauri::command] #[tauri::command]
pub async fn jre_find_jre_18plus_jres() -> Result<Vec<JavaVersion>> { pub async fn jre_find_jre_18plus_jres() -> Result<Vec<JavaVersion>> {
Ok(jre::find_java18plus_jres().await?) Ok(jre::find_filtered_jres("1.18").await?)
} }
// Autodetect Java globals, by searching the users computer. // Autodetect Java globals, by searching the users computer.

View File

@@ -5,7 +5,10 @@
use theseus::prelude::*; use theseus::prelude::*;
use tauri::{Manager, WindowEvent}; use tauri::Manager;
use window_shadows::set_shadow;
use tracing_error::ErrorLayer; use tracing_error::ErrorLayer;
use tracing_subscriber::EnvFilter; use tracing_subscriber::EnvFilter;
@@ -78,13 +81,21 @@ fn main() {
{ {
builder = builder.setup(|app| { builder = builder.setup(|app| {
let win = app.get_window("main").unwrap(); let win = app.get_window("main").unwrap();
win.set_decorations(false); win.set_decorations(false).unwrap();
Ok(()) Ok(())
}) })
} }
builder = builder.setup(|app| {
let win = app.get_window("main").unwrap();
set_shadow(&win, true).unwrap();
Ok(())
});
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
{ {
use tauri::WindowEvent;
builder = builder builder = builder
.setup(|app| { .setup(|app| {
use api::window_ext::WindowExt; use api::window_ext::WindowExt;

View File

@@ -8,7 +8,7 @@
}, },
"package": { "package": {
"productName": "Modrinth App", "productName": "Modrinth App",
"version": "0.0.1" "version": "0.2.0"
}, },
"tauri": { "tauri": {
"allowlist": { "allowlist": {
@@ -40,6 +40,9 @@
}, },
"os": { "os": {
"all": true "all": true
},
"app": {
"all": true
} }
}, },
"macOSPrivateApi": true, "macOSPrivateApi": true,
@@ -72,7 +75,7 @@
"windows": { "windows": {
"certificateThumbprint": null, "certificateThumbprint": null,
"digestAlgorithm": "sha256", "digestAlgorithm": "sha256",
"timestampUrl": "" "timestampUrl": "http://timestamp.digicert.com"
} }
}, },
"security": { "security": {
@@ -92,7 +95,7 @@
"height": 650, "height": 650,
"resizable": true, "resizable": true,
"title": "Modrinth App", "title": "Modrinth App",
"width": 1140, "width": 1280,
"minHeight": 630, "minHeight": 630,
"minWidth": 1100 "minWidth": 1100
} }

View File

@@ -1,5 +1,5 @@
<script setup> <script setup>
import { handleError, onMounted, ref, watch } from 'vue' import { ref, watch } from 'vue'
import { RouterView, RouterLink, useRouter } from 'vue-router' import { RouterView, RouterLink, useRouter } from 'vue-router'
import { import {
HomeIcon, HomeIcon,
@@ -26,35 +26,20 @@ import { type } from '@tauri-apps/api/os'
import { appWindow } from '@tauri-apps/api/window' import { appWindow } from '@tauri-apps/api/window'
import { isDev } from '@/helpers/utils.js' import { isDev } from '@/helpers/utils.js'
import mixpanel from 'mixpanel-browser' import mixpanel from 'mixpanel-browser'
import { saveWindowState, StateFlags } from 'tauri-plugin-window-state-api'
import OnboardingModal from '@/components/OnboardingModal.vue'
import { getVersion } from '@tauri-apps/api/app'
const themeStore = useTheming() const themeStore = useTheming()
const isLoading = ref(true) const isLoading = ref(true)
onMounted(async () => {
const { settings, collapsed_navigation } = await get().catch(handleError)
themeStore.setThemeState(settings)
themeStore.collapsedNavigation = collapsed_navigation
await warning_listener((e) =>
notificationsWrapper.value.addNotification({
title: 'Warning',
text: e.message,
type: 'warn',
})
)
if ((await type()) === 'Darwin') {
document.getElementsByTagName('html')[0].classList.add('mac')
} else {
document.getElementsByTagName('html')[0].classList.add('windows')
}
})
defineExpose({ defineExpose({
initialize: async () => { initialize: async () => {
isLoading.value = false isLoading.value = false
const { theme, opt_out_analytics, collapsed_navigation, advanced_rendering } = await get() const { theme, opt_out_analytics, collapsed_navigation, advanced_rendering, onboarded } =
await get()
const dev = await isDev() const dev = await isDev()
const version = await getVersion()
themeStore.setThemeState(theme) themeStore.setThemeState(theme)
themeStore.collapsedNavigation = collapsed_navigation themeStore.collapsedNavigation = collapsed_navigation
@@ -64,10 +49,16 @@ defineExpose({
if (opt_out_analytics) { if (opt_out_analytics) {
mixpanel.opt_out_tracking() mixpanel.opt_out_tracking()
} }
mixpanel.track('Launched') mixpanel.track('Launched', { version, dev, onboarded })
if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault()) if (!dev) document.addEventListener('contextmenu', (event) => event.preventDefault())
if ((await type()) === 'Darwin') {
document.getElementsByTagName('html')[0].classList.add('mac')
} else {
document.getElementsByTagName('html')[0].classList.add('windows')
}
await warning_listener((e) => await warning_listener((e) =>
notificationsWrapper.value.addNotification({ notificationsWrapper.value.addNotification({
title: 'Warning', title: 'Warning',
@@ -119,15 +110,23 @@ document.querySelector('body').addEventListener('click', function (e) {
target = target.parentElement target = target.parentElement
} }
}) })
const accounts = ref(null)
</script> </script>
<template> <template>
<SplashScreen v-if="isLoading" app-loading /> <SplashScreen v-if="isLoading" app-loading />
<div v-else class="container"> <div v-else class="container">
<suspense>
<OnboardingModal ref="testModal" :accounts="accounts" />
</suspense>
<div class="nav-container" :class="{ expanded: !themeStore.collapsedNavigation }"> <div class="nav-container" :class="{ expanded: !themeStore.collapsedNavigation }">
<div class="nav-section"> <div class="nav-section">
<suspense> <suspense>
<AccountsCard ref="accounts" :expanded="!themeStore.collapsedNavigation" /> <AccountsCard
ref="accounts"
:mode="themeStore.collapsedNavigation ? 'small' : 'expanded'"
/>
</suspense> </suspense>
<div class="pages-list"> <div class="pages-list">
<RouterLink <RouterLink
@@ -215,7 +214,16 @@ document.querySelector('body').addEventListener('click', function (e) {
<Button class="titlebar-button" icon-only @click="() => appWindow.toggleMaximize()"> <Button class="titlebar-button" icon-only @click="() => appWindow.toggleMaximize()">
<MaximizeIcon /> <MaximizeIcon />
</Button> </Button>
<Button class="titlebar-button close" icon-only @click="() => appWindow.close()"> <Button
class="titlebar-button close"
icon-only
@click="
() => {
saveWindowState(StateFlags.ALL)
appWindow.close()
}
"
>
<XIcon /> <XIcon />
</Button> </Button>
</section> </section>
@@ -250,10 +258,11 @@ document.querySelector('body').addEventListener('click', function (e) {
} }
.window-controls { .window-controls {
z-index: 20;
display: none; display: none;
flex-direction: row; flex-direction: row;
align-items: center; align-items: center;
gap: 0; gap: 0.25rem;
.titlebar-button { .titlebar-button {
display: flex; display: flex;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

View File

@@ -4,4 +4,3 @@ export { default as KoFiIcon } from './kofi.svg'
export { default as PatreonIcon } from './patreon.svg' export { default as PatreonIcon } from './patreon.svg'
export { default as PaypalIcon } from './paypal.svg' export { default as PaypalIcon } from './paypal.svg'
export { default as OpenCollectiveIcon } from './opencollective.svg' export { default as OpenCollectiveIcon } from './opencollective.svg'
export { default as Default } from './default.png'

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +1,16 @@
<template> <template>
<div <div
v-if="mode !== 'isolated'"
ref="button" ref="button"
class="button-base avatar-button" class="button-base avatar-button"
:class="{ expanded: expanded }" :class="{ expanded: mode === 'expanded' }"
@click="toggle()" @click="showCard = !showCard"
> >
<Avatar :size="expanded ? 'xs' : 'sm'" :src="selectedAccount?.profile_picture ?? ''" /> <Avatar
<div v-show="expanded" class="avatar-text"> :size="mode === 'expanded' ? 'xs' : 'sm'"
:src="selectedAccount ? `https://mc-heads.net/avatar/${selectedAccount.id}/128` : ''"
/>
<div v-show="mode === 'expanded'" class="avatar-text">
<div class="text no-select"> <div class="text no-select">
{{ selectedAccount ? selectedAccount.username : 'Offline' }} {{ selectedAccount ? selectedAccount.username : 'Offline' }}
</div> </div>
@@ -17,9 +21,14 @@
</div> </div>
</div> </div>
<transition name="fade"> <transition name="fade">
<Card v-if="showCard" ref="card" class="account-card" :class="{ expanded: expanded }"> <Card
v-if="showCard || mode === 'isolated'"
ref="card"
class="account-card"
:class="{ expanded: mode === 'expanded', isolated: mode === 'isolated' }"
>
<div v-if="selectedAccount" class="selected account"> <div v-if="selectedAccount" class="selected account">
<Avatar size="xs" :src="selectedAccount.profile_picture" /> <Avatar size="xs" :src="`https://mc-heads.net/avatar/${selectedAccount.id}/128`" />
<div> <div>
<h4>{{ selectedAccount.username }}</h4> <h4>{{ selectedAccount.username }}</h4>
<p>Selected</p> <p>Selected</p>
@@ -37,7 +46,7 @@
<div v-if="displayAccounts.length > 0" class="account-group"> <div v-if="displayAccounts.length > 0" class="account-group">
<div v-for="account in displayAccounts" :key="account.id" class="account-row"> <div v-for="account in displayAccounts" :key="account.id" class="account-row">
<Button class="option account" @click="setAccount(account)"> <Button class="option account" @click="setAccount(account)">
<Avatar :src="account.profile_picture" class="icon" /> <Avatar :src="`https://mc-heads.net/avatar/${account.id}/128`" class="icon" />
<p>{{ account.username }}</p> <p>{{ account.username }}</p>
</Button> </Button>
<Button v-tooltip="'Log out'" icon-only @click="logout(account.id)"> <Button v-tooltip="'Log out'" icon-only @click="logout(account.id)">
@@ -55,7 +64,7 @@
<script setup> <script setup>
import { Avatar, Button, Card, PlusIcon, TrashIcon, UsersIcon, LogInIcon } from 'omorphia' import { Avatar, Button, Card, PlusIcon, TrashIcon, UsersIcon, LogInIcon } from 'omorphia'
import { ref, defineProps, computed, onMounted, onBeforeUnmount } from 'vue' import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { import {
users, users,
remove_user, remove_user,
@@ -68,51 +77,41 @@ import { handleError } from '@/store/state.js'
import mixpanel from 'mixpanel-browser' import mixpanel from 'mixpanel-browser'
defineProps({ defineProps({
expanded: { mode: {
type: Boolean, type: String,
required: true, required: true,
default: 'normal',
}, },
}) })
const settings = ref(await get().catch(handleError)) const emit = defineEmits(['change'])
const appendProfiles = (accounts) => { const settings = ref({})
return accounts.map((account) => { const accounts = ref([])
return { async function refreshValues() {
...account, settings.value = await get().catch(handleError)
profile_picture: `https://mc-heads.net/avatar/${account.id}/128`, accounts.value = await users().catch(handleError)
}
})
} }
defineExpose({
const accounts = ref(await users().then(appendProfiles).catch(handleError)) refreshValues,
})
await refreshValues()
const displayAccounts = computed(() => const displayAccounts = computed(() =>
accounts.value.filter((account) => settings.value.default_user !== account.id) accounts.value.filter((account) => settings.value.default_user !== account.id)
) )
const selectedAccount = ref( const selectedAccount = computed(() =>
accounts.value.find((account) => account.id === settings.value.default_user) accounts.value.find((account) => account.id === settings.value.default_user)
) )
const refreshValues = async () => { async function setAccount(account) {
accounts.value = await users().then(appendProfiles).catch(handleError)
selectedAccount.value = accounts.value.find(
(account) => account.id === settings.value.default_user
)
}
let showCard = ref(false)
let card = ref(null)
let button = ref(null)
const setAccount = async (account) => {
settings.value.default_user = account.id settings.value.default_user = account.id
selectedAccount.value = account
await set(settings.value).catch(handleError) await set(settings.value).catch(handleError)
emit('change')
} }
const login = async () => { async function login() {
const url = await authenticate_begin_flow().catch(handleError) const url = await authenticate_begin_flow().catch(handleError)
const window = new WebviewWindow('loginWindow', { const window = new WebviewWindow('loginWindow', {
@@ -120,14 +119,6 @@ const login = async () => {
url: url, url: url,
}) })
window.once('tauri://created', function () {
console.log('webview created')
})
window.once('tauri://error', function (e) {
console.log('webview error', e)
})
const loggedIn = await authenticate_await_completion().catch(handleError) const loggedIn = await authenticate_await_completion().catch(handleError)
await setAccount(loggedIn) await setAccount(loggedIn)
await refreshValues() await refreshValues()
@@ -141,14 +132,15 @@ const logout = async (id) => {
if (!selectedAccount.value && accounts.value.length > 0) { if (!selectedAccount.value && accounts.value.length > 0) {
await setAccount(accounts.value[0]) await setAccount(accounts.value[0])
await refreshValues() await refreshValues()
} else {
emit('change')
} }
mixpanel.track('AccountLogOut') mixpanel.track('AccountLogOut')
} }
const toggle = () => { let showCard = ref(false)
showCard.value = !showCard.value let card = ref(null)
} let button = ref(null)
const handleClickOutside = (event) => { const handleClickOutside = (event) => {
const elements = document.elementsFromPoint(event.clientX, event.clientY) const elements = document.elementsFromPoint(event.clientX, event.clientY)
if ( if (
@@ -219,6 +211,12 @@ onBeforeUnmount(() => {
&.expanded { &.expanded {
left: 13.5rem; left: 13.5rem;
} }
&.isolated {
position: relative;
left: 0;
top: 0;
}
} }
.accounts-title { .accounts-title {

View File

@@ -61,7 +61,6 @@ const hideContextMenu = () => {
} }
const optionClicked = (option) => { const optionClicked = (option) => {
console.log('item check', item.value)
emit('option-clicked', { emit('option-clicked', {
item: item.value, item: item.value,
option: option, option: option,

View File

@@ -57,7 +57,7 @@
<script setup> <script setup>
import { Button, Modal, XIcon, DownloadIcon, DropdownSelect, formatCategory } from 'omorphia' import { Button, Modal, XIcon, DownloadIcon, DropdownSelect, formatCategory } from 'omorphia'
import { add_project_from_version as installMod } from '@/helpers/profile' import { add_project_from_version as installMod } from '@/helpers/profile'
import { defineExpose, ref } from 'vue' import { ref } from 'vue'
import { handleError, useTheming } from '@/store/state.js' import { handleError, useTheming } from '@/store/state.js'
import mixpanel from 'mixpanel-browser' import mixpanel from 'mixpanel-browser'

View File

@@ -1,6 +1,6 @@
<template> <template>
<JavaDetectionModal ref="detectJavaModal" @submit="(val) => emit('update:modelValue', val)" /> <JavaDetectionModal ref="detectJavaModal" @submit="(val) => emit('update:modelValue', val)" />
<div class="toggle-setting"> <div class="toggle-setting" :class="{ compact }">
<input <input
autocomplete="off" autocomplete="off"
:disabled="props.disabled" :disabled="props.disabled"
@@ -18,10 +18,7 @@
" "
/> />
<span class="installation-buttons"> <span class="installation-buttons">
<Button <Button :disabled="props.disabled" @click="autoDetect">
:disabled="props.disabled"
@click="$refs.detectJavaModal.show(props.version, props.modelValue)"
>
<SearchIcon /> <SearchIcon />
Auto detect Auto detect
</Button> </Button>
@@ -48,11 +45,12 @@
<script setup> <script setup>
import { Button, SearchIcon, PlayIcon, CheckIcon, XIcon, FolderSearchIcon } from 'omorphia' import { Button, SearchIcon, PlayIcon, CheckIcon, XIcon, FolderSearchIcon } from 'omorphia'
import { get_jre } from '@/helpers/jre.js' import { find_jre_17_jres, get_jre } from '@/helpers/jre.js'
import { ref } from 'vue' import { ref } from 'vue'
import { open } from '@tauri-apps/api/dialog' import { open } from '@tauri-apps/api/dialog'
import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue' import JavaDetectionModal from '@/components/ui/JavaDetectionModal.vue'
import mixpanel from 'mixpanel-browser' import mixpanel from 'mixpanel-browser'
import { handleError } from '@/store/state.js'
const props = defineProps({ const props = defineProps({
version: { version: {
@@ -74,6 +72,10 @@ const props = defineProps({
required: false, required: false,
default: null, default: null,
}, },
compact: {
type: Boolean,
default: false,
},
}) })
const emit = defineEmits(['update:modelValue']) const emit = defineEmits(['update:modelValue'])
@@ -117,6 +119,18 @@ async function handleJavaFileInput() {
emit('update:modelValue', result) emit('update:modelValue', result)
} }
} }
const detectJavaModal = ref(null)
async function autoDetect() {
if (!props.compact) {
detectJavaModal.value.show(props.version, props.modelValue)
} else {
let versions = await find_jre_17_jres().catch(handleError)
if (versions.length > 0) {
emit('update:modelValue', versions[0])
}
}
}
</script> </script>
<style lang="scss" scoped> <style lang="scss" scoped>
@@ -131,12 +145,15 @@ async function handleJavaFileInput() {
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
&.compact {
flex-wrap: wrap;
}
} }
.installation-buttons { .installation-buttons {
display: flex; display: flex;
flex-direction: row; flex-direction: row;
flex-wrap: wrap;
align-items: center; align-items: center;
gap: 0.5rem; gap: 0.5rem;
margin: 0; margin: 0;

View File

@@ -47,18 +47,7 @@
<Card v-if="showCard === true" ref="card" class="info-card"> <Card v-if="showCard === true" ref="card" class="info-card">
<div v-for="loadingBar in currentLoadingBars" :key="loadingBar.id" class="info-text"> <div v-for="loadingBar in currentLoadingBars" :key="loadingBar.id" class="info-text">
<h3 class="info-title"> <h3 class="info-title">
{{ loadingBar.bar_type.pack_name ?? 'Installing Modpack' }} {{ loadingBar.title }}
</h3>
<ProgressBar :progress="Math.floor(loadingBar.current)" />
<div class="row">{{ Math.floor(loadingBar.current) }}% {{ loadingBar.message }}</div>
</div>
</Card>
</transition>
<transition name="download">
<Card v-if="showCard === true" ref="card" class="info-card">
<div v-for="loadingBar in currentLoadingBars" :key="loadingBar.id" class="info-text">
<h3 class="info-title">
{{ loadingBar.bar_type.pack_name ?? 'Installing Modpack' }}
</h3> </h3>
<ProgressBar :progress="Math.floor(loadingBar.current)" /> <ProgressBar :progress="Math.floor(loadingBar.current)" />
<div class="row">{{ Math.floor(loadingBar.current) }}% {{ loadingBar.message }}</div> <div class="row">{{ Math.floor(loadingBar.current) }}% {{ loadingBar.message }}</div>
@@ -123,6 +112,7 @@ const profiles = ref(null)
const infoButton = ref(null) const infoButton = ref(null)
const profileButton = ref(null) const profileButton = ref(null)
const showCard = ref(false) const showCard = ref(false)
const showProfiles = ref(false) const showProfiles = ref(false)
const currentProcesses = ref(await getRunningProfiles().catch(handleError)) const currentProcesses = ref(await getRunningProfiles().catch(handleError))
@@ -159,15 +149,25 @@ const goToTerminal = (path) => {
router.push(`/instance/${encodeURIComponent(path ?? selectedProfile.value.path)}/logs`) router.push(`/instance/${encodeURIComponent(path ?? selectedProfile.value.path)}/logs`)
} }
const currentLoadingBars = ref(Object.values(await progress_bars_list().catch(handleError))) const currentLoadingBars = ref([])
const unlistenLoading = await loading_listener(async () => {
await refreshInfo()
})
const refreshInfo = async () => { const refreshInfo = async () => {
const currentLoadingBarCount = currentLoadingBars.value.length const currentLoadingBarCount = currentLoadingBars.value.length
currentLoadingBars.value = Object.values(await progress_bars_list().catch(handleError)) currentLoadingBars.value = Object.values(await progress_bars_list().catch(handleError)).map(
(x) => {
if (x.bar_type.type === 'java_download') {
x.title = 'Downloading Java ' + x.bar_type.version
}
if (x.bar_type.profile_name) {
x.title = x.bar_type.profile_name
}
if (x.bar_type.pack_name) {
x.title = x.bar_type.pack_name
}
return x
}
)
if (currentLoadingBars.value.length === 0) { if (currentLoadingBars.value.length === 0) {
showCard.value = false showCard.value = false
} else if (currentLoadingBarCount < currentLoadingBars.value.length) { } else if (currentLoadingBarCount < currentLoadingBars.value.length) {
@@ -175,6 +175,11 @@ const refreshInfo = async () => {
} }
} }
await refreshInfo()
const unlistenLoading = await loading_listener(async () => {
await refreshInfo()
})
const selectProfile = (profile) => { const selectProfile = (profile) => {
selectedProfile.value = profile selectedProfile.value = profile
showProfiles.value = false showProfiles.value = false

View File

@@ -1,10 +1,13 @@
import { ofetch } from 'ofetch' import { ofetch } from 'ofetch'
import { handleError } from '@/store/state.js' import { handleError } from '@/store/state.js'
import { getVersion } from '@tauri-apps/api/app'
export const useFetch = async (url, item) => { export const useFetch = async (url, item) => {
try { try {
const version = await getVersion()
return await ofetch(url, { return await ofetch(url, {
headers: { 'User-Agent': 'modrinth/theseus (support@modrinth.com)' }, headers: { 'User-Agent': `modrinth/theseus/${version} (support@modrinth.com)` },
}) })
} catch (err) { } catch (err) {
handleError({ message: `Error fetching ${item}` }) handleError({ message: `Error fetching ${item}` })

View File

@@ -52,12 +52,12 @@ export async function get_jre(path) {
// Autodetect Java globals, by searching the users computer. // Autodetect Java globals, by searching the users computer.
// Returns a *NEW* JavaGlobals that can be put into Settings // Returns a *NEW* JavaGlobals that can be put into Settings
export async function autodetect_java_globals(path) { export async function autodetect_java_globals() {
return await invoke('jre_autodetect_java_globals', { path }) return await invoke('jre_autodetect_java_globals')
} }
// Automatically installs specified java version // Automatically installs specified java version
export async function jre_auto_install_java(javaVersion) { export async function auto_install_java(javaVersion) {
return await invoke('jre_auto_install_java', { javaVersion }) return await invoke('jre_auto_install_java', { javaVersion })
} }

View File

@@ -21,9 +21,7 @@ breadcrumbs.setRootContext({ name: 'Home', link: route.path })
const recentInstances = shallowRef([]) const recentInstances = shallowRef([])
const getInstances = async () => { const getInstances = async () => {
console.log('aa')
const profiles = await list(true).catch(handleError) const profiles = await list(true).catch(handleError)
console.log(profiles)
recentInstances.value = Object.values(profiles).sort((a, b) => { recentInstances.value = Object.values(profiles).sort((a, b) => {
return dayjs(b.metadata.last_played ?? 0).diff(dayjs(a.metadata.last_played ?? 0)) return dayjs(b.metadata.last_played ?? 0).diff(dayjs(a.metadata.last_played ?? 0))
}) })

View File

@@ -221,7 +221,6 @@ const handleRightClick = (event) => {
} }
const handleOptionsClick = async (args) => { const handleOptionsClick = async (args) => {
console.log(args)
switch (args.option) { switch (args.option) {
case 'play': case 'play':
await startInstance('InstancePageContextMenu') await startInstance('InstancePageContextMenu')

View File

@@ -192,7 +192,7 @@ import {
renderString, renderString,
} from 'omorphia' } from 'omorphia'
import { releaseColor } from '@/helpers/utils' import { releaseColor } from '@/helpers/utils'
import { ref, defineProps, watch, computed } from 'vue' import { ref, watch, computed } from 'vue'
import { useRoute } from 'vue-router' import { useRoute } from 'vue-router'
import { useBreadcrumbs } from '@/store/breadcrumbs' import { useBreadcrumbs } from '@/store/breadcrumbs'

View File

@@ -1,6 +1,6 @@
[package] [package]
name = "theseus_playground" name = "theseus_playground"
version = "0.1.0" version = "0.0.0"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html