notedeck

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

commit 7c970b5fbfcdbf7468ef2cc15a01d07ba5b719a6
parent 9645ecb70fe25f3334a72824e9cc7d12130bbc56
Author: e <e@*.lan>
Date:   Sun, 28 Dec 2025 09:28:55 -0600

filter: add contact_list_timestamp tracking to FilterStates

Add infrastructure to track when a contact list filter was built,
enabling detection of stale filters after follow/unfollow actions.

Changes:
- Add `contact_list_timestamp` field to FilterStates
- Add `invalidate()` method to reset filter states for rebuild

This is preparatory work for fixing #1225 where unfollowed accounts
still appear in the feed because the timeline filter is not rebuilt
when the contact list changes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: e <e@*.lan>
Signed-off-by: alltheseas

Diffstat:
Mcrates/notedeck/src/filter.rs | 22++++++++++++++++++++++
1 file changed, 22 insertions(+), 0 deletions(-)

diff --git a/crates/notedeck/src/filter.rs b/crates/notedeck/src/filter.rs @@ -20,6 +20,11 @@ pub struct UnifiedSubscription { pub struct FilterStates { pub initial_state: FilterState, pub states: HashMap<String, FilterState>, + + /// Timestamp (`created_at`) of the contact list note used to build + /// the current filter. Used to detect when the contact list has + /// changed (e.g., after follow/unfollow) so the filter can be rebuilt. + pub contact_list_timestamp: Option<u64>, } impl FilterStates { @@ -73,6 +78,7 @@ impl FilterStates { Self { initial_state, states: HashMap::new(), + contact_list_timestamp: None, } } @@ -93,6 +99,22 @@ impl FilterStates { *cur_state = state.clone(); } } + + /// Invalidate the filter states, forcing a rebuild on the next check. + /// + /// This resets all relay states to [`FilterState::NeedsRemote`] and + /// clears the contact list timestamp, which will trigger the filter + /// rebuild flow when the timeline is next polled. + /// + /// Note: We reset states rather than clearing them so that + /// [`Self::set_all_states`] can update them during the rebuild. + pub fn invalidate(&mut self) { + self.initial_state = FilterState::NeedsRemote; + for state in self.states.values_mut() { + *state = FilterState::NeedsRemote; + } + self.contact_list_timestamp = None; + } } /// We may need to fetch some data from relays before our filter is ready.