notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

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:
Mcrates/notedeck_columns/src/nav.rs | 28+++++++++++++---------------
Mcrates/notedeck_columns/src/route.rs | 37++++++++++++++++++++++++++++++++++---
Mcrates/notedeck_columns/src/toolbar.rs | 33++++++++++++---------------------
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, + ); } } }