From: Olaf Wintermann Date: Mon, 20 Jul 2026 17:38:17 +0000 (+0200) Subject: implement check for external note content changes, when a note is attached X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=f22035ce3530bf6676e870c8c353f6fe0be9ebe0;p=note.git implement check for external note content changes, when a note is attached --- diff --git a/Cargo.lock b/Cargo.lock index d63a028..9c387f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1577,6 +1577,7 @@ version = "0.1.0" dependencies = [ "backend", "entity", + "notify", "sea-orm", "tokio", "ui-rs", diff --git a/application/backend/src/backend.rs b/application/backend/src/backend.rs index 6a3e800..4b81ae6 100644 --- a/application/backend/src/backend.rs +++ b/application/backend/src/backend.rs @@ -309,9 +309,9 @@ impl Backend { }); // start fs notification - let fs_btx = broadcast_tx.clone(); + let notify_backend = backend_clone.clone(); let cmd = Box::pin(async move { - let ret = fs_notify(nrx, fs_btx).await; + let ret = fs_notify(nrx, notify_backend).await; if let Err(e) = ret { println!("fs_noitify task failed {:?}", e); } @@ -328,16 +328,20 @@ impl Backend { (backend_handle, join) } -} -impl BackendHandle { pub fn send_broadcast(&self, msg: BroadcastMessage) -> Result> { - let result = self.btx.send(msg); - if let Some(notify) = &self.backend.broadcast_notify.as_ref() { + let result = self.broadcast.send(msg); + if let Some(notify) = &self.broadcast_notify.as_ref() { notify(); } result } +} + +impl BackendHandle { + pub fn send_broadcast(&self, msg: BroadcastMessage) -> Result> { + self.backend.send_broadcast(msg) + } /// Reloads the notebook structure/collections. On success, it sends a NotebookStructureUpdate /// to the broadcast channel. diff --git a/application/backend/src/notify.rs b/application/backend/src/notify.rs index c2297b5..2245399 100644 --- a/application/backend/src/notify.rs +++ b/application/backend/src/notify.rs @@ -29,22 +29,23 @@ use std::collections::HashMap; use std::path::{Path, PathBuf}; use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher}; use tokio::sync::mpsc::{*}; -use crate::backend::BroadcastMessage; +use crate::backend::{Backend, BroadcastMessage}; use std::collections::hash_map::Entry; +use std::sync::Arc; pub enum FSWatch { Add(PathBuf), Remove(PathBuf), } -pub async fn fs_notify(mut rx: UnboundedReceiver, btx: tokio::sync::broadcast::Sender) -> notify::Result<()> { +pub async fn fs_notify(mut rx: UnboundedReceiver, backend: Arc) -> notify::Result<()> { let mut path_map = HashMap::::new(); let mut watcher = RecommendedWatcher::new( move |res: Result| { match res { Ok(event) => { - _ = btx.send(BroadcastMessage::Notify(event)); + _ = backend.send_broadcast(BroadcastMessage::Notify(event)); }, Err(e) => { println!("Notify Error: {:?}", e); diff --git a/application/note/Cargo.toml b/application/note/Cargo.toml index c95d867..4a7e28f 100644 --- a/application/note/Cargo.toml +++ b/application/note/Cargo.toml @@ -9,3 +9,4 @@ entity = { path = "../../entity" } ui-rs = { path = "../../ui-rs" } tokio = { version = "1.52.1", features = ["rt-multi-thread"] } sea-orm = { version = "2.0.0-rc", features = [ "sqlx-sqlite", "sqlx-postgres", "runtime-tokio-native-tls", "macros" ] } +notify = "9.0.0-rc.4" diff --git a/application/note/src/main.rs b/application/note/src/main.rs index aed51c2..7c6d926 100644 --- a/application/note/src/main.rs +++ b/application/note/src/main.rs @@ -176,6 +176,7 @@ pub enum AppStates { Null = 0, NoteEnableNew, NoteShowInfo, + NoteShowExtModInfo, NoteMaximized } diff --git a/application/note/src/note.rs b/application/note/src/note.rs index d1c627e..dee8194 100644 --- a/application/note/src/note.rs +++ b/application/note/src/note.rs @@ -38,6 +38,7 @@ use ui_rs::{action, doc_cast, ui_actions, UiModel}; use ui_rs::ui::*; use crate::AppStates; use crate::window::NoteTypeTabView; +use notify::{Event}; static TMP_ID: AtomicU64 = AtomicU64::new(1); @@ -67,6 +68,7 @@ pub struct Note { title_end: i32, modified: bool, + is_saving: bool, pub local_path: Option, pub local_lastmodified: Option, @@ -100,6 +102,7 @@ impl Note { title_start: -1, title_end: -1, modified: false, + is_saving: false, local_path: None, local_lastmodified: None, @@ -164,7 +167,7 @@ impl Note { return; }; - if let Some(path) = &self.local_path && let Some(lastmodified) = self.local_lastmodified { + if let Some(path) = &self.local_path && self.local_lastmodified.is_some() { let proxy = doc.doc_proxy(); self.backend.get_file_metadata(path.as_path(), |result| { proxy.call_mainthread(|_doc, note| { @@ -265,6 +268,34 @@ impl Note { } } + #[action(Event)] + pub fn filesystem_notify(&mut self, _event: &ActionEvent, event: &Event) { + // for now we only care about modify events + if !event.kind.is_modify() { + return; + } + + // ignore when the note is currently saving + if self.is_saving { + return; + } + + let Some(local_path) = &self.local_path else { + return; + }; + + // event is not for any file relevant for this note + if !event.paths.contains(local_path) { + return; + } + + println!("note file modified"); + let Some(doc) = self.doc.get_doc() else { + return; + }; + doc.ctx.set_state(AppStates::NoteShowExtModInfo as i32); + } + #[action] pub fn save(&mut self, _event: &ActionEvent) { self.save_note(); @@ -351,6 +382,20 @@ impl Note { obj.splitview_set_visible(0, event.intval == 0); doc.ctx.set_state(AppStates::NoteMaximized as i32); } + + #[action] + pub fn note_reload(&mut self, _event: &mut ActionEvent) { + self.load_content(); + self.note_extmod_close(_event); + } + + #[action] + pub fn note_extmod_close(&mut self, _event: &mut ActionEvent) { + let Some(doc) = self.doc.get_doc() else { + return; + }; + doc.ctx.unset_state(AppStates::NoteShowExtModInfo as i32); + } } impl NoteViewModel for Note { @@ -391,9 +436,12 @@ impl NoteViewModel for Note { content: Set(content), }; + self.is_saving = true; + let proxy = doc.doc_proxy(); self.backend.save_note(self.notebook_instance_id, self.id.clone(), note, Some(notecontent), |result|{ proxy.call_mainthread(move |doc, note|{ + note.is_saving = false; match result { SaveNoteResult::Ok(ret) => { note.id = NoteId::Id(ret.model.note_id); diff --git a/application/note/src/notebook.rs b/application/note/src/notebook.rs index 2fd1b3d..b9b969a 100644 --- a/application/note/src/notebook.rs +++ b/application/note/src/notebook.rs @@ -346,11 +346,14 @@ impl Notebook { } }, BroadcastMessage::Notify(event) => { - println!("fs notify event"); + if let Some(note) = &self.selected_note { + let arg: Box = Box::new(event); + note.doc.ctx.call_action_with_parameter("filesystem_notify", arg); + } }, _ => { - }, + } } } } diff --git a/application/note/src/window.rs b/application/note/src/window.rs index 17af135..6c48d81 100644 --- a/application/note/src/window.rs +++ b/application/note/src/window.rs @@ -256,6 +256,24 @@ pub fn create_window(app: &App, ctx: &AppContext) -> UiObject ContainerBuilder<'a, T> { } self } + + pub fn visibility_states(&mut self, states: &[i32]) -> &mut Self { + unsafe { + ui_container_args_set_visibility_states(self.args, states.as_ptr(), states.len() as c_int); + } + self + } } impl<'a, T> Drop for ContainerBuilder<'a, T> {