ced/src/app/state/lifecycle.rs
2025-07-23 12:47:26 -04:00

134 lines
4.7 KiB
Rust

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)
.map(|tab| tab.title.to_owned())
.collect()
}
pub fn request_quit(&mut self, ctx: &egui::Context) {
if self.has_unsaved_changes() && !self.state_cache {
self.pending_unsaved_action = Some(UnsavedAction::Quit);
} else {
self.clean_quit_requested = true;
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
ctx.send_viewport_cmd(egui::ViewportCommand::Close);
}
}
pub fn force_quit(&mut self, ctx: &egui::Context) {
self.force_quit_confirmed = true;
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
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 {
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(),
)
}
UnsavedAction::CloseTab(tab_index) => {
let file_name = self
.tabs
.get(*tab_index)
.map_or_else(|| "unknown file".to_string(), |tab| tab.title.to_owned());
(
vec![file_name],
"Unsaved Changes".to_string(),
"This file has unsaved changes:".to_string(),
"Close Without Saving".to_string(),
action.to_owned(),
)
}
}
} else {
return;
};
let visuals = &ctx.style().visuals;
let error_color = visuals.error_fg_color;
egui::Window::new(title)
.collapsible(false)
.resizable(false)
.anchor(egui::Align2::CENTER_CENTER, egui::Vec2::ZERO)
.show(ctx, |ui| {
ui.vertical_centered(|ui| {
ui.add_space(8.0);
ui.label(egui::RichText::new(&confirmation_text).size(14.0));
ui.add_space(4.0);
for file in &files_to_list {
ui.label(egui::RichText::new(file).size(12.0).color(error_color));
}
ui.add_space(12.0);
ui.horizontal(|ui| {
if ui.button("Cancel").clicked() {
cancel_action = true;
}
ui.add_space(8.0);
if ui
.button(egui::RichText::new(&button_text).color(error_color))
.clicked()
{
close_action_now = Some(action.to_owned());
}
});
ui.add_space(8.0);
});
});
if cancel_action {
self.pending_unsaved_action = None;
}
if let Some(action) = close_action_now {
match action {
UnsavedAction::Quit => {
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
self.force_quit(ctx);
}
UnsavedAction::CloseTab(tab_index) => {
self.close_tab(tab_index);
if let Err(e) = self.save_state_cache() {
eprintln!("Failed to save state cache: {e}");
}
}
}
self.pending_unsaved_action = None;
}
}
}