ced/src/app/state/lifecycle.rs

134 lines
4.7 KiB
Rust
Raw Normal View History

2025-07-05 14:42:45 -04:00
use super::editor::{TextEditor, UnsavedAction};
use eframe::egui;
impl TextEditor {
pub fn has_unsaved_changes(&self) -> bool {
self.tabs.iter().any(|tab| tab.is_modified)
}
pub fn get_unsaved_files(&self) -> Vec<String> {
self.tabs
.iter()
.filter(|tab| tab.is_modified)
2025-07-16 17:20:09 -04:00
.map(|tab| tab.title.to_owned())
2025-07-05 14:42:45 -04:00
.collect()
}
pub fn request_quit(&mut self, ctx: &egui::Context) {
2025-07-23 12:47:26 -04:00
if self.has_unsaved_changes() && !self.state_cache {
2025-07-05 14:42:45 -04:00
self.pending_unsaved_action = Some(UnsavedAction::Quit);
} else {
self.clean_quit_requested = true;
2025-07-23 12:47:26 -04:00
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
2025-07-05 14:42:45 -04:00
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
}
pub fn force_quit(&mut self, ctx: &egui::Context) {
self.force_quit_confirmed = true;
2025-07-23 12:47:26 -04:00
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
2025-07-05 14:42:45 -04:00
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
pub(crate) fn show_unsaved_changes_dialog(&mut self, ctx: &egui::Context) {
let mut close_action_now = None;
let mut cancel_action = false;
let (files_to_list, title, confirmation_text, button_text, action) =
if let Some(action) = &self.pending_unsaved_action {
match action {
2025-07-16 17:34:11 -04:00
UnsavedAction::Quit => {
let files = self.get_unsaved_files();
let file_plural = if files.len() > 1 { "s" } else { "" };
(
files,
"Unsaved Changes".to_string(),
format!("File{file_plural} with unsaved changes:"),
"Quit Without Saving".to_string(),
action.to_owned(),
)
}
2025-07-05 14:42:45 -04:00
UnsavedAction::CloseTab(tab_index) => {
let file_name = self
.tabs
.get(*tab_index)
2025-07-16 17:20:09 -04:00
.map_or_else(|| "unknown file".to_string(), |tab| tab.title.to_owned());
2025-07-05 14:42:45 -04:00
(
vec![file_name],
"Unsaved Changes".to_string(),
2025-07-16 17:34:11 -04:00
"This file has unsaved changes:".to_string(),
2025-07-05 14:42:45 -04:00
"Close Without Saving".to_string(),
2025-07-16 17:20:09 -04:00
action.to_owned(),
2025-07-05 14:42:45 -04:00
)
}
}
} else {
return;
2025-07-05 14:42:45 -04:00
};
let visuals = &ctx.style().visuals;
2025-07-23 12:47:26 -04:00
let error_color = visuals.error_fg_color;
2025-07-05 14:42:45 -04:00
egui::Window::new(title)
.collapsible(false)
.resizable(false)
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
.show(ctx, |ui| {
2025-07-23 12:47:26 -04:00
ui.vertical_centered(|ui| {
2025-07-05 14:42:45 -04:00
ui.add_space(8.0);
2025-07-23 12:47:26 -04:00
ui.label(egui::RichText::new(&confirmation_text).size(14.0));
ui.add_space(4.0);
2025-07-05 14:42:45 -04:00
for file in &files_to_list {
2025-07-23 12:47:26 -04:00
ui.label(egui::RichText::new(file).size(12.0).color(error_color));
2025-07-05 14:42:45 -04:00
}
ui.add_space(12.0);
2025-07-23 12:47:26 -04:00
ui.horizontal(|ui| {
if ui.button("Cancel").clicked() {
2025-07-05 14:42:45 -04:00
cancel_action = true;
}
2025-07-23 12:47:26 -04:00
ui.add_space(8.0);
2025-07-05 14:42:45 -04:00
2025-07-23 12:47:26 -04:00
if ui
.button(egui::RichText::new(&button_text).color(error_color))
.clicked()
{
close_action_now = Some(action.to_owned());
2025-07-05 14:42:45 -04:00
}
});
2025-07-23 12:47:26 -04:00
ui.add_space(8.0);
2025-07-05 14:42:45 -04:00
});
});
if cancel_action {
self.pending_unsaved_action = None;
}
if let Some(action) = close_action_now {
match action {
2025-07-23 12:47:26 -04:00
UnsavedAction::Quit => {
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
self.force_quit(ctx);
}
2025-07-05 14:42:45 -04:00
UnsavedAction::CloseTab(tab_index) => {
self.close_tab(tab_index);
2025-07-23 12:47:26 -04:00
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
2025-07-05 14:42:45 -04:00
}
}
self.pending_unsaved_action = None;
}
}
}