mirror of
https://github.com/ALEZ-DEV/Babylonia-terminal.git
synced 2026-03-21 21:58:52 +00:00
can now download proton from the new gtk launcher
This commit is contained in:
parent
846b4291c6
commit
fa242c1cca
782
Cargo.lock
generated
782
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -11,6 +11,8 @@ relm4-components = "0.9.1"
|
|||||||
wincompatlib = "0.7.5"
|
wincompatlib = "0.7.5"
|
||||||
relm4 = { version = "0.9.1", features = ["libadwaita"] }
|
relm4 = { version = "0.9.1", features = ["libadwaita"] }
|
||||||
libadwaita = { version = "0.7.1", features = ["v1_4"] }
|
libadwaita = { version = "0.7.1", features = ["v1_4"] }
|
||||||
|
downloader = { git = "https://github.com/ALEZ-DEV/downloader" } # version = "0.2.7",
|
||||||
|
rfd = "0.15.2"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
glib-build-tools = "0.20.0"
|
glib-build-tools = "0.20.0"
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
|
use std::{ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use babylonia_terminal_sdk::{
|
use babylonia_terminal_sdk::{
|
||||||
components::proton_component::ProtonComponent, game_config::GameConfig,
|
components::proton_component::ProtonComponent, game_config::GameConfig,
|
||||||
game_manager::GameManager,
|
game_manager::GameManager, utils::github_requester::GithubRelease,
|
||||||
};
|
};
|
||||||
use log::error;
|
use log::error;
|
||||||
use relm4::{
|
use relm4::{
|
||||||
@ -9,7 +11,10 @@ use relm4::{
|
|||||||
};
|
};
|
||||||
use wincompatlib::prelude::Proton;
|
use wincompatlib::prelude::Proton;
|
||||||
|
|
||||||
use crate::ui;
|
use crate::ui::{
|
||||||
|
self,
|
||||||
|
pages::steps::{self, download_components},
|
||||||
|
};
|
||||||
|
|
||||||
static PROTON: OnceCell<Proton> = OnceCell::const_new();
|
static PROTON: OnceCell<Proton> = OnceCell::const_new();
|
||||||
|
|
||||||
@ -71,3 +76,75 @@ impl Worker for HandleGameProcess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum HandleComponentInstallationMsg {
|
||||||
|
StartInstallation(
|
||||||
|
(
|
||||||
|
usize,
|
||||||
|
usize,
|
||||||
|
Arc<download_components::DownloadComponentProgressBarReporter>,
|
||||||
|
),
|
||||||
|
), // proton release and dxvk release
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct HandleComponentInstallation;
|
||||||
|
|
||||||
|
impl Worker for HandleComponentInstallation {
|
||||||
|
type Init = ();
|
||||||
|
|
||||||
|
type Input = HandleComponentInstallationMsg;
|
||||||
|
|
||||||
|
type Output = download_components::DownloadComponentsMsg;
|
||||||
|
|
||||||
|
fn init(_init: Self::Init, _sender: relm4::ComponentSender<Self>) -> Self {
|
||||||
|
Self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update(&mut self, message: Self::Input, sender: relm4::ComponentSender<Self>) {
|
||||||
|
match message {
|
||||||
|
HandleComponentInstallationMsg::StartInstallation((
|
||||||
|
proton_release,
|
||||||
|
dxvk_release,
|
||||||
|
progress_bar,
|
||||||
|
)) => {
|
||||||
|
tokio::runtime::Builder::new_current_thread()
|
||||||
|
.enable_all()
|
||||||
|
.build()
|
||||||
|
.unwrap()
|
||||||
|
.block_on(async {
|
||||||
|
let _ = sender.output(
|
||||||
|
download_components::DownloadComponentsMsg::UpdateProgressBarMsg(
|
||||||
|
String::from("Starting download for proton"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = sender.output(
|
||||||
|
download_components::DownloadComponentsMsg::UpdateDownloadedComponentName(
|
||||||
|
String::from("proton"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let game_dir = if let Some(dir) = GameConfig::get_config().await.game_dir {
|
||||||
|
dir
|
||||||
|
} else {
|
||||||
|
GameConfig::get_config_directory().await
|
||||||
|
};
|
||||||
|
|
||||||
|
GameManager::install_wine(game_dir, proton_release, Some(progress_bar))
|
||||||
|
.await;
|
||||||
|
|
||||||
|
let _ = sender.output(
|
||||||
|
download_components::DownloadComponentsMsg::UpdateProgressBarMsg(
|
||||||
|
String::from("Unpacking proton"),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
let _ = sender
|
||||||
|
.output(download_components::DownloadComponentsMsg::UpdateGameState);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
0
babylonia-terminal-gui/src/reporter.rs
Normal file
0
babylonia-terminal-gui/src/reporter.rs
Normal file
@ -17,7 +17,7 @@ use libadwaita as adw;
|
|||||||
|
|
||||||
use crate::APP_RESOURCE_PATH;
|
use crate::APP_RESOURCE_PATH;
|
||||||
|
|
||||||
mod pages;
|
pub mod pages;
|
||||||
|
|
||||||
pub fn run(app: RelmApp<MainWindowMsg>) {
|
pub fn run(app: RelmApp<MainWindowMsg>) {
|
||||||
app.run_async::<MainWindow>(None);
|
app.run_async::<MainWindow>(None);
|
||||||
@ -28,6 +28,7 @@ pub enum MainWindowMsg {
|
|||||||
ToggleMenuVisibility,
|
ToggleMenuVisibility,
|
||||||
SelectPage,
|
SelectPage,
|
||||||
SetIsGameRunning(bool),
|
SetIsGameRunning(bool),
|
||||||
|
UpdateGameState,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct MainWindow {
|
struct MainWindow {
|
||||||
@ -103,7 +104,7 @@ impl SimpleAsyncComponent for MainWindow {
|
|||||||
set_valign: gtk::Align::Center,
|
set_valign: gtk::Align::Center,
|
||||||
|
|
||||||
#[watch]
|
#[watch]
|
||||||
set_visible: model.game_state == GameState::GameInstalled,
|
set_visible: model.game_state.is_environment_ready(),
|
||||||
|
|
||||||
adw::PreferencesPage {
|
adw::PreferencesPage {
|
||||||
add = &adw::PreferencesGroup {
|
add = &adw::PreferencesGroup {
|
||||||
@ -142,7 +143,7 @@ impl SimpleAsyncComponent for MainWindow {
|
|||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
|
||||||
set_visible: model.game_state != GameState::GameInstalled,
|
set_visible: !model.game_state.is_environment_ready(),
|
||||||
|
|
||||||
model.setup_page.widget(),
|
model.setup_page.widget(),
|
||||||
}
|
}
|
||||||
@ -236,6 +237,9 @@ impl SimpleAsyncComponent for MainWindow {
|
|||||||
MainWindowMsg::ToggleMenuVisibility => self.is_menu_visible = !self.is_menu_visible,
|
MainWindowMsg::ToggleMenuVisibility => self.is_menu_visible = !self.is_menu_visible,
|
||||||
MainWindowMsg::SelectPage => println!("Tried to select a new page"),
|
MainWindowMsg::SelectPage => println!("Tried to select a new page"),
|
||||||
MainWindowMsg::SetIsGameRunning(value) => self.is_game_running = value,
|
MainWindowMsg::SetIsGameRunning(value) => self.is_game_running = value,
|
||||||
|
MainWindowMsg::UpdateGameState => {
|
||||||
|
self.game_state = GameState::get_current_state().await.unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,122 @@
|
|||||||
|
use std::{path::PathBuf, str::FromStr};
|
||||||
|
|
||||||
|
use babylonia_terminal_sdk::{game_config::GameConfig, game_manager::GameManager};
|
||||||
|
use log::info;
|
||||||
|
use relm4::{
|
||||||
|
gtk,
|
||||||
|
prelude::{AsyncComponentParts, SimpleAsyncComponent},
|
||||||
|
view, RelmWidgetExt,
|
||||||
|
};
|
||||||
|
|
||||||
|
use libadwaita::{self as adw, prelude::*};
|
||||||
|
|
||||||
|
use super::SetupPageMsg;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ChooseGameDirectoryMsg {
|
||||||
|
ChoosePath,
|
||||||
|
Next,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ChooseGameDirectoryPage {
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[relm4::component(async, pub)]
|
||||||
|
impl SimpleAsyncComponent for ChooseGameDirectoryPage {
|
||||||
|
type Input = ChooseGameDirectoryMsg;
|
||||||
|
|
||||||
|
type Output = SetupPageMsg;
|
||||||
|
|
||||||
|
type Init = ();
|
||||||
|
|
||||||
|
view! {
|
||||||
|
#[root]
|
||||||
|
gtk::Box {
|
||||||
|
adw::PreferencesPage {
|
||||||
|
set_hexpand: true,
|
||||||
|
|
||||||
|
add = &adw::PreferencesGroup {
|
||||||
|
set_valign: gtk::Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
|
gtk::Label {
|
||||||
|
set_label: "Game directory",
|
||||||
|
add_css_class: "title-1"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
add = &adw::PreferencesGroup {
|
||||||
|
set_valign: gtk::Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
|
adw::ActionRow {
|
||||||
|
set_title: "Game directory",
|
||||||
|
set_icon_name: Some("folder-symbolic"),
|
||||||
|
set_activatable: true,
|
||||||
|
|
||||||
|
#[watch]
|
||||||
|
set_subtitle: model.path.to_str().unwrap(),
|
||||||
|
|
||||||
|
connect_activated => ChooseGameDirectoryMsg::ChoosePath,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
add = &adw::PreferencesGroup {
|
||||||
|
set_margin_vertical: 48,
|
||||||
|
|
||||||
|
gtk::Button {
|
||||||
|
set_css_classes: &["suggested-action", "pill"],
|
||||||
|
|
||||||
|
set_label: "Next",
|
||||||
|
set_hexpand: false,
|
||||||
|
set_width_request: 200,
|
||||||
|
|
||||||
|
connect_clicked => ChooseGameDirectoryMsg::Next,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn init(
|
||||||
|
init: Self::Init,
|
||||||
|
root: Self::Root,
|
||||||
|
sender: relm4::AsyncComponentSender<Self>,
|
||||||
|
) -> relm4::prelude::AsyncComponentParts<Self> {
|
||||||
|
let path = if let Some(dir) = GameConfig::get_config().await.game_dir {
|
||||||
|
dir
|
||||||
|
} else {
|
||||||
|
GameConfig::get_config_directory().await
|
||||||
|
};
|
||||||
|
|
||||||
|
let model = ChooseGameDirectoryPage { path };
|
||||||
|
|
||||||
|
let widgets = view_output!();
|
||||||
|
|
||||||
|
AsyncComponentParts { widgets, model }
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn update(&mut self, message: Self::Input, sender: relm4::AsyncComponentSender<Self>) {
|
||||||
|
match message {
|
||||||
|
ChooseGameDirectoryMsg::ChoosePath => {
|
||||||
|
info!("choose path");
|
||||||
|
let result = rfd::AsyncFileDialog::new()
|
||||||
|
.set_directory(self.path.clone())
|
||||||
|
.pick_folder()
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Some(result) = result {
|
||||||
|
self.path = result.path().to_path_buf();
|
||||||
|
}
|
||||||
|
|
||||||
|
GameConfig::set_game_dir(Some(self.path.clone()))
|
||||||
|
.await
|
||||||
|
.unwrap(); // TODO: remove unwrap
|
||||||
|
}
|
||||||
|
ChooseGameDirectoryMsg::Next => {
|
||||||
|
let _ = sender.output(SetupPageMsg::GoToDownloadComponentPage);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,10 +1,14 @@
|
|||||||
|
use std::{convert::identity, usize};
|
||||||
|
|
||||||
use babylonia_terminal_sdk::{
|
use babylonia_terminal_sdk::{
|
||||||
components::{
|
components::{
|
||||||
dxvk_component::{self, DXVKComponent},
|
dxvk_component::{self, DXVKComponent},
|
||||||
proton_component::{self, ProtonComponent},
|
proton_component::{self, ProtonComponent},
|
||||||
},
|
},
|
||||||
|
game_state::GameState,
|
||||||
utils::github_requester::{GithubRelease, GithubRequester},
|
utils::github_requester::{GithubRelease, GithubRequester},
|
||||||
};
|
};
|
||||||
|
use log::{error, info};
|
||||||
use relm4::{
|
use relm4::{
|
||||||
self,
|
self,
|
||||||
gtk::{self, prelude::*},
|
gtk::{self, prelude::*},
|
||||||
@ -15,18 +19,44 @@ use relm4::{
|
|||||||
use adw::prelude::*;
|
use adw::prelude::*;
|
||||||
use libadwaita as adw;
|
use libadwaita as adw;
|
||||||
|
|
||||||
use crate::ui::MainWindowMsg;
|
use crate::{manager, ui::MainWindowMsg};
|
||||||
|
|
||||||
use super::SetupPageMsg;
|
use super::SetupPageMsg;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum DownloadComponentsMsg {
|
pub enum DownloadComponentsMsg {
|
||||||
Next,
|
Next,
|
||||||
|
UpdateGameState,
|
||||||
|
UpdateProgressBar((u64, u64)), // current and max_progress
|
||||||
|
UpdateProgressBarMsg(String),
|
||||||
|
UpdateDownloadedComponentName(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
pub struct DownloadComponentsPage {
|
pub struct DownloadComponentsPage {
|
||||||
|
//state
|
||||||
|
game_state: GameState,
|
||||||
|
|
||||||
|
// widgets
|
||||||
|
proton_combo: adw::ComboRow,
|
||||||
|
dxvk_combo: adw::ComboRow,
|
||||||
|
|
||||||
|
// values
|
||||||
proton_versions: Vec<GithubRelease>,
|
proton_versions: Vec<GithubRelease>,
|
||||||
dxvk_versions: Vec<GithubRelease>,
|
dxvk_versions: Vec<GithubRelease>,
|
||||||
|
selected_proton_version: Option<GithubRelease>,
|
||||||
|
selected_dxvk_version: Option<GithubRelease>,
|
||||||
|
|
||||||
|
//progress_bar
|
||||||
|
progress_bar_reporter: std::sync::Arc<DownloadComponentProgressBarReporter>,
|
||||||
|
progress_bar_message: String,
|
||||||
|
fraction: f64,
|
||||||
|
show_progress_bar: bool,
|
||||||
|
|
||||||
|
// download part
|
||||||
|
is_installing: bool,
|
||||||
|
installation_handler: WorkerController<manager::HandleComponentInstallation>,
|
||||||
|
downloaded_component_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[relm4::component(async, pub)]
|
#[relm4::component(async, pub)]
|
||||||
@ -35,68 +65,128 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
|
|||||||
|
|
||||||
type Output = SetupPageMsg;
|
type Output = SetupPageMsg;
|
||||||
|
|
||||||
type Init = ();
|
type Init = GameState;
|
||||||
|
|
||||||
view! {
|
view! {
|
||||||
#[root]
|
#[root]
|
||||||
adw::PreferencesPage {
|
gtk::Box {
|
||||||
set_hexpand: true,
|
adw::PreferencesPage {
|
||||||
|
set_hexpand: true,
|
||||||
|
#[watch]
|
||||||
|
set_visible: !model.is_installing,
|
||||||
|
|
||||||
add = &adw::PreferencesGroup {
|
add = &adw::PreferencesGroup {
|
||||||
set_valign: gtk::Align::Center,
|
set_valign: gtk::Align::Center,
|
||||||
set_vexpand: true,
|
set_vexpand: true,
|
||||||
|
|
||||||
gtk::Label {
|
gtk::Label {
|
||||||
set_label: "Install components",
|
set_label: "Install components",
|
||||||
add_css_class: "title-1"
|
add_css_class: "title-1"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
add = &adw::PreferencesGroup {
|
||||||
|
set_valign: gtk::Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
|
#[local_ref]
|
||||||
|
proton_combo -> adw::ComboRow {
|
||||||
|
set_title: "proton version",
|
||||||
|
|
||||||
|
set_model: Some(>k::StringList::new(model
|
||||||
|
.proton_versions
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.tag_name.as_str())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.as_slice())),
|
||||||
|
},
|
||||||
|
|
||||||
|
#[local_ref]
|
||||||
|
dxvk_combo -> adw::ComboRow {
|
||||||
|
set_title: "dxvk version",
|
||||||
|
|
||||||
|
set_model: Some(>k::StringList::new(model
|
||||||
|
.dxvk_versions
|
||||||
|
.iter()
|
||||||
|
.map(|r| r.tag_name.as_str())
|
||||||
|
.collect::<Vec<&str>>()
|
||||||
|
.as_slice())),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
add = &adw::PreferencesGroup {
|
||||||
|
set_margin_vertical: 48,
|
||||||
|
|
||||||
|
gtk::Button {
|
||||||
|
set_css_classes: &["suggested-action", "pill"],
|
||||||
|
|
||||||
|
set_label: "Next",
|
||||||
|
set_hexpand: false,
|
||||||
|
set_width_request: 200,
|
||||||
|
|
||||||
|
connect_clicked => DownloadComponentsMsg::Next,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
add = &adw::PreferencesGroup {
|
adw::PreferencesPage {
|
||||||
set_valign: gtk::Align::Center,
|
set_hexpand: true,
|
||||||
set_vexpand: true,
|
#[watch]
|
||||||
|
set_visible: model.is_installing,
|
||||||
|
|
||||||
adw::ComboRow {
|
add = &adw::PreferencesGroup {
|
||||||
set_title: "Proton version",
|
set_valign: gtk::Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
set_model: Some(>k::StringList::new(model
|
gtk::Label {
|
||||||
.proton_versions
|
set_label: "Downloading and installing components",
|
||||||
.iter()
|
add_css_class: "title-1"
|
||||||
.map(|r| r.tag_name.as_str())
|
},
|
||||||
.collect::<Vec<&str>>()
|
|
||||||
.as_slice())),
|
|
||||||
},
|
},
|
||||||
|
|
||||||
adw::ComboRow {
|
add = &adw::PreferencesGroup {
|
||||||
set_title: "DXVK version",
|
set_valign: gtk::Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
set_model: Some(>k::StringList::new(model
|
adw::ActionRow {
|
||||||
.dxvk_versions
|
#[watch]
|
||||||
.iter()
|
set_title: match &model.selected_proton_version {
|
||||||
.map(|r| r.tag_name.as_str())
|
Some(release) => &release.tag_name,
|
||||||
.collect::<Vec<&str>>()
|
None => "WTF??!! there's no proton version found ????",
|
||||||
.as_slice())),
|
},
|
||||||
|
set_subtitle: "Proton version",
|
||||||
|
|
||||||
|
#[watch]
|
||||||
|
set_icon_name: if model.game_state == GameState::ProtonNotInstalled { Some("emblem-ok-symbolic") } else { Some("process-working") },
|
||||||
|
|
||||||
|
add_prefix = >k::Spinner {
|
||||||
|
set_spinning: true,
|
||||||
|
|
||||||
|
#[watch]
|
||||||
|
set_visible: model.game_state == GameState::ProtonNotInstalled,
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
add = &adw::PreferencesGroup {
|
||||||
|
set_valign: gtk::Align::Center,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
|
gtk::ProgressBar {
|
||||||
|
#[watch]
|
||||||
|
set_fraction: model.fraction,
|
||||||
|
|
||||||
|
#[watch]
|
||||||
|
set_text: Some(&model.progress_bar_message),
|
||||||
|
set_show_text: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
}
|
||||||
add = &adw::PreferencesGroup {
|
|
||||||
set_margin_vertical: 48,
|
|
||||||
|
|
||||||
gtk::Button {
|
|
||||||
set_css_classes: &["suggested-action", "pill"],
|
|
||||||
|
|
||||||
set_label: "Next",
|
|
||||||
set_hexpand: false,
|
|
||||||
set_width_request: 200,
|
|
||||||
|
|
||||||
connect_clicked => DownloadComponentsMsg::Next,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn init(
|
async fn init(
|
||||||
init: Self::Init,
|
game_state: Self::Init,
|
||||||
root: Self::Root,
|
root: Self::Root,
|
||||||
sender: AsyncComponentSender<Self>,
|
sender: AsyncComponentSender<Self>,
|
||||||
) -> AsyncComponentParts<Self> {
|
) -> AsyncComponentParts<Self> {
|
||||||
@ -113,16 +203,129 @@ impl SimpleAsyncComponent for DownloadComponentsPage {
|
|||||||
.unwrap(); //TODO: remove unwrap()
|
.unwrap(); //TODO: remove unwrap()
|
||||||
|
|
||||||
let model = DownloadComponentsPage {
|
let model = DownloadComponentsPage {
|
||||||
|
game_state,
|
||||||
|
|
||||||
|
proton_combo: adw::ComboRow::new(),
|
||||||
|
dxvk_combo: adw::ComboRow::new(),
|
||||||
|
|
||||||
proton_versions: proton_releases,
|
proton_versions: proton_releases,
|
||||||
dxvk_versions: dxvk_releases,
|
dxvk_versions: dxvk_releases,
|
||||||
|
selected_proton_version: None,
|
||||||
|
selected_dxvk_version: None,
|
||||||
|
|
||||||
|
progress_bar_reporter: DownloadComponentProgressBarReporter::create(sender.clone()),
|
||||||
|
progress_bar_message: String::new(),
|
||||||
|
fraction: 0.0,
|
||||||
|
show_progress_bar: false,
|
||||||
|
|
||||||
|
is_installing: false,
|
||||||
|
installation_handler: manager::HandleComponentInstallation::builder()
|
||||||
|
.detach_worker(())
|
||||||
|
.forward(sender.input_sender(), identity),
|
||||||
|
downloaded_component_name: String::new(),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let proton_combo = &model.proton_combo;
|
||||||
|
let dxvk_combo = &model.dxvk_combo;
|
||||||
|
|
||||||
let widgets = view_output!();
|
let widgets = view_output!();
|
||||||
|
|
||||||
AsyncComponentParts { widgets, model }
|
AsyncComponentParts { widgets, model }
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update(&mut self, message: Self::Input, sender: AsyncComponentSender<Self>) -> () {
|
async fn update(&mut self, message: Self::Input, sender: AsyncComponentSender<Self>) -> () {
|
||||||
todo!();
|
match message {
|
||||||
|
DownloadComponentsMsg::Next => {
|
||||||
|
if !self.is_installing {
|
||||||
|
self.is_installing = true;
|
||||||
|
|
||||||
|
let proton_index = self.proton_combo.selected() as usize;
|
||||||
|
let dxvk_index = self.dxvk_combo.selected() as usize;
|
||||||
|
|
||||||
|
let proton_release = self.proton_versions[proton_index].clone();
|
||||||
|
let dxvk_release = self.dxvk_versions[dxvk_index].clone();
|
||||||
|
|
||||||
|
self.selected_proton_version = Some(proton_release);
|
||||||
|
self.selected_dxvk_version = Some(dxvk_release);
|
||||||
|
let _ = self.installation_handler.sender().send(
|
||||||
|
manager::HandleComponentInstallationMsg::StartInstallation((
|
||||||
|
proton_index,
|
||||||
|
dxvk_index,
|
||||||
|
self.progress_bar_reporter.clone(),
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let _ = sender.output(SetupPageMsg::Finish);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DownloadComponentsMsg::UpdateDownloadedComponentName(name) => {
|
||||||
|
self.downloaded_component_name = name;
|
||||||
|
}
|
||||||
|
DownloadComponentsMsg::UpdateGameState => {
|
||||||
|
self.game_state = GameState::get_current_state().await.unwrap();
|
||||||
|
}
|
||||||
|
DownloadComponentsMsg::UpdateProgressBar((current, max_progress)) => {
|
||||||
|
self.fraction = if current == 0 {
|
||||||
|
0.0
|
||||||
|
} else {
|
||||||
|
current as f64 / max_progress as f64
|
||||||
|
};
|
||||||
|
|
||||||
|
self.progress_bar_message = format!(
|
||||||
|
"Downloading {} : {:.2}%",
|
||||||
|
self.downloaded_component_name,
|
||||||
|
self.fraction * 100.0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
DownloadComponentsMsg::UpdateProgressBarMsg(message) => {
|
||||||
|
self.progress_bar_message = message;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
struct ProgressBarReporterPrivate {
|
||||||
|
max_progress: Option<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DownloadComponentProgressBarReporter {
|
||||||
|
private: std::sync::Mutex<Option<ProgressBarReporterPrivate>>,
|
||||||
|
sender: relm4::AsyncComponentSender<DownloadComponentsPage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DownloadComponentProgressBarReporter {
|
||||||
|
fn create(page: relm4::AsyncComponentSender<DownloadComponentsPage>) -> std::sync::Arc<Self> {
|
||||||
|
std::sync::Arc::new(Self {
|
||||||
|
private: std::sync::Mutex::new(None),
|
||||||
|
sender: page,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl downloader::progress::Reporter for DownloadComponentProgressBarReporter {
|
||||||
|
fn setup(&self, max_progress: Option<u64>, message: &str) {
|
||||||
|
let private = ProgressBarReporterPrivate { max_progress };
|
||||||
|
|
||||||
|
let mut guard = self.private.lock().unwrap();
|
||||||
|
*guard = Some(private);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn progress(&self, current: u64) {
|
||||||
|
if let Some(p) = self.private.lock().unwrap().as_mut() {
|
||||||
|
self.sender.input(DownloadComponentsMsg::UpdateProgressBar((
|
||||||
|
current,
|
||||||
|
p.max_progress.unwrap(),
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_message(&self, message: &str) {}
|
||||||
|
|
||||||
|
fn done(&self) {
|
||||||
|
self.sender.input(DownloadComponentsMsg::Next);
|
||||||
|
let mut guard = self.private.lock().unwrap();
|
||||||
|
*guard = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
use std::convert::identity;
|
use std::convert::identity;
|
||||||
|
|
||||||
use babylonia_terminal_sdk::game_state::GameState;
|
use babylonia_terminal_sdk::{game_config::GameConfig, game_state::GameState};
|
||||||
|
use choose_game_directory::ChooseGameDirectoryPage;
|
||||||
use download_components::DownloadComponentsPage;
|
use download_components::DownloadComponentsPage;
|
||||||
use libadwaita::prelude::{OrientableExt, WidgetExt};
|
use libadwaita::prelude::{OrientableExt, WidgetExt};
|
||||||
use relm4::{
|
use relm4::{
|
||||||
@ -14,17 +15,21 @@ use welcome::WelcomePage;
|
|||||||
|
|
||||||
use crate::ui::MainWindowMsg;
|
use crate::ui::MainWindowMsg;
|
||||||
|
|
||||||
mod download_components;
|
mod choose_game_directory;
|
||||||
|
pub mod download_components;
|
||||||
mod welcome;
|
mod welcome;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum SetupPageMsg {
|
pub enum SetupPageMsg {
|
||||||
UpdateGameState,
|
GoToChooseGameDirectoryPage,
|
||||||
|
GoToDownloadComponentPage,
|
||||||
|
Finish,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SetupPage {
|
pub struct SetupPage {
|
||||||
game_state: GameState,
|
game_state: GameState,
|
||||||
welcome_page: Controller<welcome::WelcomePage>,
|
welcome_page: Controller<welcome::WelcomePage>,
|
||||||
|
choose_game_directory_page: AsyncController<choose_game_directory::ChooseGameDirectoryPage>,
|
||||||
download_components_page: AsyncController<download_components::DownloadComponentsPage>,
|
download_components_page: AsyncController<download_components::DownloadComponentsPage>,
|
||||||
|
|
||||||
carousel: adw::Carousel,
|
carousel: adw::Carousel,
|
||||||
@ -42,6 +47,8 @@ impl SimpleAsyncComponent for SetupPage {
|
|||||||
#[root]
|
#[root]
|
||||||
gtk::Box {
|
gtk::Box {
|
||||||
set_orientation: gtk::Orientation::Vertical,
|
set_orientation: gtk::Orientation::Vertical,
|
||||||
|
set_hexpand: true,
|
||||||
|
set_vexpand: true,
|
||||||
|
|
||||||
#[local_ref]
|
#[local_ref]
|
||||||
carousel -> adw::Carousel {
|
carousel -> adw::Carousel {
|
||||||
@ -50,6 +57,7 @@ impl SimpleAsyncComponent for SetupPage {
|
|||||||
set_allow_scroll_wheel: false,
|
set_allow_scroll_wheel: false,
|
||||||
|
|
||||||
append = model.welcome_page.widget(),
|
append = model.welcome_page.widget(),
|
||||||
|
append = model.choose_game_directory_page.widget(),
|
||||||
append = model.download_components_page.widget(),
|
append = model.download_components_page.widget(),
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -68,9 +76,12 @@ impl SimpleAsyncComponent for SetupPage {
|
|||||||
let welcome_page = WelcomePage::builder()
|
let welcome_page = WelcomePage::builder()
|
||||||
.launch(())
|
.launch(())
|
||||||
.forward(sender.input_sender(), identity);
|
.forward(sender.input_sender(), identity);
|
||||||
let download_components_page = DownloadComponentsPage::builder()
|
let choose_game_directory_page = ChooseGameDirectoryPage::builder()
|
||||||
.launch(())
|
.launch(())
|
||||||
.forward(sender.input_sender(), identity);
|
.forward(sender.input_sender(), identity);
|
||||||
|
let download_components_page = DownloadComponentsPage::builder()
|
||||||
|
.launch(game_state.clone())
|
||||||
|
.forward(sender.input_sender(), identity);
|
||||||
|
|
||||||
let carousel = adw::Carousel::new();
|
let carousel = adw::Carousel::new();
|
||||||
|
|
||||||
@ -78,6 +89,7 @@ impl SimpleAsyncComponent for SetupPage {
|
|||||||
|
|
||||||
let model = SetupPage {
|
let model = SetupPage {
|
||||||
welcome_page,
|
welcome_page,
|
||||||
|
choose_game_directory_page,
|
||||||
download_components_page,
|
download_components_page,
|
||||||
game_state,
|
game_state,
|
||||||
carousel: carousel.clone(),
|
carousel: carousel.clone(),
|
||||||
@ -88,24 +100,20 @@ impl SimpleAsyncComponent for SetupPage {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn update(&mut self, message: Self::Input, sender: AsyncComponentSender<Self>) {
|
async fn update(&mut self, message: Self::Input, sender: AsyncComponentSender<Self>) {
|
||||||
match message {
|
self.game_state = GameState::get_current_state().await.unwrap(); // TODO: delete this unwrap()
|
||||||
SetupPageMsg::UpdateGameState => {
|
|
||||||
self.game_state = GameState::get_current_state().await.unwrap()
|
|
||||||
} // TODO: delete this unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
match self.game_state {
|
match message {
|
||||||
GameState::ProtonNotInstalled => {
|
SetupPageMsg::GoToChooseGameDirectoryPage => {
|
||||||
|
self.carousel
|
||||||
|
.scroll_to(self.choose_game_directory_page.widget(), true);
|
||||||
|
}
|
||||||
|
SetupPageMsg::GoToDownloadComponentPage => {
|
||||||
self.carousel
|
self.carousel
|
||||||
.scroll_to(self.download_components_page.widget(), true);
|
.scroll_to(self.download_components_page.widget(), true);
|
||||||
}
|
}
|
||||||
GameState::DXVKNotInstalled => todo!(),
|
SetupPageMsg::Finish => {
|
||||||
GameState::FontNotInstalled => todo!(),
|
sender.output(MainWindowMsg::UpdateGameState);
|
||||||
GameState::DependecieNotInstalled => todo!(),
|
}
|
||||||
GameState::GameNotInstalled => todo!(),
|
|
||||||
GameState::GameNeedUpdate => todo!(),
|
|
||||||
GameState::GameNotPatched => todo!(),
|
|
||||||
GameState::GameInstalled => todo!(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,7 +78,9 @@ impl SimpleComponent for WelcomePage {
|
|||||||
|
|
||||||
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
|
||||||
match message {
|
match message {
|
||||||
WelcomePageMsg::Next => sender.output(SetupPageMsg::UpdateGameState).unwrap(),
|
WelcomePageMsg::Next => sender
|
||||||
|
.output(SetupPageMsg::GoToChooseGameDirectoryPage)
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,4 +46,11 @@ impl GameState {
|
|||||||
|
|
||||||
Ok(GameState::GameInstalled)
|
Ok(GameState::GameInstalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_environment_ready(&self) -> bool {
|
||||||
|
self == &GameState::GameNotInstalled
|
||||||
|
|| self == &GameState::GameNeedUpdate
|
||||||
|
|| self == &GameState::GameNotPatched
|
||||||
|
|| self == &GameState::GameInstalled
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user