commit c5fdff8f30c42dfd40bd5021d9c807c0bcc49bd2
parent 47ce825108cf53ba88d690b80cb000bb33c5685f
Author: kernelkind <kernelkind@gmail.com>
Date: Tue, 9 Dec 2025 16:24:28 -0600
refactor(route): extract Router to notedeck core
Signed-off-by: kernelkind <kernelkind@gmail.com>
Diffstat:
5 files changed, 135 insertions(+), 63 deletions(-)
diff --git a/crates/notedeck/src/lib.rs b/crates/notedeck/src/lib.rs
@@ -79,7 +79,7 @@ pub use profile::*;
pub use relay_debug::RelayDebugView;
pub use relayspec::RelaySpec;
pub use result::Result;
-pub use route::DrawerRouter;
+pub use route::{DrawerRouter, Router};
pub use storage::{AccountStorage, DataPath, DataPathType, Directory};
pub use style::NotedeckTextStyle;
pub use theme::ColorTheme;
diff --git a/crates/notedeck/src/route.rs b/crates/notedeck/src/route.rs
@@ -29,3 +29,74 @@ impl DrawerRouter {
self.drawer_focused = true;
}
}
+
+#[derive(Clone, Debug)]
+pub struct Router<R: Clone> {
+ pub routes: Vec<R>,
+ pub returning: bool,
+ pub navigating: bool,
+}
+
+impl<R: Clone> Router<R> {
+ pub fn new(routes: Vec<R>) -> Self {
+ if routes.is_empty() {
+ panic!("routes can't be empty")
+ }
+ let returning = false;
+ let navigating = false;
+
+ Self {
+ routes,
+ returning,
+ navigating,
+ }
+ }
+
+ pub fn route_to(&mut self, route: R) {
+ self.navigating = true;
+ self.routes.push(route);
+ }
+
+ /// Go back, start the returning process
+ pub fn go_back(&mut self) -> Option<R> {
+ if self.returning || self.routes.len() == 1 {
+ return None;
+ }
+ self.returning = true;
+
+ if self.routes.len() == 1 {
+ return None;
+ }
+
+ self.prev().cloned()
+ }
+
+ pub fn pop(&mut self) -> Option<R> {
+ if self.routes.len() == 1 {
+ return None;
+ }
+
+ self.returning = false;
+ self.routes.pop()
+ }
+
+ pub fn top(&self) -> &R {
+ self.routes.last().expect("routes can't be empty")
+ }
+
+ pub fn prev(&self) -> Option<&R> {
+ self.routes.get(self.routes.len() - 2)
+ }
+
+ pub fn routes(&self) -> &Vec<R> {
+ &self.routes
+ }
+
+ pub fn len(&self) -> usize {
+ self.routes.len()
+ }
+
+ pub fn is_empty(&self) -> bool {
+ self.routes.is_empty()
+ }
+}
diff --git a/crates/notedeck_columns/src/column.rs b/crates/notedeck_columns/src/column.rs
@@ -1,6 +1,6 @@
use crate::{
actionbar::TimelineOpenResult,
- route::{Route, Router, SingletonRouter},
+ route::{ColumnsRouter, Route, SingletonRouter},
timeline::{Timeline, TimelineCache, TimelineKind},
};
use enostr::RelayPool;
@@ -11,24 +11,24 @@ use tracing::warn;
#[derive(Clone, Debug)]
pub struct Column {
- pub router: Router<Route>,
+ pub router: ColumnsRouter<Route>,
pub sheet_router: SingletonRouter<Route>,
}
impl Column {
pub fn new(routes: Vec<Route>) -> Self {
- let router = Router::new(routes);
+ let router = ColumnsRouter::new(routes);
Column {
router,
sheet_router: SingletonRouter::default(),
}
}
- pub fn router(&self) -> &Router<Route> {
+ pub fn router(&self) -> &ColumnsRouter<Route> {
&self.router
}
- pub fn router_mut(&mut self) -> &mut Router<Route> {
+ pub fn router_mut(&mut self) -> &mut ColumnsRouter<Route> {
&mut self.router
}
}
@@ -164,7 +164,7 @@ impl Columns {
// Get the first router in the columns if there are columns present.
// Otherwise, create a new column picker and return the router
- pub fn get_selected_router(&mut self) -> &mut Router<Route> {
+ pub fn get_selected_router(&mut self) -> &mut ColumnsRouter<Route> {
self.ensure_column();
self.selected_mut().router_mut()
}
diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs
@@ -7,7 +7,7 @@ use crate::{
options::AppOptions,
profile::{ProfileAction, SaveProfileChanges},
repost::RepostAction,
- route::{Route, Router, SingletonRouter},
+ route::{ColumnsRouter, Route, SingletonRouter},
subscriptions::Subscriptions,
timeline::{
kind::ListKind,
@@ -316,7 +316,7 @@ fn process_nav_resp(
.columns_mut(ctx.i18n, ctx.accounts)
.column_mut(col)
.router_mut();
- cur_router.navigating = false;
+ cur_router.navigating_mut(false);
if cur_router.is_replacing() {
cur_router.remove_previous_routes();
}
@@ -431,7 +431,7 @@ pub enum RouterType {
Stack,
}
-fn go_back(stack: &mut Router<Route>, sheet: &mut SingletonRouter<Route>) {
+fn go_back(stack: &mut ColumnsRouter<Route>, sheet: &mut SingletonRouter<Route>) {
if sheet.route().is_some() {
sheet.go_back();
} else {
@@ -442,7 +442,7 @@ fn go_back(stack: &mut Router<Route>, sheet: &mut SingletonRouter<Route>) {
impl RouterAction {
pub fn process_router_action(
self,
- stack_router: &mut Router<Route>,
+ stack_router: &mut ColumnsRouter<Route>,
sheet_router: &mut SingletonRouter<Route>,
) -> Option<ProcessNavResult> {
match self {
@@ -802,7 +802,7 @@ fn render_nav_body(
get_active_columns_mut(note_context.i18n, ctx.accounts, &mut app.decks_cache)
.column(col)
.router()
- .navigating;
+ .navigating();
let draft = app.drafts.compose_mut();
if navigating {
@@ -839,7 +839,7 @@ fn render_nav_body(
get_active_columns_mut(note_context.i18n, ctx.accounts, &mut app.decks_cache)
.column(col)
.router()
- .navigating;
+ .navigating();
let search_buffer = app.view_state.searches.entry(id).or_default();
let txn = Transaction::new(ctx.ndb).expect("txn");
@@ -1246,13 +1246,13 @@ pub fn render_nav(
app.columns_mut(ctx.i18n, ctx.accounts)
.column_mut(col)
.router_mut()
- .navigating,
+ .navigating(),
)
.returning(
app.columns_mut(ctx.i18n, ctx.accounts)
.column_mut(col)
.router_mut()
- .returning,
+ .returning(),
)
.animate_transitions(ctx.settings.get_settings_mut().animate_nav_transitions)
.show_mut(ui, |ui, render_type, nav| match render_type {
diff --git a/crates/notedeck_columns/src/route.rs b/crates/notedeck_columns/src/route.rs
@@ -1,6 +1,6 @@
use egui_nav::Percent;
use enostr::{NoteId, Pubkey};
-use notedeck::{tr, Localization, NoteZapTargetOwned, RootNoteIdBuf, WalletType};
+use notedeck::{tr, Localization, NoteZapTargetOwned, RootNoteIdBuf, Router, WalletType};
use std::ops::Range;
use crate::{
@@ -418,10 +418,8 @@ impl Route {
// TODO: add this to egui-nav so we don't have to deal with returning
// and navigating headaches
#[derive(Clone, Debug)]
-pub struct Router<R: Clone> {
- routes: Vec<R>,
- pub returning: bool,
- pub navigating: bool,
+pub struct ColumnsRouter<R: Clone> {
+ router_internal: Router<R>,
replacing: bool,
forward_stack: Vec<R>,
@@ -429,18 +427,15 @@ pub struct Router<R: Clone> {
overlay_ranges: Vec<Range<usize>>,
}
-impl<R: Clone> Router<R> {
+impl<R: Clone> ColumnsRouter<R> {
pub fn new(routes: Vec<R>) -> Self {
if routes.is_empty() {
panic!("routes can't be empty")
}
- let returning = false;
- let navigating = false;
let replacing = false;
- Router {
- routes,
- returning,
- navigating,
+ let router_internal = Router::new(routes);
+ ColumnsRouter {
+ router_internal,
replacing,
forward_stack: Vec::new(),
overlay_ranges: Vec::new(),
@@ -448,9 +443,8 @@ impl<R: Clone> Router<R> {
}
pub fn route_to(&mut self, route: R) {
- self.navigating = true;
+ self.router_internal.route_to(route);
self.forward_stack.clear();
- self.routes.push(route);
}
pub fn route_to_overlaid(&mut self, route: R) {
@@ -465,17 +459,15 @@ impl<R: Clone> Router<R> {
// Route to R. Then when it is successfully placed, should call `remove_previous_routes` to remove all previous routes
pub fn route_to_replaced(&mut self, route: R) {
- self.navigating = true;
self.replacing = true;
- self.routes.push(route);
+ self.router_internal.route_to(route);
}
/// Go back, start the returning process
pub fn go_back(&mut self) -> Option<R> {
- if self.returning || self.routes.len() == 1 {
+ if self.router_internal.returning || self.router_internal.len() == 1 {
return None;
}
- self.returning = true;
if let Some(range) = self.overlay_ranges.pop() {
tracing::debug!("Going back, found overlay: {:?}", range);
@@ -484,17 +476,12 @@ impl<R: Clone> Router<R> {
tracing::debug!("Going back, no overlay");
}
- if self.routes.len() == 1 {
- return None;
- }
-
- self.prev().cloned()
+ self.router_internal.go_back()
}
pub fn go_forward(&mut self) -> bool {
if let Some(route) = self.forward_stack.pop() {
- self.navigating = true;
- self.routes.push(route);
+ self.router_internal.route_to(route);
true
} else {
false
@@ -503,7 +490,7 @@ impl<R: Clone> Router<R> {
/// Pop a route, should only be called on a NavRespose::Returned reseponse
pub fn pop(&mut self) -> Option<R> {
- if self.routes.len() == 1 {
+ if self.router_internal.len() == 1 {
return None;
}
@@ -512,7 +499,7 @@ impl<R: Clone> Router<R> {
break 's false;
};
- if last_range.end != self.routes.len() {
+ if last_range.end != self.router_internal.len() {
break 's false;
}
@@ -525,30 +512,27 @@ impl<R: Clone> Router<R> {
true
};
- self.returning = false;
- let popped = self.routes.pop();
+ let popped = self.router_internal.pop()?;
if !is_overlay {
- if let Some(ref route) = popped {
- self.forward_stack.push(route.clone());
- }
+ self.forward_stack.push(popped.clone());
}
- popped
+ Some(popped)
}
pub fn remove_previous_routes(&mut self) {
- let num_routes = self.routes.len();
+ let num_routes = self.router_internal.len();
if num_routes <= 1 {
return;
}
- self.returning = false;
+ self.router_internal.returning = false;
self.replacing = false;
- self.routes.drain(..num_routes - 1);
+ self.router_internal.routes.drain(..num_routes - 1);
}
/// Removes all routes in the overlay besides the last
fn remove_overlay(&mut self, overlay_range: Range<usize>) {
- let num_routes = self.routes.len();
+ let num_routes = self.router_internal.routes.len();
if num_routes <= 1 {
return;
}
@@ -557,7 +541,8 @@ impl<R: Clone> Router<R> {
return;
}
- self.routes
+ self.router_internal
+ .routes
.drain(overlay_range.start..overlay_range.end - 1);
}
@@ -569,34 +554,50 @@ impl<R: Clone> Router<R> {
let mut overlaying_active = None;
let mut binding = self.overlay_ranges.last_mut();
if let Some(range) = &mut binding {
- if range.end == self.routes.len() - 1 {
+ if range.end == self.router_internal.len() - 1 {
overlaying_active = Some(range);
}
};
if let Some(range) = overlaying_active {
- range.end = self.routes.len();
+ range.end = self.router_internal.len();
} else {
- let new_range = self.routes.len() - 1..self.routes.len();
+ let new_range = self.router_internal.len() - 1..self.router_internal.len();
self.overlay_ranges.push(new_range);
}
}
fn new_overlay(&mut self) {
- let new_range = self.routes.len() - 1..self.routes.len();
+ let new_range = self.router_internal.len() - 1..self.router_internal.len();
self.overlay_ranges.push(new_range);
}
- pub fn top(&self) -> &R {
- self.routes.last().expect("routes can't be empty")
+ pub fn routes(&self) -> &Vec<R> {
+ self.router_internal.routes()
}
- pub fn prev(&self) -> Option<&R> {
- self.routes.get(self.routes.len() - 2)
+ pub fn navigating(&self) -> bool {
+ self.router_internal.navigating
}
- pub fn routes(&self) -> &Vec<R> {
- &self.routes
+ pub fn navigating_mut(&mut self, new: bool) {
+ self.router_internal.navigating = new;
+ }
+
+ pub fn returning(&self) -> bool {
+ self.router_internal.returning
+ }
+
+ pub fn returning_mut(&mut self, new: bool) {
+ self.router_internal.returning = new;
+ }
+
+ pub fn top(&self) -> &R {
+ self.router_internal.top()
+ }
+
+ pub fn prev(&self) -> Option<&R> {
+ self.router_internal.prev()
}
}