commit d2ff33d031646f876c328e6e07edd3f5d96e8c24
parent 9d98f2c9e2e9f46ca44b15f74d60d4a61bb7932d
Author: William Casarin <jb55@jb55.com>
Date: Sun, 25 Jan 2026 15:28:10 -0800
route: centralize resource cleanup for popped routes
Adds cleanup_popped_route() function to handle Timeline, Thread, and
EditProfile route cleanup in one place. Updates nav.rs and toolbar.rs
to use the shared function, removing duplicated cleanup logic.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat:
3 files changed, 59 insertions(+), 39 deletions(-)
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::{ColumnsRouter, Route, SingletonRouter},
+ route::{cleanup_popped_route, ColumnsRouter, Route, SingletonRouter},
subscriptions::Subscriptions,
timeline::{
kind::ListKind,
@@ -288,20 +288,18 @@ fn process_nav_resp(
.router_mut()
.pop();
- if let Some(Route::Timeline(kind)) = &r {
- if let Err(err) = app.timeline_cache.pop(kind, ctx.ndb, ctx.pool) {
- error!("popping timeline had an error: {err} for {:?}", kind);
- }
- };
-
- if let Some(Route::Thread(selection)) = &r {
- app.threads
- .close(ctx.ndb, ctx.pool, selection, return_type, col);
- }
-
- // we should remove profile state once we've returned
- if let Some(Route::EditProfile(pk)) = &r {
- app.view_state.pubkey_to_profile_state.remove(pk);
+ // Clean up resources for the popped route
+ if let Some(route) = &r {
+ cleanup_popped_route(
+ route,
+ &mut app.timeline_cache,
+ &mut app.threads,
+ &mut app.view_state,
+ ctx.ndb,
+ ctx.pool,
+ return_type,
+ col,
+ );
}
process_result = Some(ProcessNavResult::SwitchOccurred);
diff --git a/crates/notedeck_columns/src/route.rs b/crates/notedeck_columns/src/route.rs
@@ -1,5 +1,6 @@
-use egui_nav::Percent;
-use enostr::{NoteId, Pubkey};
+use egui_nav::{Percent, ReturnType};
+use enostr::{NoteId, Pubkey, RelayPool};
+use nostrdb::Ndb;
use notedeck::{
tr, Localization, NoteZapTargetOwned, ReplacementType, RootNoteIdBuf, Router, WalletType,
};
@@ -7,8 +8,9 @@ use std::ops::Range;
use crate::{
accounts::AccountsRoute,
- timeline::{kind::ColumnTitle, ThreadSelection, TimelineKind},
+ timeline::{kind::ColumnTitle, thread::Threads, ThreadSelection, TimelineCache, TimelineKind},
ui::add_column::{AddAlgoRoute, AddColumnRoute},
+ view_state::ViewState,
};
use tokenator::{ParseError, TokenParser, TokenSerializable, TokenWriter};
@@ -729,6 +731,35 @@ impl<R: Clone> Default for SingletonRouter<R> {
}
}
+/// Centralized resource cleanup for popped routes.
+/// This handles cleanup for Timeline, Thread, and EditProfile routes.
+#[allow(clippy::too_many_arguments)]
+pub fn cleanup_popped_route(
+ route: &Route,
+ timeline_cache: &mut TimelineCache,
+ threads: &mut Threads,
+ view_state: &mut ViewState,
+ ndb: &mut Ndb,
+ pool: &mut RelayPool,
+ return_type: ReturnType,
+ col_index: usize,
+) {
+ match route {
+ Route::Timeline(kind) => {
+ if let Err(err) = timeline_cache.pop(kind, ndb, pool) {
+ tracing::error!("popping timeline had an error: {err} for {:?}", kind);
+ }
+ }
+ Route::Thread(selection) => {
+ threads.close(ndb, pool, selection, return_type, col_index);
+ }
+ Route::EditProfile(pk) => {
+ view_state.pubkey_to_profile_state.remove(pk);
+ }
+ _ => {}
+ }
+}
+
#[cfg(test)]
mod tests {
use enostr::NoteId;
diff --git a/crates/notedeck_columns/src/toolbar.rs b/crates/notedeck_columns/src/toolbar.rs
@@ -2,6 +2,7 @@ use egui_nav::ReturnType;
use notedeck::AppContext;
use crate::{
+ route::cleanup_popped_route,
timeline::{kind::ListKind, TimelineKind},
Damus, Route,
};
@@ -94,27 +95,17 @@ fn go_to_top_of_column(app: &mut Damus, ctx: &mut AppContext, col_index: usize)
// Pop all routes except the base route
while column.router().routes().len() > 1 {
if let Some(popped) = column.router_mut().pop() {
- // TODO(jb55): centralize this resource cleanup logic into a shared
- // pop_and_cleanup function. This same pattern exists in nav.rs.
- // Clean up resources for popped route
- match popped {
- Route::Timeline(timeline_kind) => {
- if let Err(err) = app.timeline_cache.pop(&timeline_kind, ctx.ndb, ctx.pool) {
- tracing::error!(
- "popping timeline had an error: {err} for {:?}",
- timeline_kind
- );
- }
- }
- Route::Thread(selection) => {
- app.threads
- .close(ctx.ndb, ctx.pool, &selection, ReturnType::Click, col_index);
- }
- Route::EditProfile(pk) => {
- app.view_state.pubkey_to_profile_state.remove(&pk);
- }
- _ => {}
- }
+ // Clean up resources for the popped route
+ cleanup_popped_route(
+ &popped,
+ &mut app.timeline_cache,
+ &mut app.threads,
+ &mut app.view_state,
+ ctx.ndb,
+ ctx.pool,
+ ReturnType::Click,
+ col_index,
+ );
}
}
}