diff --git a/rust/src/app.rs b/rust/src/app.rs index 1935673..5c4bd8c 100644 --- a/rust/src/app.rs +++ b/rust/src/app.rs @@ -3,7 +3,6 @@ use std::path::PathBuf; use std::sync::Arc; use crate::installer::validator::*; use crate::installer::downloader::DownloadManager; -use crate::installer::SevenZDearchiver; use crate::ui::download_progress::download_progress; use crate::ui::game_selection::game_selection; use crate::ui::installation_progress::installation_progress; @@ -24,7 +23,6 @@ pub enum InstallerState { Complete, } - #[derive(Default)] pub struct DownloadState { pub progress: f32, @@ -281,16 +279,7 @@ impl SinfarInstallerApp<> { } pub fn start_installation(&mut self) { - // Use tokio runtime to handle the async installation - let install_path = self.install_path.clone().expect("Install path should be set"); - let ee_exe_path = self.ee_exe_path.clone(); - let download_state = self.download_state.clone(); - let progress_state = self.download_state.clone(); - let eframe_ctx = self.eframe_ctx.clone().expect("eframe context should be set"); - let runtime = self.runtime.clone(); - let game_type = self.game_type.clone().expect("Game type should be set"); - - // Reset the download state for installation progress + // Reset state if let Ok(mut state) = self.download_state.lock() { state.progress = 0.0; state.completed = false; @@ -298,6 +287,14 @@ impl SinfarInstallerApp<> { state.cancelled = false; } + let install_path = self.install_path.clone().expect("Install path should be set"); + let ee_exe_path = self.ee_exe_path.clone(); + let game_type = self.game_type.clone().expect("Game type should be set"); + let download_state = self.download_state.clone(); + let progress_state = self.download_state.clone(); + let eframe_ctx = self.eframe_ctx.clone().expect("eframe context should be set"); + let runtime = self.runtime.clone(); + // Create extraction manager with progress callback let extractor = crate::installer::extractor::ExtractionManager::new(move |progress: f32, _filename: &str, remaining: std::time::Duration| { if let Ok(mut app_state) = progress_state.lock() { @@ -315,7 +312,7 @@ impl SinfarInstallerApp<> { }; if let Some(files) = downloaded_files { - let download_state = download_state.clone(); // Clone again for the async block + let download_state = download_state.clone(); runtime.spawn(async move { // Try to install the files if let Err(e) = extractor.install_all_files( @@ -328,10 +325,34 @@ impl SinfarInstallerApp<> { app_state.error = Some(format!("Installation failed: {}", e)); } } else { - // Mark as complete on success - if let Ok(mut app_state) = download_state.lock() { - app_state.completed = true; - app_state.progress = 1.0; + // Create shortcut after successful installation + let shortcut_result = match game_type { + GameType::Diamond => { + // For Diamond, point to sinfarx.exe in install path + let target = install_path.join("sinfarx.exe"); + crate::installer::shortcut::create_shortcut(&target, "Sinfar", None) + }, + GameType::EnhancedEdition => { + // For EE, point to sinfarx_ee.exe in bin/win32_8181 + if let Some(ee_path) = ee_exe_path { + let target = ee_path.join("bin").join("win32_8181").join("sinfarx_ee.exe"); + crate::installer::shortcut::create_shortcut(&target, "Sinfar EE", None) + } else { + Ok(()) // Should never happen as we validate earlier + } + } + }; + + if let Err(e) = shortcut_result { + if let Ok(mut app_state) = download_state.lock() { + app_state.error = Some(format!("Failed to create shortcut: {}", e)); + } + } else { + // Mark as complete on success + if let Ok(mut app_state) = download_state.lock() { + app_state.completed = true; + app_state.progress = 1.0; + } } } }); diff --git a/rust/src/installer/extractor.rs b/rust/src/installer/extractor.rs index 215470f..50c435a 100644 --- a/rust/src/installer/extractor.rs +++ b/rust/src/installer/extractor.rs @@ -355,7 +355,7 @@ impl ExtractionManager { // Extract main content info!("Starting extraction of main content"); - //self.extract_7z(content_archive, install_path).await?; + self.extract_7z(content_archive, install_path).await?; // Handle game-specific files info!("Processing game-specific files"); diff --git a/rust/src/installer/shortcut.rs b/rust/src/installer/shortcut.rs index fa65534..36cf8d9 100644 --- a/rust/src/installer/shortcut.rs +++ b/rust/src/installer/shortcut.rs @@ -1,64 +1,62 @@ -pub mod shortcut { - use std::path::{Path, PathBuf}; - use std::io::Write; - use anyhow::Result; +use std::path::{Path, PathBuf}; +use anyhow::Result; +use std::io::Write; - pub fn create_shortcut( - target_path: &Path, - shortcut_name: &str, - icon_path: Option<&Path>, - ) -> Result<()> { - #[cfg(windows)] - { - use std::os::windows::process::CommandExt; - use std::process::Command; - - let desktop_path = dirs::desktop_dir().unwrap_or_else(|| PathBuf::from(".")); - let shortcut_path = desktop_path.join(format!("{}.lnk", shortcut_name)); - - let powershell_command = format!( - "$s = (New-Object -ComObject WScript.Shell).CreateShortcut('{}'); $s.TargetPath = '{}'; {}; $s.Save()", - shortcut_path.to_string_lossy(), - target_path.to_string_lossy(), - if let Some(icon) = icon_path { - format!("$s.IconLocation = '{}'", icon.to_string_lossy()) - } else { - String::new() - } - ); - - Command::new("powershell") - .args(["-Command", &powershell_command]) - .creation_flags(0x08000000) // CREATE_NO_WINDOW - .output()?; - } +pub fn create_shortcut( + target_path: &Path, + shortcut_name: &str, + icon_path: Option<&Path>, +) -> Result<()> { + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + use std::process::Command; + let desktop_path = dirs::desktop_dir().unwrap_or_else(|| PathBuf::from(".")); + let shortcut_path = desktop_path.join(format!("{}.lnk", shortcut_name)); + + let powershell_command = format!( + "$s = (New-Object -ComObject WScript.Shell).CreateShortcut('{}'); $s.TargetPath = '{}'; {}; $s.Save()", + shortcut_path.to_string_lossy(), + target_path.to_string_lossy(), + if let Some(icon) = icon_path { + format!("$s.IconLocation = '{}'", icon.to_string_lossy()) + } else { + String::new() + } + ); + + Command::new("powershell") + .args(["-Command", &powershell_command]) + .creation_flags(0x08000000) // CREATE_NO_WINDOW + .output()?; + } + + #[cfg(unix)] + { + let desktop_path = dirs::desktop_dir().unwrap_or_else(|| PathBuf::from(".")); + let shortcut_path = desktop_path.join(format!("{}.desktop", shortcut_name)); + + let mut desktop_file = std::fs::File::create(shortcut_path)?; + + writeln!(desktop_file, "[Desktop Entry]")?; + writeln!(desktop_file, "Type=Application")?; + writeln!(desktop_file, "Name={}", shortcut_name)?; + writeln!(desktop_file, "Exec={}", target_path.to_string_lossy())?; + if let Some(icon) = icon_path { + writeln!(desktop_file, "Icon={}", icon.to_string_lossy())?; + } + writeln!(desktop_file, "Terminal=false")?; + + // Make the .desktop file executable #[cfg(unix)] { - let desktop_path = dirs::desktop_dir().unwrap_or_else(|| PathBuf::from(".")); - let shortcut_path = desktop_path.join(format!("{}.desktop", shortcut_name)); - - let mut desktop_file = std::fs::File::create(shortcut_path)?; - - writeln!(desktop_file, "[Desktop Entry]")?; - writeln!(desktop_file, "Type=Application")?; - writeln!(desktop_file, "Name={}", shortcut_name)?; - writeln!(desktop_file, "Exec={}", target_path.to_string_lossy())?; - if let Some(icon) = icon_path { - writeln!(desktop_file, "Icon={}", icon.to_string_lossy())?; - } - writeln!(desktop_file, "Terminal=false")?; - - // Make the .desktop file executable - #[cfg(unix)] - { - use std::os::unix::fs::PermissionsExt; - let mut perms = std::fs::metadata(&shortcut_path)?.permissions(); - perms.set_mode(0o755); - std::fs::set_permissions(&shortcut_path, perms)?; - } + use std::os::unix::fs::PermissionsExt; + let mut perms = std::fs::metadata(&shortcut_path)?.permissions(); + perms.set_mode(0o755); + std::fs::set_permissions(&shortcut_path, perms)?; } - - Ok(()) } + + Ok(()) } \ No newline at end of file