From 397bfce8173caa7226551ad80988a26da896ec8d Mon Sep 17 00:00:00 2001 From: kernelkind Date: Mon, 14 Jul 2025 20:42:09 -0400 Subject: [PATCH 1/4] add `Accounts` to `NoteContext` Signed-off-by: kernelkind --- crates/notedeck/src/note/mod.rs | 2 + crates/notedeck_columns/src/nav.rs | 7 +- crates/notedeck_columns/src/timeline/route.rs | 21 ++---- crates/notedeck_columns/src/ui/note/post.rs | 9 +-- crates/notedeck_columns/src/ui/note/reply.rs | 27 ++----- crates/notedeck_columns/src/ui/profile/mod.rs | 8 +- crates/notedeck_columns/src/ui/search/mod.rs | 6 +- crates/notedeck_columns/src/ui/thread.rs | 26 +------ crates/notedeck_columns/src/ui/timeline.rs | 27 +------ crates/notedeck_dave/src/ui/dave.rs | 2 +- crates/notedeck_ui/src/note/contents.rs | 22 ++---- crates/notedeck_ui/src/note/mod.rs | 74 +++++++------------ .../notedeck_ui/src/note/reply_description.rs | 4 +- 13 files changed, 69 insertions(+), 166 deletions(-) diff --git a/crates/notedeck/src/note/mod.rs b/crates/notedeck/src/note/mod.rs index ff4c945..b5b9ee3 100644 --- a/crates/notedeck/src/note/mod.rs +++ b/crates/notedeck/src/note/mod.rs @@ -4,6 +4,7 @@ mod context; pub use action::{MediaAction, NoteAction, ScrollInfo, ZapAction, ZapTargetAmount}; pub use context::{BroadcastContext, ContextSelection, NoteContextSelection}; +use crate::Accounts; use crate::JobPool; use crate::UnknownIds; use crate::{notecache::NoteCache, zaps::Zaps, Images}; @@ -17,6 +18,7 @@ use std::fmt; /// passed to inner UI elements, minimizing prop drilling. pub struct NoteContext<'d> { pub ndb: &'d Ndb, + pub accounts: &'d Accounts, pub img_cache: &'d mut Images, pub note_cache: &'d mut NoteCache, pub zaps: &'d mut Zaps, diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs index 1ca352b..2d9ba7c 100644 --- a/crates/notedeck_columns/src/nav.rs +++ b/crates/notedeck_columns/src/nav.rs @@ -424,8 +424,10 @@ fn render_nav_body( col: usize, inner_rect: egui::Rect, ) -> Option { + let current_account_has_wallet = get_current_wallet(ctx.accounts, ctx.global_wallet).is_some(); let mut note_context = NoteContext { ndb: ctx.ndb, + accounts: ctx.accounts, img_cache: ctx.img_cache, note_cache: ctx.note_cache, zaps: ctx.zaps, @@ -433,12 +435,11 @@ fn render_nav_body( job_pool: ctx.job_pool, unknown_ids: ctx.unknown_ids, clipboard: ctx.clipboard, - current_account_has_wallet: get_current_wallet(ctx.accounts, ctx.global_wallet).is_some(), + current_account_has_wallet, }; match top { Route::Timeline(kind) => render_timeline_route( &mut app.timeline_cache, - ctx.accounts, kind, col, app.note_options, @@ -449,7 +450,6 @@ fn render_nav_body( ), Route::Thread(selection) => render_thread_route( &mut app.threads, - ctx.accounts, selection, col, app.note_options, @@ -602,7 +602,6 @@ fn render_nav_body( app.note_options, search_buffer, &mut note_context, - &(&ctx.accounts.get_selected_account().key).into(), &mut app.jobs, ) .show(ui) diff --git a/crates/notedeck_columns/src/timeline/route.rs b/crates/notedeck_columns/src/timeline/route.rs index 5640a8b..1fd8701 100644 --- a/crates/notedeck_columns/src/timeline/route.rs +++ b/crates/notedeck_columns/src/timeline/route.rs @@ -6,13 +6,12 @@ use crate::{ }; use enostr::Pubkey; -use notedeck::{Accounts, MuteFun, NoteContext}; +use notedeck::{MuteFun, NoteContext}; use notedeck_ui::{jobs::JobsCache, NoteOptions}; #[allow(clippy::too_many_arguments)] pub fn render_timeline_route( timeline_cache: &mut TimelineCache, - accounts: &mut Accounts, kind: &TimelineKind, col: usize, note_options: NoteOptions, @@ -32,10 +31,9 @@ pub fn render_timeline_route( let note_action = ui::TimelineView::new( kind, timeline_cache, - &accounts.mutefun(), + ¬e_context.accounts.mutefun(), note_context, note_options, - &(&accounts.get_selected_account().key).into(), jobs, ) .ui(ui); @@ -47,11 +45,10 @@ pub fn render_timeline_route( if depth > 1 { render_profile_route( pubkey, - accounts, timeline_cache, col, ui, - &accounts.mutefun(), + ¬e_context.accounts.mutefun(), note_options, note_context, jobs, @@ -61,10 +58,9 @@ pub fn render_timeline_route( let note_action = ui::TimelineView::new( kind, timeline_cache, - &accounts.mutefun(), + ¬e_context.accounts.mutefun(), note_context, note_options, - &(&accounts.get_selected_account().key).into(), jobs, ) .ui(ui); @@ -78,7 +74,6 @@ pub fn render_timeline_route( #[allow(clippy::too_many_arguments)] pub fn render_thread_route( threads: &mut Threads, - accounts: &mut Accounts, selection: &ThreadSelection, col: usize, mut note_options: NoteOptions, @@ -94,9 +89,8 @@ pub fn render_thread_route( threads, selection.selected_or_root(), note_options, - &accounts.mutefun(), + ¬e_context.accounts.mutefun(), note_context, - &(&accounts.get_selected_account().key).into(), jobs, ) .id_source(col) @@ -107,7 +101,6 @@ pub fn render_thread_route( #[allow(clippy::too_many_arguments)] pub fn render_profile_route( pubkey: &Pubkey, - accounts: &Accounts, timeline_cache: &mut TimelineCache, col: usize, ui: &mut egui::Ui, @@ -118,7 +111,6 @@ pub fn render_profile_route( ) -> Option { let profile_view = ProfileView::new( pubkey, - accounts, col, timeline_cache, note_options, @@ -130,7 +122,8 @@ pub fn render_profile_route( if let Some(action) = profile_view { match action { - ui::profile::ProfileViewAction::EditProfile => accounts + ui::profile::ProfileViewAction::EditProfile => note_context + .accounts .get_full(pubkey) .map(|kp| RenderNavAction::ProfileAction(ProfileAction::Edit(kp.to_full()))), ui::profile::ProfileViewAction::Note(note_action) => { diff --git a/crates/notedeck_columns/src/ui/note/post.rs b/crates/notedeck_columns/src/ui/note/post.rs index 4940c90..325ae6e 100644 --- a/crates/notedeck_columns/src/ui/note/post.rs +++ b/crates/notedeck_columns/src/ui/note/post.rs @@ -12,7 +12,7 @@ use egui::{ widgets::text_edit::TextEdit, Frame, Layout, Margin, Pos2, ScrollArea, Sense, TextBuffer, }; -use enostr::{FilledKeypair, FullKeypair, KeypairUnowned, NoteId, Pubkey, RelayPool}; +use enostr::{FilledKeypair, FullKeypair, NoteId, Pubkey, RelayPool}; use nostrdb::{Ndb, Transaction}; use notedeck_ui::{ app_images, @@ -352,15 +352,9 @@ impl<'a, 'd> PostView<'a, 'd> { ui.vertical(|ui| { ui.set_max_width(avail_size.x * 0.8); - let zapping_acc = self - .note_context - .current_account_has_wallet - .then(|| KeypairUnowned::from(&self.poster)); - render_note_preview( ui, self.note_context, - zapping_acc.as_ref(), txn, id.bytes(), nostrdb::NoteKey::new(0), @@ -793,6 +787,7 @@ mod preview { let txn = Transaction::new(app.ndb).expect("txn"); let mut note_context = NoteContext { ndb: app.ndb, + accounts: app.accounts, img_cache: app.img_cache, note_cache: app.note_cache, zaps: app.zaps, diff --git a/crates/notedeck_columns/src/ui/note/reply.rs b/crates/notedeck_columns/src/ui/note/reply.rs index 6f797cb..d8b88fb 100644 --- a/crates/notedeck_columns/src/ui/note/reply.rs +++ b/crates/notedeck_columns/src/ui/note/reply.rs @@ -4,7 +4,7 @@ use crate::ui::{ note::{PostAction, PostResponse, PostType}, }; -use enostr::{FilledKeypair, KeypairUnowned, NoteId}; +use enostr::{FilledKeypair, NoteId}; use notedeck::NoteContext; use notedeck_ui::jobs::JobsCache; use notedeck_ui::{NoteOptions, NoteView, ProfilePic}; @@ -67,27 +67,16 @@ impl<'a, 'd> PostReplyView<'a, 'd> { let note_offset: i8 = pfp_offset - ProfilePic::medium_size() / 2 - NoteView::expand_size() / 2; - let zapping_acc = self - .note_context - .current_account_has_wallet - .then(|| KeypairUnowned::from(&self.poster)); - let quoted_note = egui::Frame::NONE .outer_margin(egui::Margin::same(note_offset)) .show(ui, |ui| { - NoteView::new( - self.note_context, - zapping_acc.as_ref(), - self.note, - self.note_options, - self.jobs, - ) - .truncate(false) - .selectable_text(true) - .actionbar(false) - .medium_pfp(true) - .options_button(true) - .show(ui) + NoteView::new(self.note_context, self.note, self.note_options, self.jobs) + .truncate(false) + .selectable_text(true) + .actionbar(false) + .medium_pfp(true) + .options_button(true) + .show(ui) }) .inner; diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs index 51ac11a..f139f06 100644 --- a/crates/notedeck_columns/src/ui/profile/mod.rs +++ b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -12,7 +12,7 @@ use crate::{ ui::timeline::{tabs_ui, TimelineTabView}, }; use notedeck::{ - name::get_display_name, profile::get_profile_url, Accounts, IsFollowing, MuteFun, NoteAction, + name::get_display_name, profile::get_profile_url, IsFollowing, MuteFun, NoteAction, NoteContext, NotedeckTextStyle, }; use notedeck_ui::{ @@ -24,7 +24,6 @@ use notedeck_ui::{ pub struct ProfileView<'a, 'd> { pubkey: &'a Pubkey, - accounts: &'a Accounts, col_id: usize, timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, @@ -44,7 +43,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { #[allow(clippy::too_many_arguments)] pub fn new( pubkey: &'a Pubkey, - accounts: &'a Accounts, col_id: usize, timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, @@ -54,7 +52,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { ) -> Self { ProfileView { pubkey, - accounts, col_id, timeline_cache, note_options, @@ -118,7 +115,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { &txn, self.is_muted, self.note_context, - &(&self.accounts.get_selected_account().key).into(), self.jobs, ) .show(ui) @@ -179,7 +175,7 @@ impl<'a, 'd> ProfileView<'a, 'd> { ui.add_space(24.0); let target_key = self.pubkey; - let selected = self.accounts.get_selected_account(); + let selected = self.note_context.accounts.get_selected_account(); let profile_type = if selected.key.secret_key.is_none() { ProfileType::ReadOnly diff --git a/crates/notedeck_columns/src/ui/search/mod.rs b/crates/notedeck_columns/src/ui/search/mod.rs index 846f742..c3b5d98 100644 --- a/crates/notedeck_columns/src/ui/search/mod.rs +++ b/crates/notedeck_columns/src/ui/search/mod.rs @@ -1,5 +1,5 @@ use egui::{vec2, Align, Color32, CornerRadius, RichText, Stroke, TextEdit}; -use enostr::{KeypairUnowned, NoteId, Pubkey}; +use enostr::{NoteId, Pubkey}; use state::TypingType; use crate::{timeline::TimelineTab, ui::timeline::TimelineTabView}; @@ -27,7 +27,6 @@ pub struct SearchView<'a, 'd> { txn: &'a Transaction, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, } @@ -38,7 +37,6 @@ impl<'a, 'd> SearchView<'a, 'd> { note_options: NoteOptions, query: &'a mut SearchQueryState, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, ) -> Self { Self { @@ -47,7 +45,6 @@ impl<'a, 'd> SearchView<'a, 'd> { query, note_options, note_context, - cur_acc, jobs, } } @@ -157,7 +154,6 @@ impl<'a, 'd> SearchView<'a, 'd> { self.txn, self.is_muted, self.note_context, - self.cur_acc, self.jobs, ) .show(ui) diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs index 5a403e2..7eff883 100644 --- a/crates/notedeck_columns/src/ui/thread.rs +++ b/crates/notedeck_columns/src/ui/thread.rs @@ -1,6 +1,5 @@ use egui::InnerResponse; use egui_virtual_list::VirtualList; -use enostr::KeypairUnowned; use nostrdb::{Note, Transaction}; use notedeck::note::root_note_id_from_selected_id; use notedeck::{MuteFun, NoteAction, NoteContext}; @@ -18,7 +17,6 @@ pub struct ThreadView<'a, 'd> { id_source: egui::Id, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, } @@ -30,7 +28,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { note_options: NoteOptions, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, ) -> Self { let id_source = egui::Id::new("threadscroll_threadview"); @@ -41,7 +38,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { id_source, is_muted, note_context, - cur_acc, jobs, col: 0, } @@ -134,17 +130,11 @@ impl<'a, 'd> ThreadView<'a, 'd> { ui.colored_label(ui.visuals().error_fg_color, "LOADING NOTES"); } - let zapping_acc = self - .note_context - .current_account_has_wallet - .then_some(self.cur_acc); - show_notes( ui, list, ¬es, self.note_context, - zapping_acc, self.note_options, self.jobs, txn, @@ -159,7 +149,6 @@ fn show_notes( list: &mut VirtualList, thread_notes: &ThreadNotes, note_context: &mut NoteContext<'_>, - zapping_acc: Option<&KeypairUnowned<'_>>, flags: NoteOptions, jobs: &mut JobsCache, txn: &Transaction, @@ -190,7 +179,7 @@ fn show_notes( return 1; } - let resp = note.show(note_context, zapping_acc, flags, jobs, ui); + let resp = note.show(note_context, flags, jobs, ui); action = if cur_index == selected_note_index { resp.action.and_then(strip_note_action) @@ -313,21 +302,14 @@ impl<'a> ThreadNote<'a> { fn show( &self, note_context: &'a mut NoteContext<'_>, - zapping_acc: Option<&'a KeypairUnowned<'a>>, flags: NoteOptions, jobs: &'a mut JobsCache, ui: &mut egui::Ui, ) -> NoteResponse { let inner = notedeck_ui::padding(8.0, ui, |ui| { - NoteView::new( - note_context, - zapping_acc, - &self.note, - self.options(flags), - jobs, - ) - .unread_indicator(self.unread_and_have_replies) - .show(ui) + NoteView::new(note_context, &self.note, self.options(flags), jobs) + .unread_indicator(self.unread_and_have_replies) + .show(ui) }); match self.note_type { diff --git a/crates/notedeck_columns/src/ui/timeline.rs b/crates/notedeck_columns/src/ui/timeline.rs index 8ac2366..35c91e7 100644 --- a/crates/notedeck_columns/src/ui/timeline.rs +++ b/crates/notedeck_columns/src/ui/timeline.rs @@ -1,7 +1,6 @@ use egui::containers::scroll_area::ScrollBarVisibility; use egui::{vec2, Direction, Layout, Pos2, Stroke}; use egui_tabs::TabColor; -use enostr::KeypairUnowned; use nostrdb::Transaction; use notedeck::ui::is_narrow; use notedeck_ui::jobs::JobsCache; @@ -22,7 +21,6 @@ pub struct TimelineView<'a, 'd> { reverse: bool, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, } @@ -34,7 +32,6 @@ impl<'a, 'd> TimelineView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, note_options: NoteOptions, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, ) -> Self { let reverse = false; @@ -45,7 +42,6 @@ impl<'a, 'd> TimelineView<'a, 'd> { reverse, is_muted, note_context, - cur_acc, jobs, } } @@ -59,7 +55,6 @@ impl<'a, 'd> TimelineView<'a, 'd> { self.note_options, self.is_muted, self.note_context, - self.cur_acc, self.jobs, ) } @@ -79,7 +74,6 @@ fn timeline_ui( note_options: NoteOptions, is_muted: &MuteFun, note_context: &mut NoteContext, - cur_acc: &KeypairUnowned, jobs: &mut JobsCache, ) -> Option { //padding(4.0, ui, |ui| ui.heading("Notifications")); @@ -169,7 +163,6 @@ fn timeline_ui( &txn, is_muted, note_context, - cur_acc, jobs, ) .show(ui) @@ -354,7 +347,6 @@ pub struct TimelineTabView<'a, 'd> { txn: &'a Transaction, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, } @@ -367,7 +359,6 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { txn: &'a Transaction, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, - cur_acc: &'a KeypairUnowned<'a>, jobs: &'a mut JobsCache, ) -> Self { Self { @@ -377,7 +368,6 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { txn, is_muted, note_context, - cur_acc, jobs, } } @@ -424,21 +414,10 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { }; if !muted { - let zapping_acc = if self.note_context.current_account_has_wallet { - Some(self.cur_acc) - } else { - None - }; - notedeck_ui::padding(8.0, ui, |ui| { - let resp = NoteView::new( - self.note_context, - zapping_acc, - ¬e, - self.note_options, - self.jobs, - ) - .show(ui); + let resp = + NoteView::new(self.note_context, ¬e, self.note_options, self.jobs) + .show(ui); if let Some(note_action) = resp.action { action = Some(note_action) diff --git a/crates/notedeck_dave/src/ui/dave.rs b/crates/notedeck_dave/src/ui/dave.rs index 57f1e11..71cfe07 100644 --- a/crates/notedeck_dave/src/ui/dave.rs +++ b/crates/notedeck_dave/src/ui/dave.rs @@ -211,6 +211,7 @@ impl<'a> DaveUi<'a> { ) -> Option { let mut note_context = NoteContext { ndb: ctx.ndb, + accounts: ctx.accounts, img_cache: ctx.img_cache, note_cache: ctx.note_cache, zaps: ctx.zaps, @@ -243,7 +244,6 @@ impl<'a> DaveUi<'a> { |ui| { notedeck_ui::NoteView::new( &mut note_context, - None, ¬e, NoteOptions::default(), jobs, diff --git a/crates/notedeck_ui/src/note/contents.rs b/crates/notedeck_ui/src/note/contents.rs index e68f1a5..fb7bf93 100644 --- a/crates/notedeck_ui/src/note/contents.rs +++ b/crates/notedeck_ui/src/note/contents.rs @@ -8,7 +8,6 @@ use crate::{ }; use egui::{Color32, Hyperlink, RichText}; -use enostr::KeypairUnowned; use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction}; use tracing::warn; @@ -18,7 +17,6 @@ use super::media::{find_renderable_media, image_carousel, RenderableMedia}; pub struct NoteContents<'a, 'd> { note_context: &'a mut NoteContext<'d>, - cur_acc: Option<&'a KeypairUnowned<'a>>, txn: &'a Transaction, note: &'a Note<'a>, options: NoteOptions, @@ -30,7 +28,6 @@ impl<'a, 'd> NoteContents<'a, 'd> { #[allow(clippy::too_many_arguments)] pub fn new( note_context: &'a mut NoteContext<'d>, - cur_acc: Option<&'a KeypairUnowned<'a>>, txn: &'a Transaction, note: &'a Note, options: NoteOptions, @@ -38,7 +35,6 @@ impl<'a, 'd> NoteContents<'a, 'd> { ) -> Self { NoteContents { note_context, - cur_acc, txn, note, options, @@ -53,7 +49,6 @@ impl egui::Widget for &mut NoteContents<'_, '_> { let result = render_note_contents( ui, self.note_context, - self.cur_acc, self.txn, self.note, self.options, @@ -71,7 +66,6 @@ impl egui::Widget for &mut NoteContents<'_, '_> { pub fn render_note_preview( ui: &mut egui::Ui, note_context: &mut NoteContext, - cur_acc: Option<&KeypairUnowned>, txn: &Transaction, id: &[u8; 32], parent: NoteKey, @@ -105,7 +99,7 @@ pub fn render_note_preview( */ }; - NoteView::new(note_context, cur_acc, ¬e, note_options, jobs) + NoteView::new(note_context, ¬e, note_options, jobs) .preview_style() .parent(parent) .show(ui) @@ -116,7 +110,6 @@ pub fn render_note_preview( pub fn render_note_contents( ui: &mut egui::Ui, note_context: &mut NoteContext, - cur_acc: Option<&KeypairUnowned>, txn: &Transaction, note: &Note, options: NoteOptions, @@ -275,7 +268,7 @@ pub fn render_note_contents( }); let preview_note_action = inline_note.and_then(|(id, _)| { - render_note_preview(ui, note_context, cur_acc, txn, id, note_key, options, jobs) + render_note_preview(ui, note_context, txn, id, note_key, options, jobs) .action .map(|a| match a { NoteAction::Note { note_id, .. } => NoteAction::Note { @@ -291,12 +284,11 @@ pub fn render_note_contents( ui.add_space(2.0); let carousel_id = egui::Id::new(("carousel", note.key().expect("expected tx note"))); - let trusted_media = trust_media_from_pk2( - note_context.ndb, - txn, - cur_acc.as_ref().map(|k| k.pubkey.bytes()), - note.pubkey(), - ); + let zapping_acc = { + let cur_acc = note_context.accounts.get_selected_account(); + cur_acc.wallet.as_ref().map(|_| cur_acc.key.pubkey.bytes()) + }; + let trusted_media = trust_media_from_pk2(note_context.ndb, txn, zapping_acc, note.pubkey()); media_action = image_carousel( ui, diff --git a/crates/notedeck_ui/src/note/mod.rs b/crates/notedeck_ui/src/note/mod.rs index cedcbb4..6e64e3e 100644 --- a/crates/notedeck_ui/src/note/mod.rs +++ b/crates/notedeck_ui/src/note/mod.rs @@ -33,7 +33,6 @@ use notedeck::{ pub struct NoteView<'a, 'd> { note_context: &'a mut NoteContext<'d>, - zapping_acc: Option<&'a KeypairUnowned<'a>>, parent: Option, note: &'a nostrdb::Note<'a>, framed: bool, @@ -85,7 +84,6 @@ impl egui::Widget for &mut NoteView<'_, '_> { impl<'a, 'd> NoteView<'a, 'd> { pub fn new( note_context: &'a mut NoteContext<'d>, - zapping_acc: Option<&'a KeypairUnowned<'a>>, note: &'a nostrdb::Note<'a>, mut flags: NoteOptions, jobs: &'a mut JobsCache, @@ -98,7 +96,6 @@ impl<'a, 'd> NoteView<'a, 'd> { Self { note_context, - zapping_acc, parent, note, flags, @@ -231,7 +228,6 @@ impl<'a, 'd> NoteView<'a, 'd> { ui.add(&mut NoteContents::new( self.note_context, - self.zapping_acc, txn, self.note, self.flags, @@ -317,14 +313,7 @@ impl<'a, 'd> NoteView<'a, 'd> { .text_style(style.text_style()), ); }); - NoteView::new( - self.note_context, - self.zapping_acc, - ¬e_to_repost, - self.flags, - self.jobs, - ) - .show(ui) + NoteView::new(self.note_context, ¬e_to_repost, self.flags, self.jobs).show(ui) } pub fn show_impl(&mut self, ui: &mut egui::Ui) -> NoteResponse { @@ -440,7 +429,6 @@ impl<'a, 'd> NoteView<'a, 'd> { ui.horizontal(|ui| { note_action = reply_desc( ui, - self.zapping_acc, txn, ¬e_reply, self.note_context, @@ -455,32 +443,27 @@ impl<'a, 'd> NoteView<'a, 'd> { }) .inner; - let mut contents = NoteContents::new( - self.note_context, - self.zapping_acc, - txn, - self.note, - self.flags, - self.jobs, - ); + let mut contents = + NoteContents::new(self.note_context, txn, self.note, self.flags, self.jobs); ui.add(&mut contents); note_action = contents.action.or(note_action); if self.options().has(NoteOptions::ActionBar) { - note_action = render_note_actionbar( - ui, - self.zapping_acc.as_ref().map(|c| Zapper { + let zapper = { + let cur_acc = self.note_context.accounts.get_selected_account(); + let has_wallet = cur_acc.wallet.is_some(); + + has_wallet.then_some(Zapper { zaps: self.note_context.zaps, - cur_acc: c, - }), - self.note.id(), - self.note.pubkey(), - note_key, - ) - .inner - .or(note_action); + cur_acc: cur_acc.keypair(), + }) + }; + note_action = + render_note_actionbar(ui, zapper, self.note.id(), self.note.pubkey(), note_key) + .inner + .or(note_action); } NoteUiResponse { @@ -527,7 +510,6 @@ impl<'a, 'd> NoteView<'a, 'd> { note_action = reply_desc( ui, - self.zapping_acc, txn, ¬e_reply, self.note_context, @@ -537,25 +519,25 @@ impl<'a, 'd> NoteView<'a, 'd> { .or(note_action.take()); }); - let mut contents = NoteContents::new( - self.note_context, - self.zapping_acc, - txn, - self.note, - self.flags, - self.jobs, - ); + let mut contents = + NoteContents::new(self.note_context, txn, self.note, self.flags, self.jobs); ui.add(&mut contents); note_action = contents.action.or(note_action); + let zapper = { + let cur_acc = self.note_context.accounts.get_selected_account(); + let has_wallet = cur_acc.wallet.is_some(); + + has_wallet.then_some(Zapper { + zaps: self.note_context.zaps, + cur_acc: cur_acc.keypair(), + }) + }; if self.options().has(NoteOptions::ActionBar) { note_action = render_note_actionbar( ui, - self.zapping_acc.as_ref().map(|c| Zapper { - zaps: self.note_context.zaps, - cur_acc: c, - }), + zapper, self.note.id(), self.note.pubkey(), note_key, @@ -774,7 +756,7 @@ fn note_hitbox_clicked( struct Zapper<'a> { zaps: &'a Zaps, - cur_acc: &'a KeypairUnowned<'a>, + cur_acc: KeypairUnowned<'a>, } #[profiling::function] diff --git a/crates/notedeck_ui/src/note/reply_description.rs b/crates/notedeck_ui/src/note/reply_description.rs index 43c459c..3e49c00 100644 --- a/crates/notedeck_ui/src/note/reply_description.rs +++ b/crates/notedeck_ui/src/note/reply_description.rs @@ -3,14 +3,12 @@ use nostrdb::{Note, NoteReply, Transaction}; use super::NoteOptions; use crate::{jobs::JobsCache, note::NoteView, Mention}; -use enostr::KeypairUnowned; use notedeck::{NoteAction, NoteContext}; #[must_use = "Please handle the resulting note action"] #[profiling::function] pub fn reply_desc( ui: &mut egui::Ui, - cur_acc: Option<&KeypairUnowned>, txn: &Transaction, note_reply: &NoteReply, note_context: &mut NoteContext, @@ -43,7 +41,7 @@ pub fn reply_desc( if r.hovered() { r.on_hover_ui_at_pointer(|ui| { ui.set_max_width(400.0); - NoteView::new(note_context, cur_acc, note, note_options, jobs) + NoteView::new(note_context, note, note_options, jobs) .actionbar(false) .wide(true) .show(ui); From a7f5319fdeab57b8cc95e34b1b3bb827187de324 Mon Sep 17 00:00:00 2001 From: kernelkind Date: Mon, 14 Jul 2025 21:00:06 -0400 Subject: [PATCH 2/4] remove `MuteFun` prop Signed-off-by: kernelkind --- crates/notedeck_columns/src/nav.rs | 1 - crates/notedeck_columns/src/timeline/route.rs | 30 +++++-------------- crates/notedeck_columns/src/ui/profile/mod.rs | 8 ++--- crates/notedeck_columns/src/ui/search/mod.rs | 6 +--- crates/notedeck_columns/src/ui/thread.rs | 9 ++---- crates/notedeck_columns/src/ui/timeline.rs | 13 ++------ 6 files changed, 15 insertions(+), 52 deletions(-) diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs index 2d9ba7c..8159af5 100644 --- a/crates/notedeck_columns/src/nav.rs +++ b/crates/notedeck_columns/src/nav.rs @@ -598,7 +598,6 @@ fn render_nav_body( SearchView::new( &txn, - &ctx.accounts.mutefun(), app.note_options, search_buffer, &mut note_context, diff --git a/crates/notedeck_columns/src/timeline/route.rs b/crates/notedeck_columns/src/timeline/route.rs index 1fd8701..feae00d 100644 --- a/crates/notedeck_columns/src/timeline/route.rs +++ b/crates/notedeck_columns/src/timeline/route.rs @@ -6,7 +6,7 @@ use crate::{ }; use enostr::Pubkey; -use notedeck::{MuteFun, NoteContext}; +use notedeck::NoteContext; use notedeck_ui::{jobs::JobsCache, NoteOptions}; #[allow(clippy::too_many_arguments)] @@ -28,15 +28,9 @@ pub fn render_timeline_route( | TimelineKind::Universe | TimelineKind::Hashtag(_) | TimelineKind::Generic(_) => { - let note_action = ui::TimelineView::new( - kind, - timeline_cache, - ¬e_context.accounts.mutefun(), - note_context, - note_options, - jobs, - ) - .ui(ui); + let note_action = + ui::TimelineView::new(kind, timeline_cache, note_context, note_options, jobs) + .ui(ui); note_action.map(RenderNavAction::NoteAction) } @@ -48,22 +42,15 @@ pub fn render_timeline_route( timeline_cache, col, ui, - ¬e_context.accounts.mutefun(), note_options, note_context, jobs, ) } else { // we render profiles like timelines if they are at the root - let note_action = ui::TimelineView::new( - kind, - timeline_cache, - ¬e_context.accounts.mutefun(), - note_context, - note_options, - jobs, - ) - .ui(ui); + let note_action = + ui::TimelineView::new(kind, timeline_cache, note_context, note_options, jobs) + .ui(ui); note_action.map(RenderNavAction::NoteAction) } @@ -89,7 +76,6 @@ pub fn render_thread_route( threads, selection.selected_or_root(), note_options, - ¬e_context.accounts.mutefun(), note_context, jobs, ) @@ -104,7 +90,6 @@ pub fn render_profile_route( timeline_cache: &mut TimelineCache, col: usize, ui: &mut egui::Ui, - is_muted: &MuteFun, note_options: NoteOptions, note_context: &mut NoteContext, jobs: &mut JobsCache, @@ -114,7 +99,6 @@ pub fn render_profile_route( col, timeline_cache, note_options, - is_muted, note_context, jobs, ) diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs index f139f06..6f9e785 100644 --- a/crates/notedeck_columns/src/ui/profile/mod.rs +++ b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -12,8 +12,8 @@ use crate::{ ui::timeline::{tabs_ui, TimelineTabView}, }; use notedeck::{ - name::get_display_name, profile::get_profile_url, IsFollowing, MuteFun, NoteAction, - NoteContext, NotedeckTextStyle, + name::get_display_name, profile::get_profile_url, IsFollowing, NoteAction, NoteContext, + NotedeckTextStyle, }; use notedeck_ui::{ app_images, @@ -27,7 +27,6 @@ pub struct ProfileView<'a, 'd> { col_id: usize, timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, } @@ -46,7 +45,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { col_id: usize, timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, ) -> Self { @@ -55,7 +53,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { col_id, timeline_cache, note_options, - is_muted, note_context, jobs, } @@ -113,7 +110,6 @@ impl<'a, 'd> ProfileView<'a, 'd> { reversed, self.note_options, &txn, - self.is_muted, self.note_context, self.jobs, ) diff --git a/crates/notedeck_columns/src/ui/search/mod.rs b/crates/notedeck_columns/src/ui/search/mod.rs index c3b5d98..4540111 100644 --- a/crates/notedeck_columns/src/ui/search/mod.rs +++ b/crates/notedeck_columns/src/ui/search/mod.rs @@ -5,7 +5,7 @@ use state::TypingType; use crate::{timeline::TimelineTab, ui::timeline::TimelineTabView}; use egui_winit::clipboard::Clipboard; use nostrdb::{Filter, Ndb, Transaction}; -use notedeck::{MuteFun, NoteAction, NoteContext, NoteRef}; +use notedeck::{NoteAction, NoteContext, NoteRef}; use notedeck_ui::{ context_menu::{input_context, PasteBehavior}, icons::search_icon, @@ -25,7 +25,6 @@ pub struct SearchView<'a, 'd> { query: &'a mut SearchQueryState, note_options: NoteOptions, txn: &'a Transaction, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, } @@ -33,7 +32,6 @@ pub struct SearchView<'a, 'd> { impl<'a, 'd> SearchView<'a, 'd> { pub fn new( txn: &'a Transaction, - is_muted: &'a MuteFun, note_options: NoteOptions, query: &'a mut SearchQueryState, note_context: &'a mut NoteContext<'d>, @@ -41,7 +39,6 @@ impl<'a, 'd> SearchView<'a, 'd> { ) -> Self { Self { txn, - is_muted, query, note_options, note_context, @@ -152,7 +149,6 @@ impl<'a, 'd> SearchView<'a, 'd> { reversed, self.note_options, self.txn, - self.is_muted, self.note_context, self.jobs, ) diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs index 7eff883..f74a133 100644 --- a/crates/notedeck_columns/src/ui/thread.rs +++ b/crates/notedeck_columns/src/ui/thread.rs @@ -2,7 +2,7 @@ use egui::InnerResponse; use egui_virtual_list::VirtualList; use nostrdb::{Note, Transaction}; use notedeck::note::root_note_id_from_selected_id; -use notedeck::{MuteFun, NoteAction, NoteContext}; +use notedeck::{NoteAction, NoteContext}; use notedeck_ui::jobs::JobsCache; use notedeck_ui::note::NoteResponse; use notedeck_ui::{NoteOptions, NoteView}; @@ -15,7 +15,6 @@ pub struct ThreadView<'a, 'd> { note_options: NoteOptions, col: usize, id_source: egui::Id, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, } @@ -26,7 +25,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { threads: &'a mut Threads, selected_note_id: &'a [u8; 32], note_options: NoteOptions, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, ) -> Self { @@ -36,7 +34,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { selected_note_id, note_options, id_source, - is_muted, note_context, jobs, col: 0, @@ -138,7 +135,6 @@ impl<'a, 'd> ThreadView<'a, 'd> { self.note_options, self.jobs, txn, - self.is_muted, ) } } @@ -152,7 +148,6 @@ fn show_notes( flags: NoteOptions, jobs: &mut JobsCache, txn: &Transaction, - is_muted: &MuteFun, ) -> Option { let mut action = None; @@ -162,6 +157,8 @@ fn show_notes( let selected_note_index = thread_notes.selected_index; let notes = &thread_notes.notes; + let is_muted = note_context.accounts.mutefun(); + list.ui_custom_layout(ui, notes.len(), |ui, cur_index| { let note = ¬es[cur_index]; diff --git a/crates/notedeck_columns/src/ui/timeline.rs b/crates/notedeck_columns/src/ui/timeline.rs index 35c91e7..0d8ed56 100644 --- a/crates/notedeck_columns/src/ui/timeline.rs +++ b/crates/notedeck_columns/src/ui/timeline.rs @@ -8,7 +8,7 @@ use std::f32::consts::PI; use tracing::{error, warn}; use crate::timeline::{TimelineCache, TimelineKind, TimelineTab, ViewFilter}; -use notedeck::{note::root_note_id_from_selected_id, MuteFun, NoteAction, NoteContext, ScrollInfo}; +use notedeck::{note::root_note_id_from_selected_id, NoteAction, NoteContext, ScrollInfo}; use notedeck_ui::{ anim::{AnimationHelper, ICON_EXPANSION_MULTIPLE}, show_pointer, NoteOptions, NoteView, @@ -19,7 +19,6 @@ pub struct TimelineView<'a, 'd> { timeline_cache: &'a mut TimelineCache, note_options: NoteOptions, reverse: bool, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, } @@ -29,7 +28,6 @@ impl<'a, 'd> TimelineView<'a, 'd> { pub fn new( timeline_id: &'a TimelineKind, timeline_cache: &'a mut TimelineCache, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, note_options: NoteOptions, jobs: &'a mut JobsCache, @@ -40,7 +38,6 @@ impl<'a, 'd> TimelineView<'a, 'd> { timeline_cache, note_options, reverse, - is_muted, note_context, jobs, } @@ -53,7 +50,6 @@ impl<'a, 'd> TimelineView<'a, 'd> { self.timeline_cache, self.reverse, self.note_options, - self.is_muted, self.note_context, self.jobs, ) @@ -72,7 +68,6 @@ fn timeline_ui( timeline_cache: &mut TimelineCache, reversed: bool, note_options: NoteOptions, - is_muted: &MuteFun, note_context: &mut NoteContext, jobs: &mut JobsCache, ) -> Option { @@ -161,7 +156,6 @@ fn timeline_ui( reversed, note_options, &txn, - is_muted, note_context, jobs, ) @@ -345,7 +339,6 @@ pub struct TimelineTabView<'a, 'd> { reversed: bool, note_options: NoteOptions, txn: &'a Transaction, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, } @@ -357,7 +350,6 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { reversed: bool, note_options: NoteOptions, txn: &'a Transaction, - is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, jobs: &'a mut JobsCache, ) -> Self { @@ -366,7 +358,6 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { reversed, note_options, txn, - is_muted, note_context, jobs, } @@ -376,7 +367,7 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { let mut action: Option = None; let len = self.tab.notes.len(); - let is_muted = self.is_muted; + let is_muted = self.note_context.accounts.mutefun(); self.tab .list From 142aa879c3db8147f6f0697bfebe681ff405c73b Mon Sep 17 00:00:00 2001 From: kernelkind Date: Mon, 14 Jul 2025 21:14:01 -0400 Subject: [PATCH 3/4] make `Contacts::is_following` use bytes instead of `Pubkey` Signed-off-by: kernelkind --- crates/notedeck/src/account/contacts.rs | 4 ++-- crates/notedeck/src/user_account.rs | 6 +++--- crates/notedeck_columns/src/ui/profile/mod.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/notedeck/src/account/contacts.rs b/crates/notedeck/src/account/contacts.rs index 32e8060..0a7136a 100644 --- a/crates/notedeck/src/account/contacts.rs +++ b/crates/notedeck/src/account/contacts.rs @@ -49,14 +49,14 @@ impl Contacts { update_state(&mut self.state, &res.note, res.note_key); } - pub fn is_following(&self, other: &Pubkey) -> IsFollowing { + pub fn is_following(&self, other_pubkey: &[u8; 32]) -> IsFollowing { match &self.state { ContactState::Unreceived => IsFollowing::Unknown, ContactState::Received { contacts, note_key: _, } => { - if contacts.contains(other) { + if contacts.contains(other_pubkey) { IsFollowing::Yes } else { IsFollowing::No diff --git a/crates/notedeck/src/user_account.rs b/crates/notedeck/src/user_account.rs index 73bdfa5..9192e55 100644 --- a/crates/notedeck/src/user_account.rs +++ b/crates/notedeck/src/user_account.rs @@ -1,4 +1,4 @@ -use enostr::{Keypair, KeypairUnowned, Pubkey}; +use enostr::{Keypair, KeypairUnowned}; use tokenator::{ParseError, TokenParser, TokenSerializable}; use crate::{ @@ -33,8 +33,8 @@ impl UserAccount { self } - pub fn is_following(&self, pk: &Pubkey) -> IsFollowing { - self.data.contacts.is_following(pk) + pub fn is_following(&self, other_pubkey: &[u8; 32]) -> IsFollowing { + self.data.contacts.is_following(other_pubkey) } } diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs index 6f9e785..c79186b 100644 --- a/crates/notedeck_columns/src/ui/profile/mod.rs +++ b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -178,7 +178,7 @@ impl<'a, 'd> ProfileView<'a, 'd> { } else if &selected.key.pubkey == self.pubkey { ProfileType::MyProfile } else { - ProfileType::Followable(selected.is_following(target_key)) + ProfileType::Followable(selected.is_following(target_key.bytes())) }; match profile_type { From efae62024e6e054f20e38a2aea39dcef7b84e704 Mon Sep 17 00:00:00 2001 From: kernelkind Date: Mon, 14 Jul 2025 21:14:37 -0400 Subject: [PATCH 4/4] migrate to check following through `Contacts::is_following` Signed-off-by: kernelkind --- crates/notedeck_ui/src/contacts.rs | 55 +------------------------ crates/notedeck_ui/src/note/contents.rs | 13 +++--- 2 files changed, 7 insertions(+), 61 deletions(-) diff --git a/crates/notedeck_ui/src/contacts.rs b/crates/notedeck_ui/src/contacts.rs index 9c7d207..0a1d730 100644 --- a/crates/notedeck_ui/src/contacts.rs +++ b/crates/notedeck_ui/src/contacts.rs @@ -1,58 +1,5 @@ -use nostrdb::{Filter, Ndb, Note, Transaction}; - -fn pk1_is_following_pk2( - ndb: &Ndb, - txn: &Transaction, - pk1: &[u8; 32], - pk2: &[u8; 32], -) -> Option { - let note = get_contacts_note(ndb, txn, pk1)?; - - Some(note_follows(note, pk2)) -} - -pub fn trust_media_from_pk2( - ndb: &Ndb, - txn: &Transaction, - pk1: Option<&[u8; 32]>, - pk2: &[u8; 32], -) -> bool { - pk1.map(|pk| pk == pk2 || pk1_is_following_pk2(ndb, txn, pk, pk2).unwrap_or(false)) - .unwrap_or(false) -} - -fn get_contacts_note<'a>(ndb: &'a Ndb, txn: &'a Transaction, user: &[u8; 32]) -> Option> { - Some( - ndb.query(txn, &[contacts_filter(user)], 1) - .ok()? - .first()? - .note - .clone(), - ) -} +use nostrdb::Filter; pub fn contacts_filter(pk: &[u8; 32]) -> Filter { Filter::new().authors([pk]).kinds([3]).limit(1).build() } - -fn note_follows(contacts_note: Note<'_>, pk: &[u8; 32]) -> bool { - for tag in contacts_note.tags() { - if tag.count() < 2 { - continue; - } - - let Some("p") = tag.get_str(0) else { - continue; - }; - - let Some(author) = tag.get_id(1) else { - continue; - }; - - if pk == author { - return true; - } - } - - false -} diff --git a/crates/notedeck_ui/src/note/contents.rs b/crates/notedeck_ui/src/note/contents.rs index fb7bf93..ee28504 100644 --- a/crates/notedeck_ui/src/note/contents.rs +++ b/crates/notedeck_ui/src/note/contents.rs @@ -2,7 +2,6 @@ use std::cell::OnceCell; use crate::{ blur::imeta_blurhashes, - contacts::trust_media_from_pk2, jobs::JobsCache, note::{NoteAction, NoteOptions, NoteResponse, NoteView}, }; @@ -11,7 +10,7 @@ use egui::{Color32, Hyperlink, RichText}; use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction}; use tracing::warn; -use notedeck::NoteContext; +use notedeck::{IsFollowing, NoteContext}; use super::media::{find_renderable_media, image_carousel, RenderableMedia}; @@ -284,11 +283,11 @@ pub fn render_note_contents( ui.add_space(2.0); let carousel_id = egui::Id::new(("carousel", note.key().expect("expected tx note"))); - let zapping_acc = { - let cur_acc = note_context.accounts.get_selected_account(); - cur_acc.wallet.as_ref().map(|_| cur_acc.key.pubkey.bytes()) - }; - let trusted_media = trust_media_from_pk2(note_context.ndb, txn, zapping_acc, note.pubkey()); + let trusted_media = note_context + .accounts + .get_selected_account() + .is_following(note.pubkey()) + == IsFollowing::Yes; media_action = image_carousel( ui,