]> uap-core.de Git - note.git/commitdiff
check lastmodified when a Note view model is re-attached main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 18 Jul 2026 09:45:08 +0000 (11:45 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Sat, 18 Jul 2026 09:45:08 +0000 (11:45 +0200)
application/backend/src/backend.rs
application/backend/src/storage.rs
application/note/src/note.rs

index 4f0661a81ffcaa5096ae3c6a99a2b0ea3bf4c81a..d7aec6215e640be9e47ecc60eece515b3ebfc8cb 100644 (file)
@@ -25,7 +25,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-
+use std::fs::Metadata;
 use std::future::Future;
 use std::io::Error;
 use std::path::{Path, PathBuf};
@@ -48,7 +48,7 @@ use entity::notecontent::{Entity as NoteContent};
 use migration::prelude::Utc;
 use crate::lockmanager::LockManager;
 use crate::note::{create_nodename, randomize_nodename};
-use crate::storage::{get_collection_storage_path, get_file_content, get_last_modified, get_note_storage_path, write_file, write_tmp_file};
+use crate::storage::{*};
 
 pub struct Backend {
     rt: Arc<Runtime>,
@@ -562,7 +562,14 @@ impl BackendHandle {
                                 let fs_result = write_file(path.as_path(), note_content.as_ref()).await;
                                 match fs_result {
                                     Ok(_) => {
-                                        result = SaveNoteResult::Ok((note.clone(), 0));
+                                        let lastmodified = get_last_modified(path.as_path()).await;
+                                        let ret = SaveNoteRet {
+                                            model: note.clone(),
+                                            content_id: 0,
+                                            local_path: Some(path),
+                                            local_lastmodified: lastmodified
+                                        };
+                                        result = SaveNoteResult::Ok(ret);
                                     },
                                     Err(e) => {
                                         result = SaveNoteResult::FileError(e);
@@ -579,7 +586,13 @@ impl BackendHandle {
 
                             match result2 {
                                 Ok(ctn) => {
-                                    result = SaveNoteResult::Ok((note.clone(), ctn.id));
+                                    let ret = SaveNoteRet {
+                                        model: note.clone(),
+                                        content_id: ctn.id,
+                                        local_path: None,
+                                        local_lastmodified: None
+                                    };
+                                    result = SaveNoteResult::Ok(ret);
                                 }
                                 Err(e) => {
                                     result = SaveNoteResult::Error(e);
@@ -587,7 +600,13 @@ impl BackendHandle {
                             }
                         }
                     } else {
-                        result = SaveNoteResult::Ok((note.clone(), 0));
+                        let ret = SaveNoteRet {
+                            model: note.clone(),
+                            content_id: 0,
+                            local_path: None,
+                            local_lastmodified: None
+                        };
+                        result = SaveNoteResult::Ok(ret);
                     }
 
                     if result.is_ok() {
@@ -609,6 +628,16 @@ impl BackendHandle {
         let _ = self.tx.send(cmd);
     }
 
+    pub fn get_file_metadata<F>(&self, path: &Path, callback: F)
+    where F: FnOnce(std::io::Result<Metadata>) + Send + 'static {
+        let p = PathBuf::from(path);
+        let cmd = Box::pin(async move {
+            let result = tokio::fs::metadata(p.as_path()).await;
+            callback(result);
+        });
+        let _ = self.tx.send(cmd);
+    }
+
     pub fn open_extern<F>(&self, note_id: i32, callback: F)
     where F: FnOnce(OpenExternResult) + Send + 'static {
         let backend = self.backend.clone();
@@ -666,7 +695,7 @@ pub struct NoteContentRet {
 
 
 pub enum SaveNoteResult {
-    Ok((entity::note::Model, i32)),
+    Ok(SaveNoteRet),
     VersionConflict,
     FileAlreadyExists(PathBuf),
     Error(DbErr),
@@ -674,6 +703,13 @@ pub enum SaveNoteResult {
     ValidationError(&'static str)
 }
 
+pub struct SaveNoteRet {
+    pub model: entity::note::Model,
+    pub content_id: i32,
+    pub local_path: Option<PathBuf>,
+    pub local_lastmodified: Option<SystemTime>
+}
+
 pub enum OpenExternResult {
     Ok((PathBuf, bool)), // path, istmp
     DbErr(DbErr),
index 6271822988adc2c3ffeeb93da020f6d9fcf6da91..a91ab75f7b505b58ee8c97ac712baa3afa393335 100644 (file)
@@ -25,7 +25,7 @@
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  * POSSIBILITY OF SUCH DAMAGE.
  */
-use std::fs::metadata;
+
 use std::io::ErrorKind;
 use std::path::Path;
 use std::time::SystemTime;
index 93b1713f276c76f540c449fb7db2a6b04ef643ab..b2a933e10079782ddbfa274d8f29b9af5f27c061 100644 (file)
@@ -129,7 +129,7 @@ impl Note {
     /// Handles any attachment status change, which includes if this note is
     /// directly attached or detached, but also if any parent attachment status changes
     #[action]
-    pub fn attachment_status_changed(&mut self, _event: &mut ActionEvent) -> Option<()>{
+    pub fn attachment_status_changed(&mut self, _event: &mut ActionEvent) -> Option<()> {
         let doc = self.doc.get_doc()?;
 
         if doc.ctx.is_attached_to_obj() {
@@ -149,6 +149,8 @@ impl Note {
                     doc.ctx.unset_state(AppStates::NoteShowInfo as i32);
                 }
             }
+
+            self.check_lastmodified();
         } else {
             self.lock = None;
             self.text.set_readonly(false);
@@ -157,6 +159,34 @@ impl Note {
         Some(())
     }
 
+    fn check_lastmodified(&mut self) {
+        let Some(doc) = self.doc.get_doc() else {
+            return;
+        };
+
+        if let Some(path) = &self.local_path && let Some(lastmodified) = self.local_lastmodified {
+            let proxy = doc.doc_proxy();
+            self.backend.get_file_metadata(path.as_path(), |result| {
+                proxy.call_mainthread(|doc, note| {
+                    match result {
+                        Ok(metadata) => {
+                            if let Ok(lm) = metadata.modified() && let Some(lastmodified) = note.local_lastmodified {
+                                if lastmodified != lm {
+                                    println!("note was changed");
+                                }
+                            } else {
+                                println!("no last_modified available");
+                            }
+                        },
+                        Err(e) => {
+                            println!("cannot get metadata: {}", e);
+                        }
+                    }
+                });
+            });
+        }
+    }
+
     pub fn init_from_model(&mut self, model: &entity::note::Model) {
         self.id = NoteId::Id(model.note_id);
         self.nodename = Some(model.nodename.clone());
@@ -365,11 +395,13 @@ impl NoteViewModel for Note {
         self.backend.save_note(self.notebook_instance_id, self.id.clone(), note, Some(notecontent), |result|{
             proxy.call_mainthread(move |doc, note|{
                 match result {
-                    SaveNoteResult::Ok((notemodel, content_id)) => {
-                        note.id = NoteId::Id(notemodel.note_id);
-                        note.content_id = content_id;
-                        note.version = notemodel.version;
-                        println!("Note saved: note_id: {}, content_id: {}, version: {}", notemodel.note_id, content_id, note.version);
+                    SaveNoteResult::Ok(ret) => {
+                        note.id = NoteId::Id(ret.model.note_id);
+                        note.content_id = ret.content_id;
+                        note.version = ret.model.version;
+                        note.local_path = ret.local_path;
+                        note.local_lastmodified = ret.local_lastmodified;
+                        println!("Note saved: note_id: {}, content_id: {}, version: {}", ret.model.note_id, ret.content_id, note.version);
 
                         // make sure the "new note" button is always enabled within this note
                         doc.ctx.unsuppress_state(AppStates::NoteEnableNew as i32);