dependencies = [
"backend",
"entity",
+ "notify",
"sea-orm",
"tokio",
"ui-rs",
});
// 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);
}
(backend_handle, join)
}
-}
-impl BackendHandle {
pub fn send_broadcast(&self, msg: BroadcastMessage) -> Result<usize, SendError<BroadcastMessage>> {
- 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<usize, SendError<BroadcastMessage>> {
+ self.backend.send_broadcast(msg)
+ }
/// Reloads the notebook structure/collections. On success, it sends a NotebookStructureUpdate
/// to the broadcast channel.
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<FSWatch>, btx: tokio::sync::broadcast::Sender<BroadcastMessage>) -> notify::Result<()> {
+pub async fn fs_notify(mut rx: UnboundedReceiver<FSWatch>, backend: Arc<Backend>) -> notify::Result<()> {
let mut path_map = HashMap::<PathBuf, u32>::new();
let mut watcher = RecommendedWatcher::new(
move |res: Result<Event, notify::Error>| {
match res {
Ok(event) => {
- _ = btx.send(BroadcastMessage::Notify(event));
+ _ = backend.send_broadcast(BroadcastMessage::Notify(event));
},
Err(e) => {
println!("Notify Error: {:?}", e);
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"
Null = 0,
NoteEnableNew,
NoteShowInfo,
+ NoteShowExtModInfo,
NoteMaximized
}
use ui_rs::ui::*;
use crate::AppStates;
use crate::window::NoteTypeTabView;
+use notify::{Event};
static TMP_ID: AtomicU64 = AtomicU64::new(1);
title_end: i32,
modified: bool,
+ is_saving: bool,
pub local_path: Option<PathBuf>,
pub local_lastmodified: Option<SystemTime>,
title_start: -1,
title_end: -1,
modified: false,
+ is_saving: false,
local_path: None,
local_lastmodified: None,
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| {
}
}
+ #[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();
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 {
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);
}
},
BroadcastMessage::Notify(event) => {
- println!("fs notify event");
+ if let Some(note) = &self.selected_note {
+ let arg: Box<dyn Any> = Box::new(event);
+ note.doc.ctx.call_action_with_parameter("filesystem_notify", arg);
+ }
},
_ => {
- },
+ }
}
}
}
l.visibility_states(&[AppStates::NoteShowInfo as i32]);
});
+ obj.hbox_builder()
+ .visibility_states(&[AppStates::NoteShowExtModInfo as i32])
+ .spacing(4)
+ .create(|obj|{
+ obj.label(|l|{
+ l.label("The note has been modified by an external program");
+ l.fill(true);
+ });
+ obj.button(|b|{
+ b.label("Reload");
+ b.action("note_reload");
+ });
+ obj.button(|b|{
+ b.label("Close");
+ b.action("note_extmod_close");
+ });
+ });
+
let textarea = obj.textarea(|b|{
b.fill(true);
b.varname("note_text");
}
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> {