use std::hash::{DefaultHasher, Hash, Hasher}; use crate::model::config::GlobalConfig; use crate::model::patch::PatchFileVec; use crate::pkg::{Feature, Status}; use crate::profiles::Profile; use crate::{model::misc::Game, pkg::PkgKey}; use crate::pkg_store::PackageStore; use crate::util; use anyhow::{anyhow, Result}; use tauri::AppHandle; pub struct GlobalState { pub remain_open: bool, } pub struct AppData { pub profile: Option, pub pkgs: PackageStore, pub cfg: GlobalConfig, pub state: GlobalState, pub patch_set: PatchFileVec, } #[derive(PartialEq, Debug, Copy, Clone)] pub enum ToggleAction { Disable, EnableSelf, EnableRecursive, } impl AppData { pub fn new(apph: AppHandle) -> AppData { let cfg = std::fs::read_to_string(util::config_dir().join("config.json")) .and_then(|s| Ok(serde_json::from_str::(&s)?)) .unwrap_or_default(); let profile = match cfg.recent_profile { Some((game, ref name)) => Profile::load(game, name.clone()).ok(), None => None }; let patch_set = PatchFileVec::new(util::config_dir()) .map_err(|e| log::error!("unable to load patch set: {e}")) .unwrap_or_default(); log::debug!("Recent profile: {:?}", profile); AppData { profile: profile, pkgs: PackageStore::new(apph.clone()), cfg, state: GlobalState { remain_open: true }, patch_set } } pub fn write(&self) -> Result<(), std::io::Error> { std::fs::write(util::config_dir().join("config.json"), serde_json::to_string_pretty(&self.cfg)?) } pub fn switch_profile(&mut self, game: Game, name: String) -> Result<()> { match Profile::load(game.clone(), name.clone()) { Ok(profile) => { self.profile = Some(profile); self.cfg.recent_profile = Some((game, name)); self.write()?; Ok(()) } Err(e) => { self.profile = None; self.cfg.recent_profile = None; Err(e) } } } pub fn toggle_package(&mut self, key: PkgKey, action: ToggleAction) -> Result<()> { log::debug!("toggle: {} {:?}", key, action); let profile = self.profile.as_mut().ok_or_else(|| anyhow!("No profile"))?; if action != ToggleAction::Disable { let pkg = self.pkgs.get(&key)?; let loc = pkg.loc .clone() .ok_or_else(|| anyhow!("Attempted to enable a non-existent package"))?; if let Status::OK(feature_set) = loc.status { log::debug!("{:?}", feature_set); if feature_set.contains(Feature::Mod) { profile.mod_pkgs_mut().insert(key); } } if action == ToggleAction::EnableRecursive { for d in &loc.dependencies { _ = self.toggle_package(d.clone(), action); } } } else { profile.mod_pkgs_mut().remove(&key); for (ckey, pkg) in self.pkgs.get_all() { if let Some(loc) = pkg.loc { if loc.dependencies.contains(&key) { self.toggle_package(ckey, action)?; } } } } Ok(()) } pub fn sum_packages(&self, p: &Profile) -> String { let mut hasher = DefaultHasher::new(); for key in p.mod_pkgs().into_iter() { if let Ok(pkg) = self.pkgs.get(&key) { if let Some(loc) = &pkg.loc { key.hash(&mut hasher); loc.version.hash(&mut hasher); } } } hasher.finish().to_string() } pub fn fix(&mut self) { if let Some(p) = &mut self.profile { p.fix(&self.pkgs); } } }