feat: checkbox to delete profile dirs along with profile
Some checks failed
/ cargo-fmtcheck (push) Has been cancelled
/ cargo-clippy (push) Has been cancelled
/ cargo-test (push) Has been cancelled
/ appimage (push) Has been cancelled

This commit is contained in:
Gabriele Musco 2025-04-29 14:22:27 +02:00
commit c794037377
3 changed files with 55 additions and 7 deletions

View file

@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize};
use std::{ use std::{
collections::HashMap, collections::HashMap,
fmt::Display, fmt::Display,
fs::File, fs::{remove_dir_all, File},
io::BufReader, io::BufReader,
path::{Path, PathBuf}, path::{Path, PathBuf},
slice::Iter, slice::Iter,
@ -450,6 +450,29 @@ impl Profile {
get_data_dir().join("prefixes").join(uuid) get_data_dir().join("prefixes").join(uuid)
} }
/// deletes files and folders associated to this profile (mostly repo clones)
pub fn delete_files(&self) -> Vec<std::io::Result<()>> {
[
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 { pub fn xr_runtime_json_env_var(&self) -> String {
format!( format!(
"XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"", "XR_RUNTIME_JSON=\"{prefix}/share/openxr/1/openxr_{runtime}.json\"",

View file

@ -113,7 +113,8 @@ pub enum Msg {
StartWithDebug, StartWithDebug,
RestartXRService, RestartXRService,
ProfileSelected(Profile), ProfileSelected(Profile),
DeleteProfile, /// bool param: delete files
DeleteProfile(bool),
SaveProfile(Profile), SaveProfile(Profile),
RunSetCap, RunSetCap,
OpenLibsurviveSetup, OpenLibsurviveSetup,
@ -658,9 +659,16 @@ impl AsyncComponent for App {
w.stop(); w.stop();
} }
} }
Msg::DeleteProfile => { Msg::DeleteProfile(delete_files) => {
let todel = self.get_selected_profile(); let todel = self.get_selected_profile();
if todel.editable { 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.user_profiles.retain(|p| p.uuid != todel.uuid);
self.config.save(); self.config.save();
self.profiles = self.config.profiles(); self.profiles = self.config.profiles();
@ -1007,7 +1015,7 @@ impl AsyncComponent for App {
MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService, MainViewOutMsg::DoStartStopXRService => Msg::DoStartStopXRService,
MainViewOutMsg::RestartXRService => Msg::RestartXRService, MainViewOutMsg::RestartXRService => Msg::RestartXRService,
MainViewOutMsg::ProfileSelected(uuid) => Msg::ProfileSelected(uuid), 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::SaveProfile(p) => Msg::SaveProfile(p),
MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup, MainViewOutMsg::OpenLibsurviveSetup => Msg::OpenLibsurviveSetup,
MainViewOutMsg::BuildProfile(clean) => Msg::BuildProfile(clean), MainViewOutMsg::BuildProfile(clean) => Msg::BuildProfile(clean),

View file

@ -112,7 +112,8 @@ pub enum MainViewOutMsg {
DoStartStopXRService, DoStartStopXRService,
RestartXRService, RestartXRService,
ProfileSelected(Profile), ProfileSelected(Profile),
DeleteProfile, /// bool param: delete files
DeleteProfile(bool),
SaveProfile(Profile), SaveProfile(Profile),
OpenLibsurviveSetup, OpenLibsurviveSetup,
/// params: clean /// params: clean
@ -931,6 +932,13 @@ impl AsyncComponent for MainView {
let profile_delete_confirm_dialog = adw::AlertDialog::builder() let profile_delete_confirm_dialog = adw::AlertDialog::builder()
.heading("Are you sure you want to delete this profile?") .heading("Are you sure you want to delete this profile?")
.extra_child(
&gtk::CheckButton::builder()
.label("Delete all files and folders associated with profile")
.halign(gtk::Align::Center)
.hexpand(true)
.build(),
)
.build(); .build();
profile_delete_confirm_dialog.add_response("no", "_No"); profile_delete_confirm_dialog.add_response("no", "_No");
profile_delete_confirm_dialog.add_response("yes", "_Yes"); profile_delete_confirm_dialog.add_response("yes", "_Yes");
@ -942,10 +950,19 @@ impl AsyncComponent for MainView {
clone!( clone!(
#[strong] #[strong]
sender, sender,
move |_, res| { move |dialog, res| {
let delete_files_checkbox = dialog
.extra_child()
.and_then(|child| child.downcast::<gtk::CheckButton>().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" { if res == "yes" {
sender sender
.output(Self::Output::DeleteProfile) .output(Self::Output::DeleteProfile(delete_files))
.expect("Sender output failed"); .expect("Sender output failed");
} }
} }