use std::path::Path; use egui::TextEdit; use serde::{Deserialize, Serialize}; use crate::{ editors::tags::Tag, filesystem::{FILESYSTEM, LegacyFileSystem}, util, }; #[derive(Debug, Serialize, Deserialize, Clone)] pub struct Note { pub id: String, pub name: String, #[serde(default)] pub content: String, #[serde(default)] pub subject: String, #[serde(default)] pub tags: Vec, #[serde(skip)] #[serde(default = "default_saved")] pub saved: bool, } pub fn default_saved() -> bool { true } impl Default for Note { fn default() -> Self { Self { id: uuid::Uuid::new_v4().to_string(), name: "New Note".to_string(), subject: "".to_string(), content: "".to_string(), tags: Vec::new(), saved: false, } } } impl Note { pub fn new() -> Self { Self { id: uuid::Uuid::new_v4().to_string(), name: "New Note".to_string(), subject: "".to_string(), content: "".to_string(), tags: Vec::new(), saved: false, } } pub fn save(&mut self) -> Result<(), Box> { let id = &self.id; FILESYSTEM.write(Path::new(&format!("notes/{id}.json")), self.clone())?; self.saved = true; Ok(()) } pub fn load(id: &str) -> Result> { let mut note: Self = FILESYSTEM.read(Path::new(&format!("notes/{id}.json")))?; note.id = id.to_string(); note.saved = true; Ok(note) } pub fn ui(&mut self, ui: &mut egui::Ui) { if ui.input(|i| i.key_pressed(egui::Key::S) && i.modifiers.ctrl) { if let Err(e) = self.save() { eprintln!("Failed to save: {e}"); } } util::saved_status(ui, self.saved, &self.id, &self.name); if ui.button("Save").clicked() { if let Err(e) = self.save() { eprintln!("Failed to save: {e}"); } } let id = ui.make_persistent_id("note_name"); egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) .show_header(ui, |ui| { ui.strong("Name"); }) .body(|ui| { ui.separator(); if TextEdit::singleline(&mut self.name) .desired_width(f32::INFINITY) .frame(false) .show(ui) .response .changed() { self.saved = false; } ui.separator(); }); let id = ui.make_persistent_id("note_tags"); egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) .show_header(ui, |ui| { ui.strong("Tags"); }) .body(|ui| { ui.separator(); Tag::selector_ui(&mut self.tags, ui, Some(&mut self.saved)); ui.separator(); }); let id = ui.make_persistent_id("note_subject"); egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) .show_header(ui, |ui| { ui.strong("Subject"); }) .body(|ui| { ui.separator(); if TextEdit::singleline(&mut self.subject) .desired_width(f32::INFINITY) .frame(false) .show(ui) .response .changed() { self.saved = false; } ui.separator(); }); let id = ui.make_persistent_id("note_content"); egui::collapsing_header::CollapsingState::load_with_default_open(ui.ctx(), id, true) .show_header(ui, |ui| { ui.strong("Content"); }) .body(|ui| { ui.separator(); if TextEdit::multiline(&mut self.content) .desired_width(f32::INFINITY) .desired_rows(5) .frame(false) .show(ui) .response .changed() { self.saved = false; } ui.separator(); }); } }