diff --git a/assets/dxvk.json b/assets/dxvk.json index e62b6c5..edc1bfd 100644 --- a/assets/dxvk.json +++ b/assets/dxvk.json @@ -82,6 +82,11 @@ } ], "async": [ + { + "version": "1.10.2", + "uri": "https://github.com/Sporif/dxvk-async/releases/download/1.10.2/dxvk-async-1.10.2.tar.gz", + "recommended": true + }, { "version": "1.10.1", "uri": "https://github.com/Sporif/dxvk-async/releases/download/1.10.1/dxvk-async-1.10.1.tar.gz", diff --git a/src/ui/components/wine_group.rs b/src/ui/components/wine_group.rs index aba0873..f15ca92 100644 --- a/src/ui/components/wine_group.rs +++ b/src/ui/components/wine_group.rs @@ -38,4 +38,10 @@ impl WineGroup { expander_row } } + + pub fn update_states(&self, runners_folder: T) { + for component in &self.version_components { + component.update_state(runners_folder.to_string()); + } + } } diff --git a/src/ui/components/wine_row.rs b/src/ui/components/wine_row.rs index 7b12c63..7253220 100644 --- a/src/ui/components/wine_row.rs +++ b/src/ui/components/wine_row.rs @@ -4,6 +4,10 @@ use libadwaita::{self as adw, prelude::*}; use gtk::glib; use gtk::Align; +use std::path::Path; + +use anime_game_core::prelude::*; + use crate::lib::wine::Version; #[derive(Debug, Clone)] @@ -48,31 +52,78 @@ impl WineRow { } } - pub fn download(&self) { - let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); + pub fn is_downloaded(&self, runners_folder: T) -> bool { + Path::new(&format!("{}/{}", runners_folder.to_string(), self.version.name)).exists() + } + + pub fn update_state(&self, runners_folder: T) { + if self.is_downloaded(runners_folder) { + self.button.set_icon_name("user-trash-symbolic"); + } + + else { + self.button.set_icon_name("document-save-symbolic"); + } + } + + /// Download wine + /// + /// This method doesn't update components states, so you need to call `update_state` method manually + pub fn download(&self, runners_folder: T) -> Result<(), std::io::Error> { + let (sender, receiver) = glib::MainContext::channel::(glib::PRIORITY_DEFAULT); let this = self.clone(); this.progress_bar.set_visible(true); this.button.set_visible(false); - receiver.attach(None, move |fraction| { - this.progress_bar.set_fraction(fraction as f64 / 100f64); - this.progress_bar.set_text(Some(&format!("Downloading: {}%", fraction))); + receiver.attach(None, move |state| { + match state { + InstallerUpdate::DownloadingStarted(_) => (), + InstallerUpdate::DownloadingFinished => (), + InstallerUpdate::UnpackingStarted(_) => (), - if fraction == 100 { - this.progress_bar.set_visible(false); - this.button.set_visible(true); + InstallerUpdate::DownloadingProgress(curr, total) => { + let progress = curr as f64 / total as f64; + + this.progress_bar.set_fraction(progress); + this.progress_bar.set_text(Some(&format!("Downloading: {}%", (progress * 100.0) as u64))); + }, + + InstallerUpdate::UnpackingProgress(curr, total) => { + let progress = curr as f64 / total as f64; + + this.progress_bar.set_fraction(progress); + this.progress_bar.set_text(Some(&format!("Unpacking: {}%", (progress * 100.0) as u64))); + }, + + InstallerUpdate::UnpackingFinished => { + this.progress_bar.set_visible(false); + this.button.set_visible(true); + }, + + // TODO: proper handling + InstallerUpdate::DownloadingError(err) => panic!("Failed to download wine: {}", err), + InstallerUpdate::UnpackingError => panic!("Failed to unpack wine") } glib::Continue(true) }); - std::thread::spawn(move || { - for i in 1..101 { - std::thread::sleep(std::time::Duration::from_millis(150)); + let (send, recv) = std::sync::mpsc::channel(); - sender.send(i); - } + let installer = Installer::new(&self.version.uri)?; + let runners_folder = runners_folder.to_string(); + + send.send(installer); + + std::thread::spawn(move || { + let mut installer = recv.recv().unwrap(); + + installer.install(runners_folder, move |state| { + sender.send(state); + }); }); + + Ok(()) } } diff --git a/src/ui/preferences/general_page.rs b/src/ui/preferences/general_page.rs index f4a176a..375261b 100644 --- a/src/ui/preferences/general_page.rs +++ b/src/ui/preferences/general_page.rs @@ -65,6 +65,11 @@ impl AppWidgets { dxvk_components: Default::default() }; + let config = match config::get() { + Ok(config) => config, + Err(err) => return Err(err.to_string()) + }; + // Update wine versions lists let groups = match wine::List::get() { Ok(list) => list, @@ -76,6 +81,8 @@ impl AppWidgets { for group in groups { let group = WineGroup::new(group); + group.update_states(&config.game.wine.builds); + result.wine_groups.add(&group.expander_row); components.push(group); @@ -116,7 +123,8 @@ impl AppWidgets { /// It may be helpful if you want to add the same event for several widgets, or call an action inside of another action #[derive(Debug, Clone, glib::Downgrade)] pub enum Actions { - DownloadDXVK(Rc) + DownloadDXVK(Rc), + DownloadWine(Rc<(usize, usize)>) } impl Actions { @@ -180,6 +188,15 @@ impl App { } })); + // Wine install/remove buttons + let components = &*self.widgets.wine_components; + + for (i, group) in components.into_iter().enumerate() { + for (j, component) in (&group.version_components).into_iter().enumerate() { + component.button.connect_clicked(Actions::DownloadWine(Rc::new((i, j))).into_fn(&self)); + } + } + // Set DXVK recommended only switcher event self.widgets.dxvk_recommended_only.connect_state_notify(clone!(@strong self as this => move |switcher| { for component in &*this.widgets.dxvk_components { @@ -218,11 +235,19 @@ impl App { match action { Actions::DownloadDXVK(i) => { - let component = &this.widgets.dxvk_components[*i]; + this.widgets.dxvk_components[*i].download(); + } - println!("Download DXVK: {:?}", &component.version); + Actions::DownloadWine(version) => { + let config = config::get().expect("Failed to load config"); - component.download(); + let component = &this.widgets + .wine_components[version.0] + .version_components[version.1]; + + if let Ok(_) = component.download(&config.game.wine.builds) { + component.update_state(&config.game.wine.builds); + } } }