notedeck

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

commit 5917bc16fd0c03c6f73c0fabfea46e4304834d7b
parent 18ea05db0ab294d6d0f0aa738054e6804a1cb1ab
Author: kernelkind <kernelkind@gmail.com>
Date:   Tue,  8 Apr 2025 17:48:07 -0400

propagate current account

Signed-off-by: kernelkind <kernelkind@gmail.com>

Diffstat:
Mcrates/enostr/src/keypair.rs | 23+++++++++++++++++++++++
Mcrates/enostr/src/lib.rs | 2+-
Mcrates/notedeck_columns/src/nav.rs | 1+
Mcrates/notedeck_columns/src/timeline/route.rs | 3+++
Mcrates/notedeck_columns/src/ui/note/contents.rs | 19++++++++++++++++---
Mcrates/notedeck_columns/src/ui/note/mod.rs | 39+++++++++++++++++++++++++++++++--------
Mcrates/notedeck_columns/src/ui/note/post.rs | 1+
Mcrates/notedeck_columns/src/ui/note/reply.rs | 15++++++++++-----
Mcrates/notedeck_columns/src/ui/note/reply_description.rs | 4+++-
Mcrates/notedeck_columns/src/ui/profile/mod.rs | 4++++
Mcrates/notedeck_columns/src/ui/search/mod.rs | 5+++++
Mcrates/notedeck_columns/src/ui/thread.rs | 5+++++
Mcrates/notedeck_columns/src/ui/timeline.rs | 19+++++++++++++++++--
13 files changed, 120 insertions(+), 20 deletions(-)

diff --git a/crates/enostr/src/keypair.rs b/crates/enostr/src/keypair.rs @@ -16,6 +16,20 @@ pub struct Keypair { pub secret_key: Option<SecretKey>, } +pub struct KeypairUnowned<'a> { + pub pubkey: &'a Pubkey, + pub secret_key: Option<&'a SecretKey>, +} + +impl<'a> From<&'a Keypair> for KeypairUnowned<'a> { + fn from(value: &'a Keypair) -> Self { + Self { + pubkey: &value.pubkey, + secret_key: value.secret_key.as_ref(), + } + } +} + impl Keypair { pub fn from_secret(secret_key: SecretKey) -> Self { let cloned_secret_key = secret_key.clone(); @@ -70,6 +84,15 @@ impl<'a> FilledKeypair<'a> { } } +impl<'a> From<FilledKeypair<'a>> for KeypairUnowned<'a> { + fn from(value: FilledKeypair<'a>) -> Self { + Self { + pubkey: value.pubkey, + secret_key: Some(value.secret_key), + } + } +} + impl FullKeypair { pub fn new(pubkey: Pubkey, secret_key: SecretKey) -> Self { FullKeypair { pubkey, secret_key } diff --git a/crates/enostr/src/lib.rs b/crates/enostr/src/lib.rs @@ -11,7 +11,7 @@ pub use client::{ClientMessage, EventClientMessage}; pub use error::Error; pub use ewebsock; pub use filter::Filter; -pub use keypair::{FilledKeypair, FullKeypair, Keypair, SerializableKeypair}; +pub use keypair::{FilledKeypair, FullKeypair, Keypair, KeypairUnowned, SerializableKeypair}; pub use nostr::SecretKey; pub use note::{Note, NoteId}; pub use profile::Profile; diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -432,6 +432,7 @@ fn render_nav_body( app.note_options, search_buffer, &mut note_context, + &ctx.accounts.get_selected_account().map(|a| (&a.key).into()), ) .show(ui, ctx.clipboard) .map(RenderNavAction::NoteAction) diff --git a/crates/notedeck_columns/src/timeline/route.rs b/crates/notedeck_columns/src/timeline/route.rs @@ -42,6 +42,7 @@ pub fn render_timeline_route( &accounts.mutefun(), note_context, note_options, + &accounts.get_selected_account().map(|a| (&a.key).into()), ) .ui(ui); @@ -69,6 +70,7 @@ pub fn render_timeline_route( &accounts.mutefun(), note_context, note_options, + &accounts.get_selected_account().map(|a| (&a.key).into()), ) .ui(ui); @@ -83,6 +85,7 @@ pub fn render_timeline_route( note_options, &accounts.mutefun(), note_context, + &accounts.get_selected_account().map(|a| (&a.key).into()), ) .id_source(egui::Id::new(("threadscroll", col))) .ui(ui) diff --git a/crates/notedeck_columns/src/ui/note/contents.rs b/crates/notedeck_columns/src/ui/note/contents.rs @@ -6,6 +6,7 @@ use crate::ui::{ }; use crate::{actionbar::NoteAction, images::ImageType, timeline::TimelineKind}; use egui::{Button, Color32, Hyperlink, Image, Response, RichText, Sense, Window}; +use enostr::KeypairUnowned; use nostrdb::{BlockType, Mention, Ndb, Note, NoteKey, Transaction}; use tracing::warn; @@ -22,6 +23,7 @@ pub struct NoteContext<'d> { pub struct NoteContents<'a, 'd> { note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, txn: &'a Transaction, note: &'a Note<'a>, options: NoteOptions, @@ -32,12 +34,14 @@ impl<'a, 'd> NoteContents<'a, 'd> { #[allow(clippy::too_many_arguments)] pub fn new( note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, txn: &'a Transaction, note: &'a Note, options: ui::note::NoteOptions, ) -> Self { NoteContents { note_context, + cur_acc, txn, note, options, @@ -52,7 +56,14 @@ impl<'a, 'd> NoteContents<'a, 'd> { impl egui::Widget for &mut NoteContents<'_, '_> { fn ui(self, ui: &mut egui::Ui) -> egui::Response { - let result = render_note_contents(ui, self.note_context, self.txn, self.note, self.options); + let result = render_note_contents( + ui, + self.note_context, + self.cur_acc, + self.txn, + self.note, + self.options, + ); self.action = result.action; result.response } @@ -65,6 +76,7 @@ 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, @@ -103,7 +115,7 @@ pub fn render_note_preview( ui.visuals().noninteractive().bg_stroke.color, )) .show(ui, |ui| { - ui::NoteView::new(note_context, &note, note_options) + ui::NoteView::new(note_context, cur_acc, &note, note_options) .actionbar(false) .small_pfp(true) .wide(true) @@ -121,6 +133,7 @@ pub fn render_note_preview( fn render_note_contents( ui: &mut egui::Ui, note_context: &mut NoteContext, + cur_acc: &Option<KeypairUnowned>, txn: &Transaction, note: &Note, options: NoteOptions, @@ -241,7 +254,7 @@ fn render_note_contents( }); let preview_note_action = if let Some((id, _block_str)) = inline_note { - render_note_preview(ui, note_context, txn, id, note_key, options).action + render_note_preview(ui, note_context, cur_acc, txn, id, note_key, options).action } else { None }; diff --git a/crates/notedeck_columns/src/ui/note/mod.rs b/crates/notedeck_columns/src/ui/note/mod.rs @@ -24,7 +24,7 @@ use crate::{ use egui::emath::{pos2, Vec2}; use egui::{Id, Label, Pos2, Rect, Response, RichText, Sense}; -use enostr::{NoteId, Pubkey}; +use enostr::{KeypairUnowned, NoteId, Pubkey}; use nostrdb::{Ndb, Note, NoteKey, Transaction}; use notedeck::{CachedNote, NoteCache, NotedeckTextStyle}; @@ -32,6 +32,7 @@ use super::profile::preview::one_line_display_name_widget; pub struct NoteView<'a, 'd> { note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, parent: Option<NoteKey>, note: &'a nostrdb::Note<'a>, flags: NoteOptions, @@ -72,6 +73,7 @@ impl View for NoteView<'_, '_> { impl<'a, 'd> NoteView<'a, 'd> { pub fn new( note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, note: &'a nostrdb::Note<'a>, mut flags: NoteOptions, ) -> Self { @@ -81,6 +83,7 @@ impl<'a, 'd> NoteView<'a, 'd> { let parent: Option<NoteKey> = None; Self { note_context, + cur_acc, parent, note, flags, @@ -180,6 +183,7 @@ impl<'a, 'd> NoteView<'a, 'd> { ui.add(&mut NoteContents::new( self.note_context, + self.cur_acc, txn, self.note, self.flags, @@ -300,7 +304,7 @@ impl<'a, 'd> NoteView<'a, 'd> { .text_style(style.text_style()), ); }); - NoteView::new(self.note_context, &note_to_repost, self.flags).show(ui) + NoteView::new(self.note_context, self.cur_acc, &note_to_repost, self.flags).show(ui) } else { self.show_standard(ui) } @@ -377,7 +381,14 @@ impl<'a, 'd> NoteView<'a, 'd> { if note_reply.reply().is_some() { let action = ui .horizontal(|ui| { - reply_desc(ui, txn, &note_reply, self.note_context, self.flags) + reply_desc( + ui, + self.cur_acc, + txn, + &note_reply, + self.note_context, + self.flags, + ) }) .inner; @@ -388,7 +399,8 @@ impl<'a, 'd> NoteView<'a, 'd> { }); }); - let mut contents = NoteContents::new(self.note_context, txn, self.note, self.flags); + let mut contents = + NoteContents::new(self.note_context, self.cur_acc, txn, self.note, self.flags); ui.add(&mut contents); @@ -426,8 +438,14 @@ impl<'a, 'd> NoteView<'a, 'd> { .borrow(self.note.tags()); if note_reply.reply().is_some() { - let action = - reply_desc(ui, txn, &note_reply, self.note_context, self.flags); + let action = reply_desc( + ui, + self.cur_acc, + txn, + &note_reply, + self.note_context, + self.flags, + ); if action.is_some() { note_action = action; @@ -435,8 +453,13 @@ impl<'a, 'd> NoteView<'a, 'd> { } }); - let mut contents = - NoteContents::new(self.note_context, txn, self.note, self.flags); + let mut contents = NoteContents::new( + self.note_context, + self.cur_acc, + txn, + self.note, + self.flags, + ); ui.add(&mut contents); if let Some(action) = contents.action() { diff --git a/crates/notedeck_columns/src/ui/note/post.rs b/crates/notedeck_columns/src/ui/note/post.rs @@ -331,6 +331,7 @@ impl<'a, 'd> PostView<'a, 'd> { let resp = render_note_preview( ui, self.note_context, + &Some(self.poster.into()), txn, id.bytes(), nostrdb::NoteKey::new(0), diff --git a/crates/notedeck_columns/src/ui/note/reply.rs b/crates/notedeck_columns/src/ui/note/reply.rs @@ -64,11 +64,16 @@ impl<'a, 'd> PostReplyView<'a, 'd> { let selection = egui::Frame::NONE .outer_margin(egui::Margin::same(note_offset)) .show(ui, |ui| { - ui::NoteView::new(self.note_context, self.note, self.note_options) - .actionbar(false) - .medium_pfp(true) - .options_button(true) - .show(ui) + ui::NoteView::new( + self.note_context, + &Some(self.poster.into()), + self.note, + self.note_options, + ) + .actionbar(false) + .medium_pfp(true) + .options_button(true) + .show(ui) }) .inner .context_selection; diff --git a/crates/notedeck_columns/src/ui/note/reply_description.rs b/crates/notedeck_columns/src/ui/note/reply_description.rs @@ -3,6 +3,7 @@ use crate::{ ui::{self}, }; use egui::{Label, RichText, Sense}; +use enostr::KeypairUnowned; use nostrdb::{Note, NoteReply, Transaction}; use super::{contents::NoteContext, NoteOptions}; @@ -11,6 +12,7 @@ use super::{contents::NoteContext, NoteOptions}; #[profiling::function] pub fn reply_desc( ui: &mut egui::Ui, + cur_acc: &Option<KeypairUnowned>, txn: &Transaction, note_reply: &NoteReply, note_context: &mut NoteContext, @@ -39,7 +41,7 @@ pub fn reply_desc( if r.hovered() { r.on_hover_ui_at_pointer(|ui| { ui.set_max_width(400.0); - ui::NoteView::new(note_context, note, note_options) + ui::NoteView::new(note_context, cur_acc, note, note_options) .actionbar(false) .wide(true) .show(ui); diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -114,6 +114,10 @@ impl<'a, 'd> ProfileView<'a, 'd> { &txn, self.is_muted, self.note_context, + &self + .accounts + .get_selected_account() + .map(|a| (&a.key).into()), ) .show(ui) { diff --git a/crates/notedeck_columns/src/ui/search/mod.rs b/crates/notedeck_columns/src/ui/search/mod.rs @@ -1,4 +1,5 @@ use egui::{vec2, Align, Color32, CornerRadius, RichText, Stroke, TextEdit}; +use enostr::KeypairUnowned; use super::{note::contents::NoteContext, padding}; use crate::{ @@ -21,6 +22,7 @@ pub struct SearchView<'a, 'd> { txn: &'a Transaction, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, } impl<'a, 'd> SearchView<'a, 'd> { @@ -30,6 +32,7 @@ impl<'a, 'd> SearchView<'a, 'd> { note_options: NoteOptions, query: &'a mut SearchQueryState, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, ) -> Self { Self { txn, @@ -37,6 +40,7 @@ impl<'a, 'd> SearchView<'a, 'd> { query, note_options, note_context, + cur_acc, } } @@ -79,6 +83,7 @@ impl<'a, 'd> SearchView<'a, 'd> { self.txn, self.is_muted, self.note_context, + self.cur_acc, ) .show(ui) }) diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs @@ -3,6 +3,7 @@ use crate::{ timeline::{ThreadSelection, TimelineCache, TimelineKind}, }; +use enostr::KeypairUnowned; use nostrdb::Transaction; use notedeck::{MuteFun, RootNoteId, UnknownIds}; use tracing::error; @@ -20,6 +21,7 @@ pub struct ThreadView<'a, 'd> { id_source: egui::Id, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, } impl<'a, 'd> ThreadView<'a, 'd> { @@ -31,6 +33,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { note_options: NoteOptions, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, ) -> Self { let id_source = egui::Id::new("threadscroll_threadview"); ThreadView { @@ -41,6 +44,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { id_source, is_muted, note_context, + cur_acc, } } @@ -108,6 +112,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { &txn, self.is_muted, self.note_context, + self.cur_acc, ) .show(ui) }) diff --git a/crates/notedeck_columns/src/ui/timeline.rs b/crates/notedeck_columns/src/ui/timeline.rs @@ -9,6 +9,7 @@ use crate::{ 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::note::root_note_id_from_selected_id; use notedeck::MuteFun; @@ -25,6 +26,7 @@ pub struct TimelineView<'a, 'd> { reverse: bool, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, } impl<'a, 'd> TimelineView<'a, 'd> { @@ -35,6 +37,7 @@ impl<'a, 'd> TimelineView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, note_options: NoteOptions, + cur_acc: &'a Option<KeypairUnowned<'a>>, ) -> Self { let reverse = false; TimelineView { @@ -44,6 +47,7 @@ impl<'a, 'd> TimelineView<'a, 'd> { reverse, is_muted, note_context, + cur_acc, } } @@ -56,6 +60,7 @@ impl<'a, 'd> TimelineView<'a, 'd> { self.note_options, self.is_muted, self.note_context, + self.cur_acc, ) } @@ -74,6 +79,7 @@ fn timeline_ui( note_options: NoteOptions, is_muted: &MuteFun, note_context: &mut NoteContext, + cur_acc: &Option<KeypairUnowned>, ) -> Option<NoteAction> { //padding(4.0, ui, |ui| ui.heading("Notifications")); /* @@ -151,6 +157,7 @@ fn timeline_ui( &txn, is_muted, note_context, + cur_acc, ) .show(ui) }); @@ -317,6 +324,7 @@ pub struct TimelineTabView<'a, 'd> { txn: &'a Transaction, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, } impl<'a, 'd> TimelineTabView<'a, 'd> { @@ -328,6 +336,7 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { txn: &'a Transaction, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + cur_acc: &'a Option<KeypairUnowned<'a>>, ) -> Self { Self { tab, @@ -336,6 +345,7 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { txn, is_muted, note_context, + cur_acc, } } @@ -382,8 +392,13 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { if !muted { ui::padding(8.0, ui, |ui| { - let resp = - ui::NoteView::new(self.note_context, &note, self.note_options).show(ui); + let resp = ui::NoteView::new( + self.note_context, + self.cur_acc, + &note, + self.note_options, + ) + .show(ui); if let Some(note_action) = resp.action { action = Some(note_action)