Skip to content

Commit

Permalink
feat: deleting instances
Browse files Browse the repository at this point in the history
  • Loading branch information
Umatriz committed Aug 18, 2024
1 parent 3c065af commit dc96d79
Show file tree
Hide file tree
Showing 9 changed files with 234 additions and 196 deletions.
44 changes: 40 additions & 4 deletions crates/client/src/collections.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use nomi_modding::modrinth::{

use crate::{
errors_pool::ErrorPoolExt,
toasts,
views::{InstancesConfig, SimpleDependency},
};

Expand Down Expand Up @@ -102,18 +103,53 @@ impl<'c> TasksCollection<'c> for GameDownloadingCollection {
pub struct GameDeletionCollection;

impl<'c> TasksCollection<'c> for GameDeletionCollection {
type Context = ();
type Context = &'c InstancesConfig;

type Target = ();
type Target = InstanceProfileId;

type Executor = executors::Linear;

fn name() -> &'static str {
"Game deletion collection"
}

fn handle(_context: Self::Context) -> Handler<'c, Self::Target> {
Handler::new(|()| ())
fn handle(context: Self::Context) -> Handler<'c, Self::Target> {
Handler::new(|id: InstanceProfileId| {
if let Some(instance) = context.find_instance(id.instance()) {
instance.write().remove_profile(id);
if context.update_instance_config(id.instance()).report_error().is_some() {
toasts::add(|toasts| toasts.success("Successfully removed the profile"))
}
}
})
}
}

pub struct InstanceDeletionCollection;

impl<'c> TasksCollection<'c> for InstanceDeletionCollection {
type Context = &'c mut InstancesConfig;

type Target = Option<usize>;

type Executor = executors::Linear;

fn name() -> &'static str {
"Instance deletion collection"
}

fn handle(context: Self::Context) -> Handler<'c, Self::Target> {
Handler::new(|id: Option<usize>| {
let Some(id) = id else {
return;
};

if context.remove_instance(id).is_none() {
return;
}

toasts::add(|toasts| toasts.success("Successfully removed the instance"))
})
}
}

Expand Down
5 changes: 3 additions & 2 deletions crates/client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use egui_notify::Toasts;
use open_directory::open_directory_native;
use std::path::Path;
use subscriber::EguiLayer;
use ui_ext::{UiExt, TOASTS_ID};
use ui_ext::UiExt;
use views::{add_tab_menu::AddTab, AddProfileMenu, CreateInstanceMenu, View};

use errors_pool::{ErrorPoolExt, ERRORS_POOL};
Expand Down Expand Up @@ -135,7 +135,8 @@ impl eframe::App for MyTabs {
.manager
.add_collection::<collections::AssetsCollection>(())
.add_collection::<collections::FabricDataCollection>(&mut self.context.states.add_profile_menu.fabric_versions)
.add_collection::<collections::GameDeletionCollection>(())
.add_collection::<collections::GameDeletionCollection>(&self.context.states.instances.instances)
.add_collection::<collections::InstanceDeletionCollection>(&mut self.context.states.instances.instances)
.add_collection::<collections::GameDownloadingCollection>(&self.context.states.instances.instances)
.add_collection::<collections::JavaCollection>(())
.add_collection::<collections::ProjectCollection>(&mut self.context.states.mod_manager.current_project)
Expand Down
7 changes: 4 additions & 3 deletions crates/client/src/ui_ext.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use eframe::egui::{self, popup_below_widget, Id, PopupCloseBehavior, Response, RichText, Ui, WidgetText};
use egui_notify::{Toast, Toasts};

pub const TOASTS_ID: &str = "global_egui_notify_toasts";

pub trait UiExt {
fn ui(&self) -> &Ui;
Expand All @@ -27,6 +24,10 @@ pub trait UiExt {
ui.label(RichText::new(format!("⚠ {}", text.into())).color(ui.visuals().warn_fg_color))
}

fn warn_irreversible_action(&mut self) -> Response {
self.warn_label_with_icon_before("This action is irreversible.")
}

fn markdown_ui(&mut self, id: egui::Id, markdown: &str) {
use parking_lot::Mutex;
use std::sync::Arc;
Expand Down
167 changes: 79 additions & 88 deletions crates/client/src/views/profiles.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
use std::{collections::HashSet, path::PathBuf, sync::Arc};

use anyhow::bail;
use eframe::egui::{self, Align2, RichText, TextWrapMode, Ui};
use eframe::egui::{self, Align2, Id, RichText, TextWrapMode, Ui};
use egui_extras::{Column, TableBuilder};
use egui_task_manager::{Caller, Task, TaskManager};
use itertools::Itertools;
use nomi_core::{
configs::profile::{ProfileState, VersionProfile},
fs::write_toml_config_sync,
game_paths::GamePaths,
instance::{launch::arguments::UserData, load_instances, Instance, InstanceProfileId, ProfilePayload},
instance::{delete_profile, launch::arguments::UserData, load_instances, Instance, InstanceProfileId, ProfilePayload},
repository::{launcher_manifest::LauncherManifest, username::Username},
};
use parking_lot::RwLock;
Expand All @@ -18,9 +18,11 @@ use tracing::error;

use crate::{
cache::GLOBAL_CACHE,
collections::{AssetsCollection, GameDownloadingCollection, GameRunnerCollection},
collections::{AssetsCollection, GameDeletionCollection, GameDownloadingCollection, GameRunnerCollection, InstanceDeletionCollection},
download::{task_assets, task_download_version},
errors_pool::ErrorPoolExt,
toasts,
ui_ext::UiExt,
TabKind,
};

Expand Down Expand Up @@ -94,6 +96,13 @@ impl InstancesConfig {
self.instances.iter().find(|p| p.read().id() == id).cloned()
}

pub fn remove_instance(&mut self, id: usize) -> Option<Arc<RwLock<Instance>>> {
self.instances
.iter()
.position(|i| i.read().id() == id)
.map(|idx| self.instances.remove(idx))
}

pub fn load() -> Self {
Self {
instances: load_instances()
Expand Down Expand Up @@ -154,7 +163,6 @@ impl InstancesConfig {
}

impl Instances<'_> {
// TODO: It requires profile to be loaded
fn profile_action_ui(&mut self, ui: &mut Ui, profile_payload: &ProfilePayload) {
let button = if profile_payload.is_downloaded {
ui.add_enabled(self.is_allowed_to_take_action, egui::Button::new("Launch"))
Expand Down Expand Up @@ -282,15 +290,42 @@ impl Instances<'_> {
});

row.col(|ui| {
ui.button("TODO: Delete");
ui.button_with_confirm_popup(Id::new("confirm_profile_deletion").with(profile.id), "Delete", |ui| {
ui.set_width(200.0);
ui.label("Are you sure you want to delete this profile?");
ui.warn_irreversible_action();

ui.horizontal(|ui| {
let yes_button = ui.button("Yes");
let no_button = ui.button("No");

if yes_button.clicked() {
let id = profile.id;
if let Some(profile) = self.profiles_state.instances.find_profile(id) {
let profile = profile.read();
let game_version = profile.profile.version().to_owned();
let task = Task::new(
"Deleting profile",
Caller::standard(async move {
delete_profile(GamePaths::from_id(id), &game_version).await;
id
}),
);

self.manager.push_task::<GameDeletionCollection>(task)
} else {
toasts::add(|toasts| toasts.warning("Cannot find profile to delete"));
}
}

if yes_button.clicked() || no_button.clicked() {
ui.memory_mut(|mem| mem.close_popup())
}
});
});
});
});
}

// is_deleting.drain(..).for_each(|index| {
// self.profiles_state.instances.instances.remove(index);
// self.profiles_state.instances.update_config_sync().report_error();
// });
});
}
}
Expand All @@ -303,87 +338,43 @@ impl View for Instances<'_> {
for instance in iter {
let instance = instance.read();
ui.group(|ui| {
ui.label(RichText::new(instance.name()).strong());
egui::CollapsingHeader::new("Profiles")
.id_source(egui::Id::new(instance.id()).with("__profiles_list"))
.show(ui, |ui| {
let id = ui.make_persistent_id("instance_details").with(instance.id());
egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, false)
.show_header(ui, |ui| {
ui.label(RichText::new(instance.name()).strong());
ui.button("Launch");
})
.body(|ui| {
ui.button_with_confirm_popup(Id::new("confirm_instance_deletion").with(instance.id()), "Delete", |ui| {
ui.set_width(200.0);
ui.label("Are you sure you want to delete this instance?");
ui.warn_irreversible_action();

ui.horizontal(|ui| {
let yes_button = ui.button("Yes");
let no_button = ui.button("No");

if yes_button.clicked() {
let path = instance.path();
let id = instance.id();
let task = Task::new(
"Deleting the instance",
Caller::standard(async move { tokio::fs::remove_dir_all(path).await.report_error().map(|()| id) }),
);
self.manager.push_task::<InstanceDeletionCollection>(task);
}

if yes_button.clicked() || no_button.clicked() {
ui.memory_mut(|mem| mem.close_popup())
}
});
});

ui.heading("Profiles");

self.show_profiles_for_instance(ui, instance.profiles(), self.is_allowed_to_take_action)
});
});
}
}
}

fn delete_profile_ui() {
// if let ProfileState::Downloaded(instance) = &profile.profile.state {
// let popup_id = ui.make_persistent_id("delete_popup_id");
// let button = ui
// .add_enabled(is_allowed_to_take_action, Button::new("Delete"))
// .on_hover_text("It will delete the profile and it's data");

// if button.clicked() {
// ui.memory_mut(|mem| mem.toggle_popup(popup_id));
// }

// popup_below_widget(ui, popup_id, &button, PopupCloseBehavior::CloseOnClickOutside, |ui| {
// ui.set_min_width(150.0);

// let delete_client_id = Id::new("delete_client");
// let delete_libraries_id = Id::new("delete_libraries");
// let delete_assets_id = Id::new("delete_assets");
// let delete_mods_id = Id::new("delete_mods");

// let mut make_checkbox = |text: &str, id, default: bool| {
// let mut state = ui.data_mut(|map| *map.get_temp_mut_or_insert_with(id, move || default));
// ui.checkbox(&mut state, text);
// ui.data_mut(|map| map.insert_temp(id, state));
// };

// make_checkbox("Delete profile's client", delete_client_id, true);
// make_checkbox("Delete profile's libraries", delete_libraries_id, false);
// if profile.profile.loader().is_fabric() {
// make_checkbox("Delete profile's mods", delete_mods_id, true);
// }
// make_checkbox("Delete profile's assets", delete_assets_id, false);

// ui.label("Are you sure you want to delete this profile and it's data?");
// ui.horizontal(|ui| {
// ui.warn_icon_with_hover_text("Deleting profile's assets and libraries might break other profiles.");
// if ui.button("Yes").clicked() {
// is_deleting.push(index);

// let version = &instance.settings.version;

// let checkbox_data = |id| ui.data(|data| data.get_temp(id)).unwrap_or_default();

// let delete_client = checkbox_data(delete_client_id);
// let delete_libraries = checkbox_data(delete_libraries_id);
// let delete_assets = checkbox_data(delete_assets_id);
// let delete_mods = checkbox_data(delete_mods_id);

// let profile_id = profile.profile.id;

// let instance = instance.clone();
// let caller = Caller::standard(async move {
// let path = Path::new(DOT_NOMI_MODS_STASH_DIR).join(format!("{}", profile_id));
// if delete_mods && path.exists() {
// tokio::fs::remove_dir_all(path).await.report_error();
// }
// instance.delete(delete_client, delete_libraries, delete_assets).await.report_error();
// });

// let task = Task::new(format!("Deleting the game's files ({})", version), caller);

// self.manager.push_task::<GameDeletionCollection>(task);

// self.tabs_state.remove_profile_related_tabs(&profile);

// ui.memory_mut(|mem| mem.close_popup());
// }
// if ui.button("No").clicked() {
// ui.memory_mut(|mem| mem.close_popup());
// }
// });
// });
// }
}
Loading

0 comments on commit dc96d79

Please sign in to comment.