deletion
This commit is contained in:
+46
-2
@@ -1,4 +1,6 @@
|
||||
use std::cell::RefCell;
|
||||
use std::fs;
|
||||
use std::io::Error;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use thiserror::Error;
|
||||
@@ -12,7 +14,11 @@ pub enum FleenError {
|
||||
#[error("Root dir is nonempty, you probably don't want to create an app here: {0}")]
|
||||
RootDirPopulatedError(PathBuf),
|
||||
#[error("Failed to open {0}: {1}")]
|
||||
FileOpenError(String, String)
|
||||
FileIoError(String, String),
|
||||
#[error("Can't create {0} because it already exists")]
|
||||
FileExistsError(PathBuf),
|
||||
#[error("Can't create {0}: {1}")]
|
||||
FileCreateError(PathBuf, String)
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -22,6 +28,11 @@ pub enum TreeEntry {
|
||||
CloseDir
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||
pub enum FileType {
|
||||
File, Dir
|
||||
}
|
||||
|
||||
pub struct FleenApp {
|
||||
root: PathBuf,
|
||||
files_cache: RefCell<Option<Vec<TreeEntry>>>
|
||||
@@ -83,8 +94,41 @@ impl FleenApp {
|
||||
|
||||
pub fn open_filename(&self, filename: &String) -> Result<(), FleenError> {
|
||||
Command::new("open").arg(filename.clone()).spawn().map_err(|err| {
|
||||
FleenError::FileOpenError(filename.clone(), err.to_string())
|
||||
FleenError::FileIoError(filename.clone(), err.to_string())
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn create_page(&self, file_type: FileType, name: &String, parent: Option<&String>) -> Result<(), FleenError> {
|
||||
let mut target = match parent {
|
||||
Some(s) => PathBuf::from(s),
|
||||
None => self.root.clone()
|
||||
};
|
||||
target.push(name.clone());
|
||||
if target.exists() {
|
||||
return Err(FleenError::FileExistsError(target))
|
||||
}
|
||||
|
||||
match file_type {
|
||||
FileType::File => std::fs::write(target.clone(), []),
|
||||
FileType::Dir => std::fs::create_dir(target.clone())
|
||||
}.map_err(|err| FleenError::FileCreateError(target.clone(), err.to_string()))?;
|
||||
|
||||
self.refresh_file_cache(true);
|
||||
if file_type == FileType::File {
|
||||
self.open_filename(&target.to_string_lossy().to_string())?
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn delete_page(&self, path: &String) -> Result<(), FleenError> {
|
||||
let target = PathBuf::from(path);
|
||||
if target.is_dir() {
|
||||
fs::remove_dir_all(target)
|
||||
} else {
|
||||
fs::remove_file(target)
|
||||
}.map_err(|err| FleenError::FileIoError(path.clone(), err.to_string()))?;
|
||||
self.refresh_file_cache(true);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
+101
-4
@@ -4,7 +4,7 @@ use std::path::PathBuf;
|
||||
use eframe::egui::{Color32, Context, Id, Stroke};
|
||||
use eframe::{egui, Frame};
|
||||
use egui_ltreeview::Action;
|
||||
use crate::fleen_app::{FleenApp, FleenError, TreeEntry};
|
||||
use crate::fleen_app::{FileType, FleenApp, FleenError, TreeEntry};
|
||||
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions::default();
|
||||
@@ -13,10 +13,17 @@ fn main() {
|
||||
})).expect("Error running application");
|
||||
}
|
||||
|
||||
enum DialogMode {
|
||||
NewFile(String),
|
||||
ConfirmDelete(String),
|
||||
RenameFile(String)
|
||||
}
|
||||
|
||||
struct FleenUi {
|
||||
app: Option<FleenApp>,
|
||||
error: Option<FleenError>,
|
||||
selected_file: Option<String>
|
||||
selected_file: Option<String>,
|
||||
dialog_mode: Option<DialogMode>
|
||||
}
|
||||
|
||||
impl Default for FleenUi {
|
||||
@@ -24,7 +31,8 @@ impl Default for FleenUi {
|
||||
Self {
|
||||
app: None,
|
||||
error: None,
|
||||
selected_file: None
|
||||
selected_file: None,
|
||||
dialog_mode: None
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,6 +63,8 @@ impl FleenUi {
|
||||
}
|
||||
|
||||
fn display(&mut self, ctx: &Context) {
|
||||
let mut new_clicked = false;
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.vertical(|ui| {
|
||||
@@ -64,10 +74,31 @@ impl FleenUi {
|
||||
self.handle_error(self.app.as_ref().unwrap().open_filename(fname))
|
||||
}
|
||||
}
|
||||
ui.add(egui::Button::new("New page")).clicked();
|
||||
|
||||
if ui.add(egui::Button::new("New page")).clicked() {
|
||||
new_clicked = true;
|
||||
self.dialog_mode = Some(DialogMode::NewFile(String::new()));
|
||||
}
|
||||
|
||||
|
||||
let delete_btn = egui::Button::new("Delete").fill(Color32::DARK_RED);
|
||||
if let Some(selected) = &self.selected_file {
|
||||
if ui.add(delete_btn).clicked() {
|
||||
self.dialog_mode = Some(DialogMode::ConfirmDelete(selected.clone()));
|
||||
}
|
||||
} else {
|
||||
ui.add_enabled(false, delete_btn);
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
match self.dialog_mode {
|
||||
Some(DialogMode::NewFile(_)) => self.new_file_dialog(ctx, new_clicked),
|
||||
Some(DialogMode::ConfirmDelete(_)) => self.confirm_delete_dialog(ctx),
|
||||
Some(DialogMode::RenameFile(_)) => todo!(),
|
||||
None => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn tree_view(&mut self, ui: &mut egui::Ui) {
|
||||
@@ -99,6 +130,72 @@ impl FleenUi {
|
||||
}
|
||||
}
|
||||
|
||||
fn new_file_dialog(&mut self, ctx: &Context, just_clicked: bool) {
|
||||
egui::Window::new("New page").collapsible(false).resizable(false).show(ctx, |ui| {
|
||||
ui.label("Name");
|
||||
// If we press enter on the text field, it emits lost_focus. We can't just create the file based
|
||||
// on that, because it's not the only thing that causes it, though. So instead we'll just focus the
|
||||
// create file button
|
||||
//let fname = match &mut self.dialog_mode { Some(DialogMode::NewFile(s)) => s, _ => unreachable!() };
|
||||
let Some(DialogMode::NewFile(fname)) = &mut self.dialog_mode else { unreachable!() };
|
||||
let name_field = egui::TextEdit::singleline(fname);
|
||||
let resp = ui.add(name_field);
|
||||
let enter_key = resp.lost_focus();
|
||||
|
||||
// We want to focus the text field if we just opened the dialog, but egui doesn't currently
|
||||
// offer a way to do that. However, we can pass in a bool for if the button that opens the
|
||||
// dialog was just clicked, and use that to tell whether we should grab focus. It's only true
|
||||
// the exact frame that the dialog was opened, which is what we're looking for.
|
||||
if just_clicked { resp.request_focus() }
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
let mut make_thing = |file_type: FileType| {
|
||||
let Some(DialogMode::NewFile(fname)) = &self.dialog_mode else { unreachable!() };
|
||||
let app = self.app.as_ref().unwrap();
|
||||
let r = app.create_page(file_type,
|
||||
fname,
|
||||
self.selected_file.as_ref());
|
||||
if r.is_err() {
|
||||
self.handle_error(r);
|
||||
} else {
|
||||
self.dialog_mode = None; // Close the dialog, we're done
|
||||
}
|
||||
};
|
||||
|
||||
let btn = ui.button("New file");
|
||||
if enter_key { btn.request_focus() }
|
||||
if btn.clicked() { make_thing(FileType::File) }
|
||||
if ui.button("New directory").clicked() { make_thing(FileType::Dir) }
|
||||
if ui.button("Cancel").clicked() {
|
||||
self.dialog_mode = None
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn confirm_delete_dialog(&mut self, ctx: &Context) {
|
||||
let (mut del, mut cancel) = (false, false);
|
||||
let Some(DialogMode::ConfirmDelete(fname)) = &self.dialog_mode else { unreachable!() };
|
||||
egui::Window::new("Are you sure?").collapsible(false).resizable(false).show(ctx, |ui| {
|
||||
let file = label_for_path(&PathBuf::from(fname));
|
||||
ui.heading(format!("Really delete {}?", file));
|
||||
ui.horizontal(|ui| {
|
||||
let btn = egui::Button::new("Yep, I'm sure").fill(Color32::DARK_RED);
|
||||
del = ui.add(btn).clicked();
|
||||
cancel = ui.button("Cancel").clicked();
|
||||
})
|
||||
});
|
||||
|
||||
if del {
|
||||
let r = self.app.as_ref().unwrap().delete_page(&fname.clone());
|
||||
self.dialog_mode = None;
|
||||
if r.is_err() { self.handle_error(r); }
|
||||
self.selected_file = None;
|
||||
} else if cancel {
|
||||
self.dialog_mode = None
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_error(&mut self, result: Result<(), FleenError>) {
|
||||
if let Err(e) = result {
|
||||
self.error = Some(e)
|
||||
|
||||
Reference in New Issue
Block a user