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:
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.