Several changes

- updated core library and components library
- added (likely working) updates pre-downloading functionality
- moved to `anyhow::Result` in lots of places
This commit is contained in:
Observer KRypt0n_ 2022-09-26 15:08:29 +02:00
parent 7ac3935ab1
commit 002c77a9c1
No known key found for this signature in database
GPG key ID: 844DA47BA25FE1E2
23 changed files with 160 additions and 58 deletions

2
Cargo.lock generated
View file

@ -31,7 +31,7 @@ dependencies = [
[[package]] [[package]]
name = "anime-game-core" name = "anime-game-core"
version = "1.1.0" version = "1.1.4"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bzip2", "bzip2",

@ -1 +1 @@
Subproject commit 6adbca88936bcb16d10063fe58688cc7b10813b2 Subproject commit e2140cea392560ac685088d6cc6295ad1172cb72

View file

@ -64,6 +64,16 @@ Adw.ApplicationWindow window {
margin-top: 64; margin-top: 64;
spacing: 8; spacing: 8;
Gtk.Button predownload_game {
icon-name: "document-save-symbolic";
tooltip-text: "Pre-download 3.1.0 update (15 GB)";
hexpand: false;
visible: false;
styles ["warning"]
}
Gtk.Button launch_game { Gtk.Button launch_game {
label: "Launch"; label: "Launch";

@ -1 +1 @@
Subproject commit 59f7158df2b9a339fd62d4ee124f0ece47751e6b Subproject commit 6ae731151cf1562877e5cb84896f3b5d3f001c6c

View file

@ -1,7 +1,7 @@
use std::fs::File; use std::fs::File;
use std::io::Read; use std::io::Read;
use std::path::Path; use std::path::Path;
use std::io::{Error, ErrorKind, Write}; use std::io::Write;
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use serde_json::Value as JsonValue; use serde_json::Value as JsonValue;
@ -39,7 +39,7 @@ static mut CONFIG: Option<Config> = None;
/// This method will load config from file once and store it into the memory. /// This method will load config from file once and store it into the memory.
/// If you know that the config file was updated - you should run `get_raw` method /// If you know that the config file was updated - you should run `get_raw` method
/// that always loads config directly from the file. This will also update in-memory config /// that always loads config directly from the file. This will also update in-memory config
pub fn get() -> Result<Config, Error> { pub fn get() -> anyhow::Result<Config> {
unsafe { unsafe {
match &CONFIG { match &CONFIG {
Some(config) => Ok(config.clone()), Some(config) => Ok(config.clone()),
@ -51,7 +51,7 @@ pub fn get() -> Result<Config, Error> {
/// Get config data /// Get config data
/// ///
/// This method will always load data directly from the file and update in-memory config /// This method will always load data directly from the file and update in-memory config
pub fn get_raw() -> Result<Config, Error> { pub fn get_raw() -> anyhow::Result<Config> {
match config_file() { match config_file() {
Some(path) => { Some(path) => {
// Try to read config if the file exists // Try to read config if the file exists
@ -71,7 +71,7 @@ pub fn get_raw() -> Result<Config, Error> {
Ok(config) Ok(config)
}, },
Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to decode data from json format: {}", err.to_string()))) Err(err) => Err(anyhow::anyhow!("Failed to decode data from json format: {}", err.to_string()))
} }
} }
@ -82,7 +82,7 @@ pub fn get_raw() -> Result<Config, Error> {
Ok(Config::default()) Ok(Config::default())
} }
}, },
None => Err(Error::new(ErrorKind::NotFound, format!("Failed to get config file path"))) None => Err(anyhow::anyhow!("Failed to get config file path"))
} }
} }
@ -98,7 +98,7 @@ pub fn update(config: Config) {
/// Update config file /// Update config file
/// ///
/// This method will also update in-memory config data /// This method will also update in-memory config data
pub fn update_raw(config: Config) -> Result<(), Error> { pub fn update_raw(config: Config) -> anyhow::Result<()> {
update(config.clone()); update(config.clone());
match config_file() { match config_file() {
@ -111,19 +111,19 @@ pub fn update_raw(config: Config) -> Result<(), Error> {
Ok(()) Ok(())
}, },
Err(err) => Err(Error::new(ErrorKind::InvalidData, format!("Failed to encode data into json format: {}", err.to_string()))) Err(err) => Err(anyhow::anyhow!("Failed to encode data into json format: {}", err.to_string()))
} }
}, },
None => Err(Error::new(ErrorKind::NotFound, format!("Failed to get config file path"))) None => Err(anyhow::anyhow!("Failed to get config file path"))
} }
} }
/// Update config file from the in-memory saved config /// Update config file from the in-memory saved config
pub fn flush() -> Result<(), Error> { pub fn flush() -> anyhow::Result<()> {
unsafe { unsafe {
match &CONFIG { match &CONFIG {
Some(config) => update_raw(config.clone()), Some(config) => update_raw(config.clone()),
None => Err(Error::new(ErrorKind::Other, "Config wasn't loaded into the memory")) None => Err(anyhow::anyhow!("Config wasn't loaded into the memory"))
} }
} }
} }

View file

@ -80,7 +80,7 @@ impl Version {
std::path::Path::new(&format!("{}/{}", folder.to_string(), self.name)).exists() std::path::Path::new(&format!("{}/{}", folder.to_string(), self.name)).exists()
} }
pub fn apply<T: ToString>(&self, dxvks_folder: T, prefix_path: T) -> std::io::Result<Output> { pub fn apply<T: ToString>(&self, dxvks_folder: T, prefix_path: T) -> anyhow::Result<Output> {
let apply_path = format!("{}/{}/setup_dxvk.sh", dxvks_folder.to_string(), self.name); let apply_path = format!("{}/{}/setup_dxvk.sh", dxvks_folder.to_string(), self.name);
let config = config::get()?; let config = config::get()?;
@ -95,13 +95,18 @@ impl Version {
None => (String::from("wine64"), String::from("wineserver"), String::from("wineboot")) None => (String::from("wine64"), String::from("wineserver"), String::from("wineboot"))
}; };
Dxvk::install( let result = Dxvk::install(
PathBuf::from(apply_path), PathBuf::from(apply_path),
PathBuf::from(prefix_path.to_string()), PathBuf::from(prefix_path.to_string()),
PathBuf::from(&wine_path), PathBuf::from(&wine_path),
PathBuf::from(wine_path), PathBuf::from(wine_path),
PathBuf::from(wineboot_path), PathBuf::from(wineboot_path),
PathBuf::from(wineserver_path) PathBuf::from(wineserver_path)
) );
match result {
Ok(output) => Ok(output),
Err(err) => Err(err.into())
}
} }
} }

View file

@ -71,7 +71,7 @@ impl DxvkRow {
} }
} }
pub fn apply<T: ToString>(&self, dxvks_folder: T, prefix_path: T) -> std::io::Result<std::process::Output> { pub fn apply<T: ToString>(&self, dxvks_folder: T, prefix_path: T) -> anyhow::Result<std::process::Output> {
self.button.set_sensitive(false); self.button.set_sensitive(false);
self.apply_button.set_sensitive(false); self.apply_button.set_sensitive(false);

View file

@ -44,7 +44,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new(window: gtk::Window) -> Result<Self, String> { pub fn new(window: gtk::Window) -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/default_paths.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/default_paths.ui");
let result = Self { let result = Self {
@ -62,10 +62,7 @@ impl Page {
exit_button: get_object(&builder, "exit_button")? exit_button: get_object(&builder, "exit_button")?
}; };
let config = match config::get() { let config = config::get()?;
Ok(config) => config,
Err(err) => return Err(err.to_string())
};
// Add paths to subtitles // Add paths to subtitles
result.runners_folder.set_subtitle(&config.game.wine.builds); result.runners_folder.set_subtitle(&config.game.wine.builds);

View file

@ -15,7 +15,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/dependencies.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/dependencies.ui");
let result = Self { let result = Self {

View file

@ -25,7 +25,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/download_components.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/download_components.ui");
let mut result = Self { let mut result = Self {

View file

@ -8,7 +8,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/finish.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/finish.ui");
Ok(Self { Ok(Self {

View file

@ -48,7 +48,7 @@ pub struct AppWidgets {
} }
impl AppWidgets { impl AppWidgets {
pub fn try_get() -> Result<Self, String> { pub fn try_get() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run.ui");
let result = Self { let result = Self {
@ -131,7 +131,7 @@ pub struct App {
impl App { impl App {
/// Create new application /// Create new application
pub fn new(app: &gtk::Application) -> Result<Self, String> { pub fn new(app: &gtk::Application) -> anyhow::Result<Self> {
// Get default widgets from ui file and add events to them // Get default widgets from ui file and add events to them
let result = Self { let result = Self {
widgets: AppWidgets::try_get()?, widgets: AppWidgets::try_get()?,

View file

@ -8,7 +8,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/tos_warning.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/tos_warning.ui");
Ok(Self { Ok(Self {

View file

@ -18,7 +18,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/voice_packages.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/voice_packages.ui");
let mut result = Self { let mut result = Self {

View file

@ -8,7 +8,7 @@ pub struct Page {
} }
impl Page { impl Page {
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/first_run/welcome.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/first_run/welcome.ui");
Ok(Self { Ok(Self {

View file

@ -30,6 +30,7 @@ use crate::lib::wine::{
Version as WineVersion, Version as WineVersion,
List as WineList List as WineList
}; };
use crate::lib::prettify_bytes::prettify_bytes;
/// This structure is used to describe widgets used in application /// This structure is used to describe widgets used in application
/// ///
@ -49,6 +50,7 @@ pub struct AppWidgets {
pub launcher_content: adw::PreferencesPage, pub launcher_content: adw::PreferencesPage,
pub icon: gtk::Image, pub icon: gtk::Image,
pub predownload_game: gtk::Button,
pub launch_game: gtk::Button, pub launch_game: gtk::Button,
pub open_preferences: gtk::Button, pub open_preferences: gtk::Button,
@ -58,7 +60,7 @@ pub struct AppWidgets {
} }
impl AppWidgets { impl AppWidgets {
pub fn try_get() -> Result<Self, String> { pub fn try_get() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/main.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/main.ui");
let window = get_object::<adw::ApplicationWindow>(&builder, "window")?; let window = get_object::<adw::ApplicationWindow>(&builder, "window")?;
@ -76,6 +78,7 @@ impl AppWidgets {
launcher_content: get_object(&builder, "launcher_content")?, launcher_content: get_object(&builder, "launcher_content")?,
icon: get_object(&builder, "icon")?, icon: get_object(&builder, "icon")?,
predownload_game: get_object(&builder, "predownload_game")?,
launch_game: get_object(&builder, "launch_game")?, launch_game: get_object(&builder, "launch_game")?,
open_preferences: get_object(&builder, "open_preferences")?, open_preferences: get_object(&builder, "open_preferences")?,
@ -150,6 +153,7 @@ pub enum Actions {
OpenPreferencesPage, OpenPreferencesPage,
PreferencesGoBack, PreferencesGoBack,
PerformButtonEvent, PerformButtonEvent,
PredownloadUpdate,
RepairGame, RepairGame,
ShowProgressBar, ShowProgressBar,
UpdateProgress { fraction: Rc<f64>, title: Rc<String> }, UpdateProgress { fraction: Rc<f64>, title: Rc<String> },
@ -195,7 +199,7 @@ pub struct App {
impl App { impl App {
/// Create new application /// Create new application
pub fn new(app: &gtk::Application) -> Result<Self, String> { pub fn new(app: &gtk::Application) -> anyhow::Result<Self> {
let mut result = Self { let mut result = Self {
widgets: AppWidgets::try_get()?, widgets: AppWidgets::try_get()?,
values: Default::default(), values: Default::default(),
@ -256,6 +260,9 @@ impl App {
// Go back button for preferences page // Go back button for preferences page
self.widgets.preferences_stack.preferences_go_back.connect_clicked(Actions::PreferencesGoBack.into_fn(&self)); self.widgets.preferences_stack.preferences_go_back.connect_clicked(Actions::PreferencesGoBack.into_fn(&self));
// Predownload update
self.widgets.predownload_game.connect_clicked(Actions::PredownloadUpdate.into_fn(&self));
// Launch game // Launch game
self.widgets.launch_game.connect_clicked(Actions::PerformButtonEvent.into_fn(&self)); self.widgets.launch_game.connect_clicked(Actions::PerformButtonEvent.into_fn(&self));
@ -593,6 +600,61 @@ impl App {
} }
} }
Actions::PredownloadUpdate => {
let values = this.values.take();
let state = values.state.clone();
this.values.set(values);
match config::get() {
Ok(config) => {
match state {
LauncherState::PredownloadAvailable { game, mut voices } => {
let (sender, receiver) = glib::MainContext::channel::<InstallerUpdate>(glib::PRIORITY_DEFAULT);
let mut diffs: Vec<VersionDiff> = vec![game];
diffs.append(&mut voices);
this.widgets.progress_bar.show();
std::thread::spawn(clone!(@strong this => move || {
for mut diff in diffs {
let sender = sender.clone();
#[allow(unused_must_use)]
let result = diff.download_in(config.launcher.temp.as_ref().unwrap(), move |curr, total| {
sender.send(InstallerUpdate::DownloadingProgress(curr, total));
});
if let Err(err) = result {
let err: Error = err.into();
this.update(Actions::Toast(Rc::new((
String::from("Downloading failed"), err.to_string()
)))).unwrap();
break;
}
}
this.update(Actions::HideProgressBar).unwrap();
}));
receiver.attach(None, clone!(@strong this => move |state| {
this.widgets.progress_bar.update_from_state(state);
glib::Continue(true)
}));
}
_ => unreachable!()
}
},
Err(err) => this.toast("Failed to load config", err)
}
}
Actions::RepairGame => { Actions::RepairGame => {
match config::get() { match config::get() {
Ok(config) => { Ok(config) => {
@ -812,14 +874,49 @@ impl App {
self.widgets.launch_game.remove_css_class("warning"); self.widgets.launch_game.remove_css_class("warning");
self.widgets.launch_game.remove_css_class("destructive-action"); self.widgets.launch_game.remove_css_class("destructive-action");
self.widgets.predownload_game.hide();
match &state { match &state {
LauncherState::Launch => { LauncherState::Launch => {
self.widgets.launch_game.set_label("Launch"); self.widgets.launch_game.set_label("Launch");
} }
// TODO LauncherState::PredownloadAvailable { game, voices } => {
LauncherState::PredownloadAvailable { .. } => {
self.widgets.launch_game.set_label("Launch"); self.widgets.launch_game.set_label("Launch");
// Calculate size of the update
let size =
game.size().unwrap_or((0, 0)).0 +
voices.into_iter().fold(0, |acc, voice| acc + voice.size().unwrap_or((0, 0)).0);
// Update tooltip
self.widgets.predownload_game.set_tooltip_text(Some(&format!("Pre-download {} update ({})", game.latest(), prettify_bytes(size))));
// Prepare button's color
self.widgets.predownload_game.remove_css_class("success");
self.widgets.predownload_game.add_css_class("warning");
self.widgets.predownload_game.set_sensitive(true);
if let Ok(config) = config::get() {
if let Some(temp) = config.launcher.temp {
let tmp = PathBuf::from(temp);
// If all the files were downloaded
let downloaded =
tmp.join(game.file_name().unwrap()).exists() &&
voices.into_iter().fold(true, move |acc, voice| acc && tmp.join(voice.file_name().unwrap()).exists());
if downloaded {
self.widgets.predownload_game.remove_css_class("warning");
self.widgets.predownload_game.add_css_class("success");
self.widgets.predownload_game.set_sensitive(false);
self.widgets.predownload_game.set_tooltip_text(Some(&format!("{} update is predownloaded ({})", game.latest(), prettify_bytes(size))));
}
}
}
self.widgets.predownload_game.show();
} }
LauncherState::PatchAvailable(patch) => { LauncherState::PatchAvailable(patch) => {

View file

@ -11,10 +11,10 @@ pub use first_run::App as FirstRunApp;
pub use main::App as MainApp; pub use main::App as MainApp;
/// This function loads object from builder or panics if it doesn't exist /// 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> { pub fn get_object<T: IsA<gtk::glib::Object>>(builder: &gtk::Builder, name: &str) -> anyhow::Result<T> {
match builder.object::<T>(name) { match builder.object::<T>(name) {
Some(object) => Ok(object), Some(object) => Ok(object),
None => Err(format!("Failed to parse object '{}'", name)) None => Err(anyhow::anyhow!("Failed to parse object '{name}'"))
} }
} }

View file

@ -48,7 +48,7 @@ pub struct AppWidgets {
} }
impl AppWidgets { impl AppWidgets {
fn try_get(window: &adw::ApplicationWindow) -> Result<Self, String> { fn try_get(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/preferences/enhancements.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/preferences/enhancements.ui");
let result = Self { let result = Self {
@ -123,7 +123,7 @@ pub struct App {
impl App { impl App {
/// Create new application /// Create new application
pub fn new(window: &adw::ApplicationWindow) -> Result<Self, String> { pub fn new(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
let result = Self { let result = Self {
widgets: AppWidgets::try_get(window)? widgets: AppWidgets::try_get(window)?
}.init_events(); }.init_events();
@ -301,7 +301,7 @@ impl App {
} }
/// This method is being called by the `PreferencesStack::update` /// This method is being called by the `PreferencesStack::update`
pub fn prepare(&self, status_page: &adw::StatusPage) -> std::io::Result<()> { pub fn prepare(&self, status_page: &adw::StatusPage) -> anyhow::Result<()> {
let config = config::get()?; let config = config::get()?;
status_page.set_description(Some("Loading enhancements...")); status_page.set_description(Some("Loading enhancements..."));

View file

@ -7,7 +7,6 @@ use gtk::glib::clone;
use std::collections::HashMap; use std::collections::HashMap;
use std::rc::Rc; use std::rc::Rc;
use std::cell::Cell; use std::cell::Cell;
use std::io::Error;
use crate::ui::get_object; use crate::ui::get_object;
use crate::lib::config; use crate::lib::config;
@ -31,7 +30,7 @@ pub struct AppWidgets {
} }
impl AppWidgets { impl AppWidgets {
fn try_get() -> Result<Self, String> { fn try_get() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/preferences/environment.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/preferences/environment.ui");
let result = Self { let result = Self {
@ -89,7 +88,7 @@ pub struct App {
impl App { impl App {
/// Create new application /// Create new application
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let result = Self { let result = Self {
widgets: AppWidgets::try_get()?, widgets: AppWidgets::try_get()?,
values: Default::default(), values: Default::default(),
@ -225,7 +224,7 @@ impl App {
} }
/// This method is being called by the `PreferencesStack::update` /// This method is being called by the `PreferencesStack::update`
pub fn prepare(&self, status_page: &adw::StatusPage) -> Result<(), Error> { pub fn prepare(&self, status_page: &adw::StatusPage) -> anyhow::Result<()> {
let config = config::get()?; let config = config::get()?;
status_page.set_description(Some("Loading environment...")); status_page.set_description(Some("Loading environment..."));

View file

@ -33,7 +33,7 @@ pub struct AppWidgets {
} }
impl AppWidgets { impl AppWidgets {
fn try_get(window: &adw::ApplicationWindow) -> Result<Self, String> { fn try_get(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/preferences/gamescope.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/preferences/gamescope.ui");
let result = Self { let result = Self {
@ -79,7 +79,7 @@ pub struct App {
impl App { impl App {
/// Create new application /// Create new application
pub fn new(window: &adw::ApplicationWindow) -> Result<Self, String> { pub fn new(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
let result = Self { let result = Self {
widgets: AppWidgets::try_get(window)? widgets: AppWidgets::try_get(window)?
}.init_events(); }.init_events();
@ -221,7 +221,7 @@ impl App {
} }
/// This method is being called by the `EnhancementsPage::prepare` /// This method is being called by the `EnhancementsPage::prepare`
pub fn prepare(&self, status_page: &adw::StatusPage) -> std::io::Result<()> { pub fn prepare(&self, status_page: &adw::StatusPage) -> anyhow::Result<()> {
let config = config::get()?; let config = config::get()?;
status_page.set_description(Some("Loading gamescope...")); status_page.set_description(Some("Loading gamescope..."));

View file

@ -55,7 +55,7 @@ pub struct AppWidgets {
} }
impl AppWidgets { impl AppWidgets {
pub fn try_get() -> Result<Self, String> { pub fn try_get() -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/preferences/general.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/preferences/general.ui");
let mut result = Self { let mut result = Self {
@ -84,16 +84,10 @@ impl AppWidgets {
dxvk_components: Default::default() dxvk_components: Default::default()
}; };
let config = match config::get() { let config = config::get()?;
Ok(config) => config,
Err(err) => return Err(err.to_string())
};
// Update voiceovers list // Update voiceovers list
let voice_packages = match VoicePackage::list_latest() { let voice_packages = VoicePackage::list_latest()?;
Ok(voice_packages) => voice_packages,
Err(err) => return Err(err.to_string())
};
let mut components = Vec::new(); let mut components = Vec::new();
@ -197,7 +191,7 @@ pub struct App {
impl App { impl App {
/// Create new application /// Create new application
pub fn new() -> Result<Self, String> { pub fn new() -> anyhow::Result<Self> {
let result = Self { let result = Self {
app: Default::default(), app: Default::default(),
widgets: AppWidgets::try_get()?, widgets: AppWidgets::try_get()?,

View file

@ -38,7 +38,7 @@ pub struct PreferencesStack {
} }
impl PreferencesStack { impl PreferencesStack {
pub fn new(window: &adw::ApplicationWindow) -> Result<Self, String> { pub fn new(window: &adw::ApplicationWindow) -> anyhow::Result<Self> {
let builder = gtk::Builder::from_resource("/org/app/ui/preferences.ui"); let builder = gtk::Builder::from_resource("/org/app/ui/preferences.ui");
let result = Self { let result = Self {

View file

@ -25,7 +25,7 @@ pub trait DownloadComponent {
Path::new(&self.get_component_path(installation_path)).exists() Path::new(&self.get_component_path(installation_path)).exists()
} }
fn download<T: ToString>(&self, installation_path: T) -> std::io::Result<Await<DownloadingResult>> { fn download<T: ToString>(&self, installation_path: T) -> anyhow::Result<Await<DownloadingResult>> {
let (sender, receiver) = glib::MainContext::channel::<InstallerUpdate>(glib::PRIORITY_DEFAULT); let (sender, receiver) = glib::MainContext::channel::<InstallerUpdate>(glib::PRIORITY_DEFAULT);
let (progress_bar, button) = self.get_downloading_widgets(); let (progress_bar, button) = self.get_downloading_widgets();