From c794037377bbddc014ce4a58b3662038fc6b056f Mon Sep 17 00:00:00 2001 From: Gabriele Musco Date: Tue, 29 Apr 2025 14:22:27 +0200 Subject: [PATCH] feat: checkbox to delete profile dirs along with profile --- src/profile.rs | 25 ++++++++++++++++++++++++- src/ui/app.rs | 14 +++++++++++--- src/ui/main_view.rs | 23 ++++++++++++++++++++--- 3 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/profile.rs b/src/profile.rs index 7433de9..a3344df 100644 --- a/src/profile.rs +++ b/src/profile.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, fmt::Display, - fs::File, + fs::{remove_dir_all, File}, io::BufReader, path::{Path, PathBuf}, slice::Iter, @@ -450,6 +450,29 @@ impl Profile { get_data_dir().join("prefixes").join(uuid) } + /// deletes files and folders associated to this profile (mostly repo clones) + pub fn delete_files(&self) -> Vec> { + [ + Some(&self.xrservice_path), + Some(&self.ovr_comp.path), + self.features.libsurvive.path.as_ref(), + self.features.basalt.path.as_ref(), + self.features.openhmd.path.as_ref(), + ] + .iter() + .map(|dir| match dir { + Some(dir) => { + if dir.try_exists().unwrap_or_default() { + remove_dir_all(dir) + } else { + Ok(()) + } + } + None => Ok(()), + }) + .collect() + } + pub fn xr_runtime_json_env_var(&self) -> String { format!( "XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"", diff --git a/src/ui/app.rs b/src/ui/app.rs index 9910d2d..c4f3b10 100644 --- a/src/ui/app.rs +++ b/src/ui/app.rs @@ -113,7 +113,8 @@ pub enum Msg { StartWithDebug, RestartXRService, ProfileSelected(Profile), - DeleteProfile, + /// bool param: delete files + DeleteProfile(bool), SaveProfile(Profile), RunSetCap, OpenLibsurviveSetup, @@ -658,9 +659,16 @@ impl AsyncComponent for App { w.stop(); } } - Msg::DeleteProfile => { + Msg::DeleteProfile(delete_files) => { let todel = self.get_selected_profile(); if todel.editable { + if delete_files { + for res in todel.delete_files() { + if let Err(e) = res { + error!("Error deleting profile directory: {e}"); + } + } + } self.config.user_profiles.retain(|p| p.uuid != todel.uuid); self.config.save(); self.profiles = self.config.profiles(); @@ -1007,7 +1015,7 @@ impl AsyncComponent for App { MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService, MainViewOutMsg::RestartXRService => Msg::RestartXRService, MainViewOutMsg::ProfileSelected(uuid) => Msg::ProfileSelected(uuid), - MainViewOutMsg::DeleteProfile => Msg::DeleteProfile, + MainViewOutMsg::DeleteProfile(delete_files) => Msg::DeleteProfile(delete_files), MainViewOutMsg::SaveProfile(p) => Msg::SaveProfile(p), MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup, MainViewOutMsg::BuildProfile(clean) => Msg::BuildProfile(clean), diff --git a/src/ui/main_view.rs b/src/ui/main_view.rs index ce5f7a6..09cd408 100644 --- a/src/ui/main_view.rs +++ b/src/ui/main_view.rs @@ -112,7 +112,8 @@ pub enum MainViewOutMsg { DoStartStopXRService, RestartXRService, ProfileSelected(Profile), - DeleteProfile, + /// bool param: delete files + DeleteProfile(bool), SaveProfile(Profile), OpenLibsurviveSetup, /// params: clean @@ -931,6 +932,13 @@ impl AsyncComponent for MainView { let profile_delete_confirm_dialog = adw::AlertDialog::builder() .heading("Are you sure you want to delete this profile?") + .extra_child( + >k::CheckButton::builder() + .label("Delete all files and folders associated with profile") + .halign(gtk::Align::Center) + .hexpand(true) + .build(), + ) .build(); profile_delete_confirm_dialog.add_response("no", "_No"); profile_delete_confirm_dialog.add_response("yes", "_Yes"); @@ -942,10 +950,19 @@ impl AsyncComponent for MainView { clone!( #[strong] sender, - move |_, res| { + move |dialog, res| { + let delete_files_checkbox = dialog + .extra_child() + .and_then(|child| child.downcast::().ok()); + let delete_files = delete_files_checkbox + .as_ref() + .is_some_and(|c| c.is_active()); + if let Some(check) = delete_files_checkbox { + check.set_active(false); + } if res == "yes" { sender - .output(Self::Output::DeleteProfile) + .output(Self::Output::DeleteProfile(delete_files)) .expect("Sender output failed"); } }