Made an abstraction over widgets with downloading functionality

This commit is contained in:
Observer KRypt0n_ 2022-07-14 23:13:00 +02:00
parent 30c7d836bd
commit 741513ab91
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
8 changed files with 122 additions and 95 deletions

View file

@ -1,22 +1,10 @@
use gtk4::{self as gtk, prelude::*};
use libadwaita::{self as adw, prelude::*};
use gtk::glib;
use gtk::Align;
use std::path::Path;
use anime_game_core::prelude::*;
use wait_not_await::Await;
use crate::lib::wine::Version;
#[derive(Debug)]
pub enum DownloadingResult {
DownloadingError(std::io::Error),
UnpackingError,
Done
}
use crate::ui::traits::download_component::*;
#[derive(Debug, Clone)]
pub struct WineRow {
@ -60,10 +48,6 @@ impl WineRow {
}
}
pub fn is_downloaded<T: ToString>(&self, runners_folder: T) -> bool {
Path::new(&format!("{}/{}", runners_folder.to_string(), self.version.name)).exists()
}
pub fn update_state<T: ToString>(&self, runners_folder: T) {
if self.is_downloaded(runners_folder) {
self.button.set_icon_name("user-trash-symbolic");
@ -73,80 +57,19 @@ impl WineRow {
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<T: ToString>(&self, runners_folder: T) -> std::io::Result<Await<DownloadingResult>> {
let (sender, receiver) = glib::MainContext::channel::<InstallerUpdate>(glib::PRIORITY_DEFAULT);
let this = self.clone();
this.progress_bar.set_visible(true);
this.button.set_visible(false);
let (downl_send, downl_recv) = std::sync::mpsc::channel();
receiver.attach(None, move |state| {
match state {
InstallerUpdate::DownloadingStarted(_) => (),
InstallerUpdate::DownloadingFinished => (),
InstallerUpdate::UnpackingStarted(_) => (),
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);
downl_send.send(DownloadingResult::Done);
},
InstallerUpdate::DownloadingError(err) => {
downl_send.send(DownloadingResult::DownloadingError(err.into()));
},
InstallerUpdate::UnpackingError => {
downl_send.send(DownloadingResult::UnpackingError);
}
}
glib::Continue(true)
});
let (send, recv) = std::sync::mpsc::channel();
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(Await::new(move || {
downl_recv.recv().unwrap()
}))
impl DownloadComponent for WineRow {
fn get_component_path<T: ToString>(&self, installation_path: T) -> String {
format!("{}/{}", installation_path.to_string(), self.version.name)
}
pub fn delete<T: ToString>(&self, runners_folder: T) -> std::io::Result<()> {
std::fs::remove_dir_all(format!("{}/{}", runners_folder.to_string(), self.version.name))
fn get_downloading_widgets(&self) -> (gtk::ProgressBar, gtk::Button) {
(self.progress_bar.clone(), self.button.clone())
}
fn get_download_uri(&self) -> String {
self.version.uri.clone()
}
}

View file

@ -10,7 +10,7 @@ use std::cell::Cell;
use crate::ui::*;
use super::preferences::PreferencesStack;
use super::ToastError;
use super::traits::toast_error::ToastError;
use crate::lib::game;
use crate::lib::tasks;

View file

@ -3,7 +3,7 @@ use libadwaita::{self as adw, prelude::*};
mod main;
mod preferences;
mod toast_error;
mod traits;
pub mod components;
@ -12,8 +12,6 @@ pub use main::{
// AppState as MainAppState,
};
pub use toast_error::ToastError;
/// This function loads object from builder or panics if it doesn't exist
pub fn get_object<T: IsA<gtk::glib::Object>>(builder: &gtk::Builder, name: &str) -> Result<T, String> {
match builder.object::<T>(name) {

View file

@ -15,6 +15,7 @@ use crate::lib::dxvk;
use crate::lib::wine;
use crate::ui::*;
use crate::ui::traits::prelude::*;
use crate::ui::components::dxvk_row::DxvkRow;
use crate::ui::components::wine_group::WineGroup;

View file

@ -5,8 +5,8 @@ use gtk::glib;
use std::io::Error;
use crate::ui::get_object;
use crate::ui::ToastError;
use crate::ui::*;
use crate::ui::traits::prelude::*;
mod general_page;
mod enhanced_page;

View file

@ -0,0 +1,98 @@
use gtk4::{self as gtk, prelude::*};
use libadwaita::{self as adw, prelude::*};
use gtk::glib;
use std::path::Path;
use anime_game_core::prelude::*;
use wait_not_await::Await;
#[derive(Debug)]
pub enum DownloadingResult {
DownloadingError(std::io::Error),
UnpackingError,
Done
}
pub trait DownloadComponent {
fn get_component_path<T: ToString>(&self, installation_path: T) -> String;
fn get_downloading_widgets(&self) -> (gtk::ProgressBar, gtk::Button);
fn get_download_uri(&self) -> String;
fn is_downloaded<T: ToString>(&self, installation_path: T) -> bool {
Path::new(&self.get_component_path(installation_path)).exists()
}
fn download<T: ToString>(&self, installation_path: T) -> std::io::Result<Await<DownloadingResult>> {
let (sender, receiver) = glib::MainContext::channel::<InstallerUpdate>(glib::PRIORITY_DEFAULT);
let (progress_bar, button) = self.get_downloading_widgets();
progress_bar.set_visible(true);
button.set_visible(false);
let (downl_send, downl_recv) = std::sync::mpsc::channel();
receiver.attach(None, move |state| {
match state {
InstallerUpdate::DownloadingStarted(_) => (),
InstallerUpdate::DownloadingFinished => (),
InstallerUpdate::UnpackingStarted(_) => (),
InstallerUpdate::DownloadingProgress(curr, total) => {
let progress = curr as f64 / total as f64;
progress_bar.set_fraction(progress);
progress_bar.set_text(Some(&format!("Downloading: {}%", (progress * 100.0) as u64)));
},
InstallerUpdate::UnpackingProgress(curr, total) => {
let progress = curr as f64 / total as f64;
progress_bar.set_fraction(progress);
progress_bar.set_text(Some(&format!("Unpacking: {}%", (progress * 100.0) as u64)));
},
InstallerUpdate::UnpackingFinished => {
progress_bar.set_visible(false);
button.set_visible(true);
downl_send.send(DownloadingResult::Done);
},
InstallerUpdate::DownloadingError(err) => {
downl_send.send(DownloadingResult::DownloadingError(err.into()));
},
InstallerUpdate::UnpackingError => {
downl_send.send(DownloadingResult::UnpackingError);
}
}
glib::Continue(true)
});
let (send, recv) = std::sync::mpsc::channel();
let installer = Installer::new(self.get_download_uri())?;
let installation_path = installation_path.to_string();
send.send(installer);
std::thread::spawn(move || {
let mut installer = recv.recv().unwrap();
installer.install(installation_path, move |state| {
sender.send(state);
});
});
Ok(Await::new(move || {
downl_recv.recv().unwrap()
}))
}
fn delete<T: ToString>(&self, installation_path: T) -> std::io::Result<()> {
std::fs::remove_dir_all(self.get_component_path(installation_path))
}
}

7
src/ui/traits/mod.rs Normal file
View file

@ -0,0 +1,7 @@
pub mod toast_error;
pub mod download_component;
pub mod prelude {
pub use super::toast_error::*;
pub use super::download_component::*;
}

View file

@ -1,7 +1,7 @@
use gtk4::{self as gtk, prelude::*};
use libadwaita::{self as adw, prelude::*};
use super::add_action;
use crate::ui::add_action;
pub trait ToastError {
fn get_toast_widgets(&self) -> (adw::ApplicationWindow, adw::ToastOverlay);