Add folder tree
This commit is contained in:
78
src/app.rs
78
src/app.rs
@ -6,7 +6,7 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use crate::{file_editor::FileEditor, preferences::Preferences, util::GuiSender};
|
||||
use crate::{file_editor::FileEditor, folder::Folder, preferences::Preferences, util::GuiSender};
|
||||
use egui::{
|
||||
Align, Button, Color32, Context, FontData, FontDefinitions, Key, Modifiers, PointerButton,
|
||||
RichText, ScrollArea, Stroke,
|
||||
@ -25,6 +25,9 @@ pub struct App {
|
||||
jobs: Jobs,
|
||||
|
||||
tabs: Vec<(TabId, Tab)>,
|
||||
|
||||
folders: Vec<Folder>,
|
||||
|
||||
open_tab_index: Option<usize>,
|
||||
|
||||
next_tab_id: TabId,
|
||||
@ -80,6 +83,7 @@ pub type TabId = usize;
|
||||
|
||||
pub enum Action {
|
||||
OpenFile(FileEditor),
|
||||
OpenFolder(Folder),
|
||||
MoveFile(TabId, PathBuf),
|
||||
CloseTab(TabId),
|
||||
// TODO
|
||||
@ -102,6 +106,7 @@ impl Default for App {
|
||||
tabs: vec![(1, Tab::File(FileEditor::new("note.md")))],
|
||||
open_tab_index: None,
|
||||
next_tab_id: 2,
|
||||
folders: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -194,6 +199,18 @@ impl App {
|
||||
|
||||
fn handle_action(&mut self, action: Action) {
|
||||
match action {
|
||||
Action::OpenFolder(new_folder) => {
|
||||
if let Some(folder) = self
|
||||
.folders
|
||||
.iter_mut()
|
||||
.find(|folder| folder.path() == new_folder.path())
|
||||
{
|
||||
*folder = new_folder;
|
||||
} else {
|
||||
self.folders.push(new_folder);
|
||||
self.folders.sort_by(|a, b| a.name().cmp(b.name()));
|
||||
}
|
||||
}
|
||||
Action::OpenFile(file_editor) => {
|
||||
self.open_tab(Tab::File(file_editor));
|
||||
}
|
||||
@ -262,7 +279,12 @@ impl eframe::App for App {
|
||||
}
|
||||
|
||||
if ui.button("Open Folder").clicked() {
|
||||
log::error!("Open Folder not implemented");
|
||||
self.jobs.start(ui.ctx(), move || {
|
||||
let path = rfd::FileDialog::new().pick_folder()?;
|
||||
let name = path.file_name()?.to_string_lossy().to_string();
|
||||
let folder = Folder::NotLoaded { name, path };
|
||||
Some(Action::OpenFolder(folder))
|
||||
});
|
||||
}
|
||||
|
||||
if ui
|
||||
@ -277,8 +299,8 @@ impl eframe::App for App {
|
||||
let can_save_file = self
|
||||
.open_tab_index
|
||||
.and_then(|i| self.tabs.get(i))
|
||||
.and_then(|(id, tab)| match tab {
|
||||
Tab::File(file_editor) => Some((*id, file_editor)),
|
||||
.map(|(id, tab)| match tab {
|
||||
Tab::File(file_editor) => (*id, file_editor),
|
||||
})
|
||||
.and_then(|(_, file_editor)| file_editor.path().zip(Some(file_editor)))
|
||||
.is_some();
|
||||
@ -287,12 +309,11 @@ impl eframe::App for App {
|
||||
self.save_active_tab(ui.ctx());
|
||||
}
|
||||
|
||||
let open_file =
|
||||
self.open_tab_index
|
||||
.and_then(|i| self.tabs.get(i))
|
||||
.and_then(|(id, tab)| match tab {
|
||||
Tab::File(file_editor) => Some((*id, file_editor)),
|
||||
});
|
||||
let open_file = self.open_tab_index.and_then(|i| self.tabs.get(i)).map(
|
||||
|(id, tab)| match tab {
|
||||
Tab::File(file_editor) => (*id, file_editor),
|
||||
},
|
||||
);
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
if ui
|
||||
@ -351,6 +372,39 @@ impl eframe::App for App {
|
||||
});
|
||||
});
|
||||
|
||||
egui::SidePanel::left("file browser")
|
||||
.resizable(true)
|
||||
.show(ctx, |ui| {
|
||||
if ui.button("refresh").clicked() {
|
||||
for folder in &mut self.folders {
|
||||
folder.unload();
|
||||
}
|
||||
}
|
||||
|
||||
ScrollArea::both().auto_shrink(false).show(ui, |ui| {
|
||||
self.folders.retain_mut(|folder| {
|
||||
let response = folder.show(ui);
|
||||
|
||||
if let Some(file_path) = response.open_file {
|
||||
let file_path = file_path.to_owned();
|
||||
self.jobs.start(ui.ctx(), move || {
|
||||
let text = fs::read_to_string(&file_path)
|
||||
.inspect_err(|e| {
|
||||
log::error!("Failed to read {file_path:?}: {e}")
|
||||
})
|
||||
.ok()?;
|
||||
|
||||
let editor = FileEditor::from_file(file_path, &text);
|
||||
Some(Action::OpenFile(editor))
|
||||
});
|
||||
}
|
||||
|
||||
// delete on right-click
|
||||
!response.clicked_by(PointerButton::Secondary)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
if let Some(Tab::File(file_editor)) = self
|
||||
.open_tab_index
|
||||
@ -389,8 +443,8 @@ impl App {
|
||||
let open_file = self
|
||||
.open_tab_index
|
||||
.and_then(|i| self.tabs.get_mut(i))
|
||||
.and_then(|(id, tab)| match tab {
|
||||
Tab::File(file_editor) => Some((*id, file_editor)),
|
||||
.map(|(id, tab)| match tab {
|
||||
Tab::File(file_editor) => (*id, file_editor),
|
||||
})
|
||||
.and_then(|(_, file_editor)| {
|
||||
file_editor
|
||||
|
||||
Reference in New Issue
Block a user