From 6fa6a5733ea7a1750f0fbde0fab5acfba803e5db Mon Sep 17 00:00:00 2001 From: William Casarin Date: Wed, 18 Dec 2024 23:16:02 -0800 Subject: [PATCH] timeline: auto-add yourself to your home timeline This is the most intuitive, and damus iOS does the same thing. You have to follow yourself, sorry. Otherwise you won't see your posts when you post which is confusing. Fixes: https://github.com/damus-io/notedeck/issues/509 --- crates/notedeck/src/filter.rs | 18 ++++++++++++++- crates/notedeck_columns/src/app.rs | 5 +++++ crates/notedeck_columns/src/timeline/kind.rs | 9 +++++++- crates/notedeck_columns/src/timeline/mod.rs | 23 +++++++++++++++----- crates/notedeck_columns/src/ui/add_column.rs | 4 ++++ 5 files changed, 52 insertions(+), 7 deletions(-) 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);