diff --git a/crates/notedeck/src/filter.rs b/crates/notedeck/src/filter.rs index 1b470a2..214a870 100644 --- a/crates/notedeck/src/filter.rs +++ b/crates/notedeck/src/filter.rs @@ -192,13 +192,14 @@ impl FilteredTags { /// Create a filter from tags. This can be used to create a filter /// from a contact list -pub fn filter_from_tags(note: &Note) -> Result { +pub fn filter_from_tags(note: &Note, add_pubkey: Option<&[u8; 32]>) -> Result { let mut author_filter = Filter::new(); let mut hashtag_filter = Filter::new(); let mut author_res: Option = None; let mut hashtag_res: Option = None; let mut author_count = 0i32; let mut hashtag_count = 0i32; + let mut has_added_pubkey = false; let tags = note.tags(); @@ -223,6 +224,13 @@ pub fn filter_from_tags(note: &Note) -> Result { continue; }; + if let Some(pk) = add_pubkey { + if author == pk { + // we don't need to add it afterwards + has_added_pubkey = true; + } + } + author_filter.add_id_element(author)?; author_count += 1; } else if t == "t" { @@ -237,6 +245,14 @@ pub fn filter_from_tags(note: &Note) -> Result { } } + // some additional ad-hoc logic for adding a pubkey + if let Some(pk) = add_pubkey { + if !has_added_pubkey { + author_filter.add_id_element(pk)?; + author_count += 1; + } + } + author_filter.end_field(); hashtag_filter.end_field(); diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs index e2b083f..7456f20 100644 --- a/crates/notedeck_columns/src/app.rs +++ b/crates/notedeck_columns/src/app.rs @@ -141,6 +141,11 @@ fn try_process_event( app_ctx.note_cache, timeline, &app_ctx.accounts.mutefun(), + app_ctx + .accounts + .get_selected_account() + .as_ref() + .map(|sa| &sa.pubkey), ) }; diff --git a/crates/notedeck_columns/src/timeline/kind.rs b/crates/notedeck_columns/src/timeline/kind.rs index 30acec4..86ae688 100644 --- a/crates/notedeck_columns/src/timeline/kind.rs +++ b/crates/notedeck_columns/src/timeline/kind.rs @@ -25,6 +25,13 @@ impl PubkeySource { PubkeySource::DeckAuthor => deck_author, } } + + pub fn to_pubkey_bytes<'a>(&'a self, deck_author: &'a [u8; 32]) -> &'a [u8; 32] { + match self { + PubkeySource::Explicit(pk) => pk.bytes(), + PubkeySource::DeckAuthor => deck_author, + } + } } impl ListKind { @@ -177,7 +184,7 @@ impl TimelineKind { )); } - match Timeline::contact_list(&results[0].note, pk_src.clone()) { + match Timeline::contact_list(&results[0].note, pk_src.clone(), default_user) { Err(Error::App(notedeck::Error::Filter(FilterError::EmptyContactList))) => { Some(Timeline::new( TimelineKind::contact_list(pk_src), diff --git a/crates/notedeck_columns/src/timeline/mod.rs b/crates/notedeck_columns/src/timeline/mod.rs index e60d02c..d91b95d 100644 --- a/crates/notedeck_columns/src/timeline/mod.rs +++ b/crates/notedeck_columns/src/timeline/mod.rs @@ -15,7 +15,7 @@ use std::fmt; use std::sync::atomic::{AtomicU32, Ordering}; use egui_virtual_list::VirtualList; -use enostr::{Relay, RelayPool}; +use enostr::{Pubkey, Relay, RelayPool}; use nostrdb::{Filter, Ndb, Note, Subscription, Transaction}; use std::cell::RefCell; use std::hash::Hash; @@ -187,8 +187,13 @@ pub struct Timeline { impl Timeline { /// Create a timeline from a contact list - pub fn contact_list(contact_list: &Note, pk_src: PubkeySource) -> Result { - let filter = filter::filter_from_tags(contact_list)?.into_follow_filter(); + pub fn contact_list( + contact_list: &Note, + pk_src: PubkeySource, + deck_author: Option<&[u8; 32]>, + ) -> Result { + let our_pubkey = deck_author.map(|da| pk_src.to_pubkey_bytes(da)); + let filter = filter::filter_from_tags(contact_list, our_pubkey)?.into_follow_filter(); Ok(Timeline::new( TimelineKind::contact_list(pk_src), @@ -388,6 +393,7 @@ pub fn merge_sorted_vecs(vec1: &[T], vec2: &[T]) -> (Vec, Merg /// /// We do this by maintaining this sub_id in the filter state, even when /// in the ready state. See: [`FilterReady`] +#[allow(clippy::too_many_arguments)] pub fn setup_new_timeline( timeline: &mut Timeline, ndb: &Ndb, @@ -396,9 +402,10 @@ pub fn setup_new_timeline( note_cache: &mut NoteCache, since_optimize: bool, is_muted: &MuteFun, + our_pk: Option<&Pubkey>, ) { // if we're ready, setup local subs - if is_timeline_ready(ndb, pool, note_cache, timeline, is_muted) { + if is_timeline_ready(ndb, pool, note_cache, timeline, is_muted, our_pk) { if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline, is_muted) { error!("setup_new_timeline: {err}"); } @@ -627,6 +634,7 @@ pub fn is_timeline_ready( note_cache: &mut NoteCache, timeline: &mut Timeline, is_muted: &MuteFun, + our_pk: Option<&Pubkey>, ) -> bool { // TODO: we should debounce the filter states a bit to make sure we have // seen all of the different contact lists from each relay @@ -658,7 +666,12 @@ pub fn is_timeline_ready( let filter = { let txn = Transaction::new(ndb).expect("txn"); let note = ndb.get_note_by_key(&txn, note_key).expect("note"); - filter::filter_from_tags(¬e).map(|f| f.into_follow_filter()) + let add_pk = timeline + .kind + .pubkey_source() + .as_ref() + .and_then(|pk_src| our_pk.map(|pk| pk_src.to_pubkey_bytes(pk))); + filter::filter_from_tags(¬e, add_pk).map(|f| f.into_follow_filter()) }; // TODO: into_follow_filter is hardcoded to contact lists, let's generalize diff --git a/crates/notedeck_columns/src/ui/add_column.rs b/crates/notedeck_columns/src/ui/add_column.rs index 388382b..09fe9b0 100644 --- a/crates/notedeck_columns/src/ui/add_column.rs +++ b/crates/notedeck_columns/src/ui/add_column.rs @@ -504,6 +504,10 @@ pub fn render_add_column_routes( ctx.note_cache, app.since_optimize, &ctx.accounts.mutefun(), + ctx.accounts + .get_selected_account() + .as_ref() + .map(|sa| &sa.pubkey), ); app.columns_mut(ctx.accounts) .add_timeline_to_column(col, timeline);