]> uap-core.de Git - note.git/commitdiff
add navigation stack main
authorOlaf Wintermann <olaf.wintermann@gmail.com>
Fri, 5 Jun 2026 21:04:06 +0000 (23:04 +0200)
committerOlaf Wintermann <olaf.wintermann@gmail.com>
Fri, 5 Jun 2026 21:04:06 +0000 (23:04 +0200)
application/src/notebook.rs
application/src/window.rs
ui-rs/src/ui/toolkit.rs

index a8465ade2c0a709e529878daa9ed80859f3a7da4..317d46c08a57f54d21623bb82b16c0a9f4c7534a 100644 (file)
@@ -6,6 +6,7 @@ use ui_rs::ui::*;
 use entity::note::{Model as Note};
 use crate::backend::{BackendHandle, BroadcastMessage, NoteId, NoteUpdate};
 use crate::note::new_note_id;
+use crate::window::NavigationItem;
 
 /// UI model for a notebook
 #[derive(UiModel)]
@@ -76,6 +77,7 @@ impl Notebook {
                 self.selected_note = None;
             }
             if let Some(note) = s.selected_element_mut(self.notes.data_mut()) {
+                let nav = NavigationItem { collection_id: self.collection_id, note_id: Some(note.id.clone()) };
                 let doc = if let Some(doc) = &note.model {
                     doc.clone()
                 } else {
@@ -97,8 +99,8 @@ impl Notebook {
                 if let Some(mut nb) = self.doc_ref.get_doc() {
                     nb.ctx.attach(&doc);
                     self.selected_note = Some(doc);
-
-                    let param: Box<dyn Any> = Box::new("hello world".to_string());
+                    
+                    let param: Box<dyn Any> = Box::new(nav);
                     nb.ctx.call_action_with_parameter("navigation", param);
                 }
             }
@@ -231,6 +233,15 @@ impl NotebookItem {
         
         doc
     }
+    
+    pub fn get_doc(&mut self, backend: &BackendHandle) -> UiDoc<Notebook> {
+        if let Some(doc) = &self.model {
+            doc.clone()
+        } else {
+            let doc = self.load_notebook(backend);
+            doc
+        }
+    }
 }
 
 /// ListView item
index ddf5ca6f5809df7c558d512b42de191f592353f2..62907918afb53c258b7037d5d3f3846d0b8a55f7 100644 (file)
@@ -30,7 +30,7 @@ use ui_rs::{action, ui_actions, UiModel};
 use ui_rs::ui::*;
 use crate::App;
 use entity::collection::{Model as Collection, Node};
-use crate::backend::{BackendHandle, BroadcastMessage};
+use crate::backend::{BackendHandle, BroadcastMessage, NoteId};
 use crate::newnotebook::new_notebook_dialog;
 use crate::notebook::{notelist_getvalue, NoteItem, Notebook, NotebookItem};
 
@@ -42,6 +42,8 @@ pub struct MainWindow {
     
     pub broadcast_rx: tokio::sync::broadcast::Receiver<BroadcastMessage>,
 
+    navigation: Navigation,
+
     selected_notebook: Option<UiDoc<Notebook>>,
 
     groups: Vec<Collection>,
@@ -58,6 +60,7 @@ impl MainWindow {
             obj: UiObjRef::default(),
             backend: app.backend.clone(),
             broadcast_rx: app.backend.btx.subscribe(),
+            navigation: Navigation::default(),
             selected_notebook: None,
             groups: Vec::new(),
             notebooks: UiSourceList::default()
@@ -73,6 +76,10 @@ impl MainWindow {
 
     #[action]
     pub fn new_note(&mut self, _event: &ActionEvent) {
+        let Some(mut obj) = self.obj.get_object() else {
+            return;
+        };
+
         // The new_note action is handled by Notebook and MainWindow
         // When a notebook is attached, the notebook receives this action, but in case
         // no notebook is selected, the action is handled in the main window
@@ -84,62 +91,59 @@ impl MainWindow {
 
         // Select the first notebook
         // TODO: maybe select a configured default notebook
-        if let Some(group) = self.notebooks.get(0) {
-            if let Some(notebook) = group.data().get(0) {
-                self.select_notebook(notebook.data.collection_id);
-                // self.selected_notebook has a value after select_notebook()
-                if let Some(doc) = &self.selected_notebook {
-                    // Now that a notebook is selected, we can open the new note UI there
-                    doc.ctx.call_action("new_note");
+        if let Some(group) = self.notebooks.get_mut(0) {
+            if let Some(notebook) = group.data_mut().get_mut(0) {
+                let doc = notebook.get_doc(&self.backend);
+                if let Some(current) = &self.selected_notebook {
+                    obj.ctx.detach(current);
                 }
+                obj.ctx.attach(&doc);
+                // Now that a notebook is selected, we can open the new note UI there
+                // TODO: this does not work correctly, the backend loading can override the list after new_ntoe
+                doc.ctx.call_action("new_note");
+
+                self.selected_notebook = Some(doc);
             }
         }
     }
 
-    pub fn select_notebook(&mut self, collection_id: i32) {
-        let Some(mut obj) = self.obj.get_object() else {
-            return;
-        };
+    pub fn do_nav(&mut self, direction: NavDirection) -> Option<()> {
+        let nav = match direction {
+            NavDirection::Forward => self.navigation.go_forward(),
+            NavDirection::Backward => self.navigation.go_back()
+        }?;
+        let mut obj = self.obj.get_object()?;
+        let (sl, i) = find_notebook(&self.notebooks, nav.collection_id)?;
+        let mut sublist = self.notebooks.get_mut(sl)?;
+
+        sublist.list().set_selected_index(i as i32);
+        let notebook = sublist.data_mut().get_mut(i)?;
 
+        // detach current notebook
         if let Some(current) = &self.selected_notebook {
             obj.ctx.detach(current);
         }
 
-        let notebook = Notebook::new(collection_id, &self.backend);
-        let doc = UiDoc::new2(notebook, |notebook, doc| {
-            notebook.doc_ref = doc.doc_ref();
-        });
-        let proxy = doc.doc_proxy();
-        self.backend.get_notes(collection_id, |result|{
-            proxy.call_mainthread(|_, nb| {
-                match result {
-                    Ok(notes) => {
-                        nb.set_notes(notes);
-                    },
-                    Err(err) => {
-                        eprintln!("get_notes failed: {}", err);
-                    }
-                }
-            });
-        });
+        let notebook_doc = notebook.get_doc(&self.backend);
+        obj.ctx.attach(&notebook_doc);
+        self.selected_notebook = Some(notebook_doc);
 
-        obj.ctx.attach(&doc);
-        self.selected_notebook = Some(doc);
+        Some(())
     }
 
     #[action]
     pub fn go_back(&mut self, _event: &ActionEvent) {
-
+        self.do_nav(NavDirection::Backward);
     }
 
     #[action]
     pub fn go_forward(&mut self, _event: &ActionEvent) {
-
+        self.do_nav(NavDirection::Forward);
     }
 
-    #[action(String)]
-    pub fn navigation(&mut self, _event: &ActionEvent, arg: &String) {
-        println!("navigation: {}", arg);
+    #[action(NavigationItem)]
+    pub fn navigation(&mut self, _event: &ActionEvent, arg: &NavigationItem) {
+        self.navigation.push(arg.clone());
     }
 
     #[action]
@@ -190,20 +194,17 @@ pub fn create_window(app: &App, ctx: &AppContext<MainWindow>) -> UiObject<MainWi
                 b.onactivate(|e|{
                     if let EventType::SubList(sl) = &e.event_type {
                         if let Some(nb) = sl.get_mut_from(&mut e.data.notebooks) {
+                            let nav = NavigationItem { collection_id: nb.data.collection_id, note_id: None };
                             // detach current notebook
                             if let Some(current) = &e.data.selected_notebook {
                                 e.obj.ctx.detach(current);
                             }
 
-                            let notebook_doc = if let Some(doc) = &nb.model {
-                                doc.clone()
-                            } else {
-                                let doc = nb.load_notebook(&e.data.backend);
-                                doc
-                            };
-
+                            let notebook_doc = nb.get_doc(&e.data.backend);
                             e.obj.ctx.attach(&notebook_doc);
                             e.data.selected_notebook = Some(notebook_doc);
+
+                            e.data.navigation.push(nav);
                         }
                     }
                 });
@@ -261,7 +262,63 @@ fn init_window_data(window: &mut MainWindow, data: &App) {
     window.update_notebook_structure(&data.notebooks);
 }
 
+fn find_notebook(sourcelist: &UiSourceList<NotebookItem>, collection_id: i32) -> Option<(usize, usize)> {
+    for (s, sl) in sourcelist.data().iter().enumerate() {
+        for (i, nb) in sl.data().iter().enumerate() {
+            if nb.data.collection_id == collection_id {
+                return Some((s, i))
+            }
+        }
+    }
+    None
+}
+
 pub enum NoteTypeTabView {
     _Empty = 0,
     TextArea = 1
+}
+
+#[derive(Default)]
+pub struct Navigation {
+    history: Vec<NavigationItem>,
+    current: usize,
+}
+
+impl Navigation {
+    pub fn push(&mut self, page: NavigationItem) {
+        // If we are not at the end, truncate forward history
+        self.history.truncate(self.current + 1);
+
+        self.history.push(page);
+        self.current += 1;
+    }
+
+    pub fn go_back(&mut self) -> Option<&NavigationItem> {
+        if self.current > 1 {
+            self.current -= 1;
+            self.history.get(self.current-1)
+        } else {
+            None
+        }
+    }
+
+    pub fn go_forward(&mut self) -> Option<&NavigationItem> {
+        if self.current < self.history.len() {
+            self.current += 1;
+            self.history.get(self.current-1)
+        } else {
+            None
+        }
+    }
+}
+
+#[derive(Default, Clone)]
+pub struct NavigationItem {
+    pub collection_id: i32,
+    pub note_id: Option<NoteId>
+}
+
+enum NavDirection {
+    Forward,
+    Backward
 }
\ No newline at end of file
index d0666a8ebeb04235d6f31695db853cc964e3aa06..b5d7ea10135b691130795b7f80ffc665d041c527 100644 (file)
@@ -949,6 +949,10 @@ impl<T> UiSourceList<T> {
         &self.sublists
     }
 
+    pub fn data_mut(&mut self) -> &mut Vec<SubList<T>> {
+        &mut self.sublists
+    }
+
     pub fn len(&self) -> usize {
         self.sublists.len()
     }
@@ -960,6 +964,20 @@ impl<T> UiSourceList<T> {
     pub fn get_mut(&mut self, index: usize) -> Option<&mut SubList<T>> {
         self.sublists.get_mut(index)
     }
+    
+    pub fn get_item(&self, sublist: usize, item: usize) -> Option<&T> {
+        if let Some(sl) = self.sublists.get(sublist) {
+            return sl.data().get(item); 
+        }
+        None
+    }
+
+    pub fn get_item_mut(&mut self, sublist: usize, item: usize) -> Option<&mut T> {
+        if let Some(sl) = self.sublists.get_mut(sublist) {
+            return sl.data_mut().get_mut(item);
+        }
+        None
+    }
 
     pub fn push(&mut self, sublist: SubList<T>) {
         unsafe {