diff --git a/Cargo.lock b/Cargo.lock index 400d865..8083348 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -87,8 +87,8 @@ dependencies = [ [[package]] name = "anime-launcher-sdk" -version = "1.1.6" -source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.1.6#4169e902252f7fd2c71cacbc31997ccc3a0e07d2" +version = "1.2.1" +source = "git+https://github.com/an-anime-team/anime-launcher-sdk?tag=1.2.1#f7bddd1d2fde4dcc7d04bda9e4d9160a5bc88218" dependencies = [ "anime-game-core", "anyhow", diff --git a/Cargo.toml b/Cargo.toml index b067072..de23876 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ glib-build-tools = "0.17" [dependencies.anime-launcher-sdk] git = "https://github.com/an-anime-team/anime-launcher-sdk" -tag = "1.1.6" +tag = "1.2.1" features = ["all", "genshin"] # path = "../anime-launcher-sdk" # ! for dev purposes only diff --git a/src/ui/preferences/environment.rs b/src/ui/preferences/environment.rs index 6b71ee3..c7ceb70 100644 --- a/src/ui/preferences/environment.rs +++ b/src/ui/preferences/environment.rs @@ -167,11 +167,11 @@ impl SimpleAsyncComponent for EnvironmentApp { async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender) { match msg { EnvironmentAppMsg::Add => { - if let Ok(mut config) = Config::get() { - let name = self.name_entry.text().trim().to_string(); - let value = self.value_entry.text().trim().to_string(); + let name = self.name_entry.text().trim().to_string(); + let value = self.value_entry.text().trim().to_string(); - if !name.is_empty() && !value.is_empty() { + if !name.is_empty() && !value.is_empty() { + if let Ok(mut config) = Config::get() { self.name_entry.set_text(""); self.value_entry.set_text(""); diff --git a/src/ui/preferences/game.rs b/src/ui/preferences/game.rs index ca98c67..2cf5dc9 100644 --- a/src/ui/preferences/game.rs +++ b/src/ui/preferences/game.rs @@ -4,14 +4,18 @@ use relm4::factory::*; use adw::prelude::*; +use anime_launcher_sdk::sessions::SessionsExt; +use anime_launcher_sdk::genshin::sessions::Sessions; + +use super::main::PreferencesAppMsg; + use crate::i18n::tr; use crate::*; #[derive(Debug)] struct GameSession { - title: String, - description: Option, - id: usize + name: String, + description: Option } #[relm4::factory(async)] @@ -25,16 +29,32 @@ impl AsyncFactoryComponent for GameSession { view! { root = adw::ActionRow { - set_title: &self.title, + set_title: &self.name, set_subtitle: match &self.description { Some(description) => description.as_str(), None => "" }, + add_suffix = >k::Button { + set_icon_name: "view-refresh-symbolic-symbolic", + add_css_class: "flat", + + set_tooltip_text: Some("Update session using current wine prefix registry values"), + + set_valign: gtk::Align::Center, + + connect_clicked[sender, index] => move |_| { + sender.output(GameAppMsg::UpdateSession(index.clone())); + } + }, + add_suffix = >k::Button { set_icon_name: "user-trash-symbolic", add_css_class: "flat", + + set_tooltip_text: Some("Delete session"), + set_valign: gtk::Align::Center, connect_clicked[sender, index] => move |_| { @@ -60,21 +80,26 @@ impl AsyncFactoryComponent for GameSession { pub struct GameApp { sessions: AsyncFactoryVecDeque, - active_sessions: gtk::StringList, + sessions_names: Vec, + + sessions_combo: adw::ComboRow, session_name_entry: adw::EntryRow } #[derive(Debug, Clone)] pub enum GameAppMsg { AddSession, - RemoveSession(DynamicIndex) + UpdateSession(DynamicIndex), + RemoveSession(DynamicIndex), + SetCurrent(u32), + UpdateCombo } #[relm4::component(async, pub)] impl SimpleAsyncComponent for GameApp { type Init = (); type Input = GameAppMsg; - type Output = (); + type Output = PreferencesAppMsg; view! { adw::PreferencesPage { @@ -84,11 +109,12 @@ impl SimpleAsyncComponent for GameApp { add = &adw::PreferencesGroup { set_title: "Game sessions", - adw::ComboRow { + #[local_ref] + sessions_combo -> adw::ComboRow { set_title: "Active session", - set_subtitle: "Currently selected game session", + set_subtitle: "Currently selected game session. Updates after each game launch", - set_model = Some(&model.active_sessions), + connect_selected_notify[sender] => move |row| sender.input(GameAppMsg::SetCurrent(row.selected())) } }, @@ -123,45 +149,137 @@ impl SimpleAsyncComponent for GameApp { let mut model = Self { sessions: AsyncFactoryVecDeque::new(adw::PreferencesGroup::new(), sender.input_sender()), - active_sessions: gtk::StringList::new(&[]), + sessions_names: Vec::new(), + + sessions_combo: adw::ComboRow::new(), session_name_entry: adw::EntryRow::new() }; - /*for (name, value) in &CONFIG.game.environment { - model.variables.guard().push_back(); - }*/ + for (name, _) in Sessions::list().unwrap_or_default() { + model.sessions.guard().push_back(GameSession { + name: name.clone(), + description: None + }); + } let sessions = model.sessions.widget(); + let sessions_combo = &model.sessions_combo; let session_name_entry = &model.session_name_entry; let widgets = view_output!(); + sender.input(GameAppMsg::UpdateCombo); + AsyncComponentParts { model, widgets } } - async fn update(&mut self, msg: Self::Input, _sender: AsyncComponentSender) { + async fn update(&mut self, msg: Self::Input, sender: AsyncComponentSender) { match msg { GameAppMsg::AddSession => { let name = self.session_name_entry.text().trim().to_string(); if !name.is_empty() { - self.session_name_entry.set_text(""); + if let Ok(config) = Config::get() { + self.session_name_entry.set_text(""); - self.active_sessions.append(&name); + match Sessions::update(name.clone(), config.get_wine_prefix_path()) { + Ok(()) => { + self.sessions.guard().push_back(GameSession { + name, + description: None + }); - self.sessions.guard().push_back(GameSession { - title: name, - description: None, - id: 0 - }); + sender.input(GameAppMsg::UpdateCombo); + } + + #[allow(unused_must_use)] + Err(err) => { + sender.output(PreferencesAppMsg::Toast { + title: String::from("Failed to update game session"), + description: Some(err.to_string()) + }); + } + } + } + } + } + + GameAppMsg::UpdateSession(index) => { + if let Some(session) = self.sessions.guard().get(index.current_index()) { + if let Ok(config) = Config::get() { + #[allow(unused_must_use)] + if let Err(err) = Sessions::update(session.name.clone(), config.get_wine_prefix_path()) { + sender.output(PreferencesAppMsg::Toast { + title: String::from("Failed to update game session"), + description: Some(err.to_string()) + }); + } + } } } GameAppMsg::RemoveSession(index) => { - self.active_sessions.remove(index.current_index() as u32); + if let Some(session) = self.sessions.guard().get(index.current_index()) { + match Sessions::remove(&session.name) { + Ok(()) => sender.input(GameAppMsg::UpdateCombo), + + #[allow(unused_must_use)] + Err(err) => { + sender.output(PreferencesAppMsg::Toast { + title: String::from("Failed to update game session"), + description: Some(err.to_string()) + }); + + return; + } + } + } + self.sessions.guard().remove(index.current_index()); } + + GameAppMsg::SetCurrent(id) => { + if let Some(name) = self.sessions_names.get(id as usize) { + if let Ok(config) = Config::get() { + #[allow(unused_must_use)] + if let Err(err) = Sessions::set_current(name.to_owned()) { + sender.output(PreferencesAppMsg::Toast { + title: String::from("Failed to update game session"), + description: Some(err.to_string()) + }); + + // Prevent session applying + return; + } + + #[allow(unused_must_use)] + if let Err(err) = Sessions::apply(name.to_owned(), config.get_wine_prefix_path()) { + sender.output(PreferencesAppMsg::Toast { + title: String::from("Failed to update game session"), + description: Some(err.to_string()) + }); + } + } + } + } + + GameAppMsg::UpdateCombo => { + let sessions = Sessions::get_sessions().unwrap_or_default(); + + self.sessions_names = sessions.sessions.into_keys().collect::>(); + + let mut selected = 0; + + for (i, name) in self.sessions_names.iter().enumerate() { + if sessions.current.as_ref() == Some(name) { + selected = i as u32; + } + } + + self.sessions_combo.set_model(Some(>k::StringList::new(&self.sessions_names.iter().map(|name: &String| name.as_str()).collect::>()))); + self.sessions_combo.set_selected(selected); + } } } } diff --git a/src/ui/preferences/sandbox.rs b/src/ui/preferences/sandbox.rs index 74ede8a..1a9c474 100644 --- a/src/ui/preferences/sandbox.rs +++ b/src/ui/preferences/sandbox.rs @@ -7,6 +7,7 @@ use adw::prelude::*; use anime_launcher_sdk::is_available; use super::main::PreferencesAppMsg; + use crate::i18n::tr; use crate::*;