From: Olaf Wintermann Date: Fri, 5 Jun 2026 21:04:06 +0000 (+0200) Subject: add navigation stack X-Git-Url: https://uap-core.de/gitweb/?a=commitdiff_plain;h=59b5e9d3403a330c582dc5990606aacce3124945;p=note.git add navigation stack --- diff --git a/application/src/notebook.rs b/application/src/notebook.rs index a8465ad..317d46c 100644 --- a/application/src/notebook.rs +++ b/application/src/notebook.rs @@ -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) = ¬e.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 = Box::new("hello world".to_string()); + + let param: Box = 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 { + if let Some(doc) = &self.model { + doc.clone() + } else { + let doc = self.load_notebook(backend); + doc + } + } } /// ListView item diff --git a/application/src/window.rs b/application/src/window.rs index ddf5ca6..6290791 100644 --- a/application/src/window.rs +++ b/application/src/window.rs @@ -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, + navigation: Navigation, + selected_notebook: Option>, groups: Vec, @@ -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(¬ebook_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) -> UiObject, 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, + 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 +} + +enum NavDirection { + Forward, + Backward } \ No newline at end of file diff --git a/ui-rs/src/ui/toolkit.rs b/ui-rs/src/ui/toolkit.rs index d0666a8..b5d7ea1 100644 --- a/ui-rs/src/ui/toolkit.rs +++ b/ui-rs/src/ui/toolkit.rs @@ -949,6 +949,10 @@ impl UiSourceList { &self.sublists } + pub fn data_mut(&mut self) -> &mut Vec> { + &mut self.sublists + } + pub fn len(&self) -> usize { self.sublists.len() } @@ -960,6 +964,20 @@ impl UiSourceList { pub fn get_mut(&mut self, index: usize) -> Option<&mut SubList> { 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) { unsafe {