diff --git a/src/fleen_app.rs b/src/fleen_app.rs index abda136..13f5b3c 100644 --- a/src/fleen_app.rs +++ b/src/fleen_app.rs @@ -1,7 +1,6 @@ -use std::ops::Index; +use std::cell::RefCell; use std::path::PathBuf; use std::process::Command; -use rfd::MessageDialogResult::No; use thiserror::Error; use crate::fleen_app::FleenError::{RootDirNonexistenceError, RootDirPopulatedError}; use crate::fleen_app::TreeEntry::{CloseDir, Dir}; @@ -11,7 +10,9 @@ pub enum FleenError { #[error("Can't reach root dir {0}")] RootDirNonexistenceError(PathBuf), #[error("Root dir is nonempty, you probably don't want to create an app here: {0}")] - RootDirPopulatedError(PathBuf) + RootDirPopulatedError(PathBuf), + #[error("Failed to open {0}: {1}")] + FileOpenError(String, String) } #[derive(Clone, Debug)] @@ -21,16 +22,15 @@ pub enum TreeEntry { CloseDir } -#[derive(Clone)] pub struct FleenApp { root: PathBuf, - files_cache: Option> + files_cache: RefCell>> } impl FleenApp { pub fn open(root: PathBuf) -> Result { match root.try_exists() { - Ok(true) => Ok(Self { root, files_cache: None }), + Ok(true) => Ok(Self { root, files_cache: RefCell::new(None) }), _ => Err(RootDirNonexistenceError(root)) } } @@ -41,7 +41,7 @@ impl FleenApp { if iter.next().is_some() { Err(RootDirPopulatedError(root)) } else { - Ok(Self { root, files_cache: None }) + Ok(Self { root, files_cache: RefCell::new(None) }) } } Err(_) => { @@ -50,14 +50,15 @@ impl FleenApp { } } - pub fn file_tree_entries(&mut self) -> impl IntoIterator { - if self.files_cache.is_none() { + // TODO: This is panicky as hell, make it return a Result + fn refresh_file_cache(&self, force: bool) { + if self.files_cache.borrow().is_none() || force { let mut entries = vec![]; fn visit_dir(dir: &PathBuf, entries: &mut Vec) { for entry in dir.read_dir().unwrap() { let path = entry.unwrap().path(); - if path.is_file() { + if path.is_file() && !path.file_name().unwrap().to_str().unwrap().starts_with('.') { entries.push(TreeEntry::File(path)) } else if path.is_dir() { entries.push(Dir(path.clone())); @@ -67,15 +68,23 @@ impl FleenApp { } } + entries.push(Dir(self.root.clone())); visit_dir(&self.root, &mut entries); - self.files_cache = Some(entries) + entries.push(CloseDir); + + self.files_cache.replace(Some(entries)); } - self.files_cache.as_ref().unwrap().clone() } - pub fn open_file_at_index(&self, index: usize) { - if let TreeEntry::File(path) = &self.files_cache.as_ref().unwrap()[index] { - Command::new("open").arg(path).spawn(); - } + pub fn file_tree_entries(&self) -> impl IntoIterator { + self.refresh_file_cache(false); + self.files_cache.borrow().clone().expect("Can't happen because we just refreshed the cache") + } + + 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()) + })?; + Ok(()) } } diff --git a/src/main.rs b/src/main.rs index c3745ab..120fb48 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,30 +1,36 @@ mod fleen_app; -use std::fmt::format; -use std::path::{Path, PathBuf}; -use eframe::egui::{Context, Id}; +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}; fn main() { let native_options = eframe::NativeOptions::default(); - eframe::run_native("Fleen", native_options, Box::new(|cc| Ok(Box::new(FleenUi::default())))); + eframe::run_native("Fleen", native_options, Box::new(|_cc| { + Ok(Box::new(FleenUi::default())) + })).expect("Error running application"); } struct FleenUi { app: Option, - error: Option + error: Option, + selected_file: Option } impl Default for FleenUi { fn default() -> Self { - Self { app: None, error: None } + Self { + app: None, + error: None, + selected_file: None + } } } impl FleenUi { - fn site_chooser(&mut self, ctx: &Context, frame: &mut Frame) { + fn site_chooser(&mut self, ctx: &Context) { egui::CentralPanel::default().show(ctx, |ui| { ui.label("No site selected!"); @@ -48,39 +54,63 @@ impl FleenUi { }); } - fn display(&mut self, ctx: &Context, frame: &mut Frame) { + fn display(&mut self, ctx: &Context) { egui::CentralPanel::default().show(ctx, |ui| { ui.horizontal(|ui| { - for action in self.tree_view(ui) { - if let Action::Activate(activate) = action { - for index in activate.selected { - self.app.as_ref().unwrap().open_file_at_index(index) + ui.vertical(|ui| { + self.tree_view(ui); + if ui.add(egui::Button::new("Open")).clicked() { + if let Some(fname) = &self.selected_file { + self.handle_error(self.app.as_ref().unwrap().open_filename(fname)) } } - } + ui.add(egui::Button::new("New page")).clicked(); + }); }) }); } - fn tree_view(&mut self, ui: &mut egui::Ui) -> Vec> { - let (_, actions) = egui_ltreeview::TreeView::new(Id::from("tree")).show(ui, |builder| { - for (id, entry) in self.app.as_mut().unwrap().file_tree_entries().into_iter().enumerate() { + fn tree_view(&mut self, ui: &mut egui::Ui) { + let tv = egui_ltreeview::TreeView::new(Id::from("tree")) + .allow_multi_selection(false) + .allow_drag_and_drop(false); + let (_, actions) = tv.show(ui, |builder| { + for entry in self.app.as_mut().unwrap().file_tree_entries().into_iter() { match entry { - TreeEntry::File(p) => builder.leaf(id, label_for_path(p)), - TreeEntry::Dir(p) => { builder.dir(id, label_for_path(p)); }, + TreeEntry::File(p) => builder.leaf(id_for_path(&p), label_for_path(&p)), + TreeEntry::Dir(p) => { builder.dir(id_for_path(&p), label_for_path(&p)); }, TreeEntry::CloseDir => builder.close_dir() } } }); - actions + + for action in actions { + match action { + Action::SetSelected(files) => { + self.selected_file = files.first().map(String::clone) + } + Action::Activate(activate) => { + for fname in activate.selected { + self.handle_error(self.app.as_ref().unwrap().open_filename(&fname)) + } + } + _ => {} + } + } + } + + fn handle_error(&mut self, result: Result<(), FleenError>) { + if let Err(e) = result { + self.error = Some(e) + } } } impl eframe::App for FleenUi { - fn update(&mut self, ctx: &Context, frame: &mut Frame) { + fn update(&mut self, ctx: &Context, _frame: &mut Frame) { match &mut self.app { - None => self.site_chooser(ctx, frame), - Some(app) => self.display(ctx, frame) + None => self.site_chooser(ctx), + Some(_) => self.display(ctx) } if let Some(err) = &self.error { @@ -95,6 +125,10 @@ impl eframe::App for FleenUi { } } -fn label_for_path(path: PathBuf) -> String { +fn label_for_path(path: &PathBuf) -> String { path.file_name().unwrap().to_string_lossy().to_string() +} + +fn id_for_path(path: &PathBuf) -> String { + path.to_string_lossy().to_string() } \ No newline at end of file