mirror of
https://github.com/an-anime-team/an-anime-game-launcher.git
synced 2024-12-18 07:51:47 +03:00
Added DxvkRow
component, made example downloading progress
This commit is contained in:
parent
fd6e729cd4
commit
9817cbd989
10 changed files with 133 additions and 51 deletions
|
@ -24,7 +24,7 @@ fn main() {
|
||||||
// Apply CSS styles to the application
|
// Apply CSS styles to the application
|
||||||
let provider = CssProvider::new();
|
let provider = CssProvider::new();
|
||||||
|
|
||||||
provider.load_from_data(include_bytes!("styles.css"));
|
provider.load_from_data(include_bytes!("../assets/styles.css"));
|
||||||
|
|
||||||
StyleContext::add_provider_for_display(
|
StyleContext::add_provider_for_display(
|
||||||
&Display::default().expect("Could not connect to a display"),
|
&Display::default().expect("Could not connect to a display"),
|
||||||
|
|
78
src/ui/components/dxvk_row.rs
Normal file
78
src/ui/components/dxvk_row.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use gtk4::{self as gtk, prelude::*};
|
||||||
|
use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
|
use gtk::glib;
|
||||||
|
use gtk::Align;
|
||||||
|
|
||||||
|
use crate::lib::dxvk::Version;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DxvkRow {
|
||||||
|
pub version: Version,
|
||||||
|
|
||||||
|
pub row: adw::ActionRow,
|
||||||
|
pub button: gtk::Button,
|
||||||
|
pub progress_bar: gtk::ProgressBar
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DxvkRow {
|
||||||
|
pub fn new(version: Version) -> Self {
|
||||||
|
let row = adw::ActionRow::new();
|
||||||
|
let button = gtk::Button::new();
|
||||||
|
|
||||||
|
row.set_title(&version.version);
|
||||||
|
row.set_visible(version.recommended);
|
||||||
|
|
||||||
|
button.set_icon_name("document-save-symbolic");
|
||||||
|
button.set_valign(gtk::Align::Center);
|
||||||
|
button.add_css_class("flat");
|
||||||
|
|
||||||
|
row.add_suffix(&button);
|
||||||
|
|
||||||
|
let progress_bar = gtk::ProgressBar::new();
|
||||||
|
|
||||||
|
progress_bar.set_text(Some("Downloading: 0%"));
|
||||||
|
progress_bar.set_show_text(true);
|
||||||
|
|
||||||
|
progress_bar.set_width_request(200);
|
||||||
|
progress_bar.set_valign(Align::Center);
|
||||||
|
progress_bar.set_visible(false);
|
||||||
|
|
||||||
|
row.add_suffix(&progress_bar);
|
||||||
|
|
||||||
|
Self {
|
||||||
|
version,
|
||||||
|
row,
|
||||||
|
button,
|
||||||
|
progress_bar
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn download(&self) {
|
||||||
|
let (sender, receiver) = glib::MainContext::channel::<i32>(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)));
|
||||||
|
|
||||||
|
if fraction == 100 {
|
||||||
|
this.progress_bar.set_visible(false);
|
||||||
|
this.button.set_visible(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::Continue(true)
|
||||||
|
});
|
||||||
|
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
for i in 1..101 {
|
||||||
|
std::thread::sleep(std::time::Duration::from_millis(150));
|
||||||
|
|
||||||
|
sender.send(i);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
1
src/ui/components/mod.rs
Normal file
1
src/ui/components/mod.rs
Normal file
|
@ -0,0 +1 @@
|
||||||
|
pub mod dxvk_row;
|
|
@ -147,7 +147,10 @@ impl App {
|
||||||
pub fn init_actions(self) -> Self {
|
pub fn init_actions(self) -> Self {
|
||||||
let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
|
let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
|
||||||
|
|
||||||
receiver.attach(None, clone!(@strong self as this => move |action| {
|
// I prefer to avoid using clone! here because it breaks my code autocompletion
|
||||||
|
let this = self.clone();
|
||||||
|
|
||||||
|
receiver.attach(None, move |action| {
|
||||||
let values = this.values.take();
|
let values = this.values.take();
|
||||||
|
|
||||||
// Some debug output
|
// Some debug output
|
||||||
|
@ -156,10 +159,16 @@ impl App {
|
||||||
match action {
|
match action {
|
||||||
Actions::OpenPreferencesPage => {
|
Actions::OpenPreferencesPage => {
|
||||||
this.widgets.leaflet.set_visible_child_name("preferences_page");
|
this.widgets.leaflet.set_visible_child_name("preferences_page");
|
||||||
|
|
||||||
if let Err(err) = this.widgets.preferences_stack.update() {
|
if let Err(err) = this.widgets.preferences_stack.update() {
|
||||||
this.toast_error("Failed to update preferences", err);
|
this.toast_error("Failed to update preferences", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*tokio::task::spawn(async {
|
||||||
|
if let Err(err) = this.widgets.preferences_stack.update().await {
|
||||||
|
// this.update(Actions::ToastError(Rc::new((String::from("Failed to update preferences"), err))));
|
||||||
|
}
|
||||||
|
});*/
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions::PreferencesGoBack => {
|
Actions::PreferencesGoBack => {
|
||||||
|
@ -177,7 +186,7 @@ impl App {
|
||||||
this.values.set(values);
|
this.values.set(values);
|
||||||
|
|
||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
}));
|
});
|
||||||
|
|
||||||
self.actions.set(Some(sender));
|
self.actions.set(Some(sender));
|
||||||
|
|
||||||
|
@ -210,6 +219,9 @@ impl ToastError for App {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for App {}
|
||||||
|
unsafe impl Sync for App {}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
pub enum AppState {
|
pub enum AppState {
|
||||||
Launch,
|
Launch,
|
||||||
|
|
|
@ -5,6 +5,8 @@ mod main;
|
||||||
mod preferences;
|
mod preferences;
|
||||||
mod toast_error;
|
mod toast_error;
|
||||||
|
|
||||||
|
pub mod components;
|
||||||
|
|
||||||
pub use main::{
|
pub use main::{
|
||||||
App as MainApp,
|
App as MainApp,
|
||||||
// AppState as MainAppState,
|
// AppState as MainAppState,
|
||||||
|
|
|
@ -198,3 +198,6 @@ impl App {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for App {}
|
||||||
|
unsafe impl Sync for App {}
|
||||||
|
|
|
@ -15,6 +15,8 @@ use crate::ui::get_object;
|
||||||
use crate::lib::config;
|
use crate::lib::config;
|
||||||
use crate::lib::dxvk;
|
use crate::lib::dxvk;
|
||||||
|
|
||||||
|
use crate::ui::components::dxvk_row::DxvkRow;
|
||||||
|
|
||||||
/// This structure is used to describe widgets used in application
|
/// This structure is used to describe widgets used in application
|
||||||
///
|
///
|
||||||
/// `AppWidgets::try_get` function loads UI file from `.assets/ui/.dist` folder and returns structure with references to its widgets
|
/// `AppWidgets::try_get` function loads UI file from `.assets/ui/.dist` folder and returns structure with references to its widgets
|
||||||
|
@ -31,7 +33,7 @@ pub struct AppWidgets {
|
||||||
pub dxvk_vanilla: adw::ExpanderRow,
|
pub dxvk_vanilla: adw::ExpanderRow,
|
||||||
pub dxvk_async: adw::ExpanderRow,
|
pub dxvk_async: adw::ExpanderRow,
|
||||||
|
|
||||||
pub dxvk_components: Rc<Vec<(adw::ActionRow, gtk::Button, dxvk::Version)>>
|
pub dxvk_components: Rc<Vec<DxvkRow>>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppWidgets {
|
impl AppWidgets {
|
||||||
|
@ -61,25 +63,15 @@ impl AppWidgets {
|
||||||
|
|
||||||
for (i, versions) in [list.vanilla, list.r#async].into_iter().enumerate() {
|
for (i, versions) in [list.vanilla, list.r#async].into_iter().enumerate() {
|
||||||
for version in versions {
|
for version in versions {
|
||||||
let row = adw::ActionRow::new();
|
let row = DxvkRow::new(version);
|
||||||
let button = gtk::Button::new();
|
|
||||||
|
|
||||||
row.set_title(&version.version);
|
|
||||||
row.set_visible(version.recommended);
|
|
||||||
|
|
||||||
button.set_icon_name("document-save-symbolic");
|
|
||||||
button.set_valign(gtk::Align::Center);
|
|
||||||
button.add_css_class("flat");
|
|
||||||
|
|
||||||
row.add_suffix(&button);
|
|
||||||
|
|
||||||
match i {
|
match i {
|
||||||
0 => result.dxvk_vanilla.add_row(&row),
|
0 => result.dxvk_vanilla.add_row(&row.row),
|
||||||
1 => result.dxvk_async.add_row(&row),
|
1 => result.dxvk_async.add_row(&row.row),
|
||||||
_ => ()
|
_ => ()
|
||||||
}
|
}
|
||||||
|
|
||||||
components.push((row, button, version));
|
components.push(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -92,15 +84,15 @@ impl AppWidgets {
|
||||||
/// This enum is used to describe an action inside of this application
|
/// This enum is used to describe an action inside of this application
|
||||||
///
|
///
|
||||||
/// It may be helpful if you want to add the same event for several widgets, or call an action inside of another action
|
/// 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, glib::Downgrade)]
|
#[derive(Debug, Clone, glib::Downgrade)]
|
||||||
pub enum Actions {
|
pub enum Actions {
|
||||||
DownloadDXVK(Rc<usize>)
|
DownloadDXVK(Rc<usize>)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Actions {
|
impl Actions {
|
||||||
pub fn into_fn<T: gtk::glib::IsA<gtk::Widget>>(&self, app: &App) -> Box<dyn Fn(&T)> {
|
pub fn into_fn<T: gtk::glib::IsA<gtk::Widget>>(&self, app: &App) -> Box<dyn Fn(&T)> {
|
||||||
Box::new(clone!(@weak self as action, @strong app => move |_| {
|
Box::new(clone!(@strong self as action, @strong app => move |_| {
|
||||||
app.update(action);
|
app.update(action.clone());
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,9 +139,9 @@ impl App {
|
||||||
fn init_events(self) -> Self {
|
fn init_events(self) -> Self {
|
||||||
// Set DXVK recommended only switcher event
|
// Set DXVK recommended only switcher event
|
||||||
self.widgets.dxvk_recommended_only.connect_state_notify(clone!(@strong self as this => move |switcher| {
|
self.widgets.dxvk_recommended_only.connect_state_notify(clone!(@strong self as this => move |switcher| {
|
||||||
for (component, _, version) in &*this.widgets.dxvk_components {
|
for component in &*this.widgets.dxvk_components {
|
||||||
component.set_visible(if switcher.state() {
|
component.row.set_visible(if switcher.state() {
|
||||||
version.recommended
|
component.version.recommended
|
||||||
} else {
|
} else {
|
||||||
true
|
true
|
||||||
});
|
});
|
||||||
|
@ -157,10 +149,10 @@ impl App {
|
||||||
}));
|
}));
|
||||||
|
|
||||||
// DXVK install/remove buttons
|
// DXVK install/remove buttons
|
||||||
let components = (*self.widgets.dxvk_components).clone();
|
let components = &*self.widgets.dxvk_components;
|
||||||
|
|
||||||
for (i, (_, button, _)) in components.into_iter().enumerate() {
|
for (i, component) in components.into_iter().enumerate() {
|
||||||
button.connect_clicked(Actions::DownloadDXVK(Rc::new(i)).into_fn(&self));
|
component.button.connect_clicked(Actions::DownloadDXVK(Rc::new(i)).into_fn(&self));
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
|
@ -172,7 +164,10 @@ impl App {
|
||||||
pub fn init_actions(self) -> Self {
|
pub fn init_actions(self) -> Self {
|
||||||
let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
|
let (sender, receiver) = glib::MainContext::channel::<Actions>(glib::PRIORITY_DEFAULT);
|
||||||
|
|
||||||
receiver.attach(None, clone!(@strong self as this => move |action| {
|
// I prefer to avoid using clone! here because it breaks my code autocompletion
|
||||||
|
let this = self.clone();
|
||||||
|
|
||||||
|
receiver.attach(None, move |action| {
|
||||||
let values = this.values.take();
|
let values = this.values.take();
|
||||||
|
|
||||||
// Some debug output
|
// Some debug output
|
||||||
|
@ -180,31 +175,18 @@ impl App {
|
||||||
|
|
||||||
match action {
|
match action {
|
||||||
Actions::DownloadDXVK(i) => {
|
Actions::DownloadDXVK(i) => {
|
||||||
println!("123");
|
let component = &this.widgets.dxvk_components[*i];
|
||||||
|
|
||||||
let (row, button, version) = &this.widgets.dxvk_components[*i];
|
println!("Download DXVK: {:?}", &component.version);
|
||||||
|
|
||||||
let progress_bar = gtk::ProgressBar::new();
|
component.download();
|
||||||
|
|
||||||
progress_bar.set_text(Some("Downloading: 0%"));
|
|
||||||
progress_bar.set_show_text(true);
|
|
||||||
|
|
||||||
progress_bar.set_width_request(200);
|
|
||||||
progress_bar.set_valign(Align::Center);
|
|
||||||
|
|
||||||
button.set_visible(false);
|
|
||||||
|
|
||||||
row.add_suffix(&progress_bar);
|
|
||||||
|
|
||||||
row.remove(&progress_bar);
|
|
||||||
button.set_visible(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.values.set(values);
|
this.values.set(values);
|
||||||
|
|
||||||
glib::Continue(true)
|
glib::Continue(true)
|
||||||
}));
|
});
|
||||||
|
|
||||||
self.actions.set(Some(sender));
|
self.actions.set(Some(sender));
|
||||||
|
|
||||||
|
@ -305,3 +287,4 @@ impl App {
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Send for App {}
|
unsafe impl Send for App {}
|
||||||
|
unsafe impl Sync for App {}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use gtk4::{self as gtk, prelude::*};
|
use gtk4::{self as gtk, prelude::*};
|
||||||
use libadwaita::{self as adw, prelude::*};
|
use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
use gtk4::glib;
|
use gtk::glib;
|
||||||
|
|
||||||
use std::io::Error;
|
use std::io::Error;
|
||||||
|
|
||||||
|
@ -84,3 +84,6 @@ impl ToastError for PreferencesStack {
|
||||||
(self.window.clone(), self.toast_overlay.clone())
|
(self.window.clone(), self.toast_overlay.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unsafe impl Send for PreferencesStack {}
|
||||||
|
unsafe impl Sync for PreferencesStack {}
|
||||||
|
|
|
@ -9,8 +9,8 @@ pub trait ToastError {
|
||||||
/// Show toast with `toast` title and `See message` button
|
/// Show toast with `toast` title and `See message` button
|
||||||
///
|
///
|
||||||
/// This button will show message dialog with error message
|
/// This button will show message dialog with error message
|
||||||
fn toast_error<T: ToString + 'static>(&self, toast: &str, err: T) {
|
fn toast_error<T: ToString, F: std::fmt::Display + 'static>(&self, toast: T, err: F) {
|
||||||
let toast = adw::Toast::new(toast);
|
let toast = adw::Toast::new(toast.to_string().as_str());
|
||||||
|
|
||||||
toast.set_button_label(Some("See message"));
|
toast.set_button_label(Some("See message"));
|
||||||
toast.set_action_name(Some("see-message.see-message"));
|
toast.set_action_name(Some("see-message.see-message"));
|
||||||
|
@ -25,7 +25,7 @@ pub trait ToastError {
|
||||||
gtk::DialogFlags::all(),
|
gtk::DialogFlags::all(),
|
||||||
gtk::MessageType::Info,
|
gtk::MessageType::Info,
|
||||||
gtk::ButtonsType::Close,
|
gtk::ButtonsType::Close,
|
||||||
&err.to_string()
|
&format!("{}", err)
|
||||||
);
|
);
|
||||||
|
|
||||||
dialog.connect_response(move |dialog, _| {
|
dialog.connect_response(move |dialog, _| {
|
||||||
|
|
Loading…
Reference in a new issue