notedeck

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

commit a29277d263aaefb8f711495bb5832f73422ee445
parent e6212e5d170f2bbfe130ce6807aa32f2262eb016
Author: kernelkind <kernelkind@gmail.com>
Date:   Fri, 18 Apr 2025 22:48:57 -0500

propagate `JobsCache`

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

Diffstat:
Mcrates/notedeck/src/note/mod.rs | 2++
Mcrates/notedeck_columns/src/nav.rs | 9+++++++--
Mcrates/notedeck_columns/src/timeline/route.rs | 9++++++++-
Mcrates/notedeck_columns/src/ui/note/post.rs | 9+++++++++
Mcrates/notedeck_columns/src/ui/note/quote_repost.rs | 6+++++-
Mcrates/notedeck_columns/src/ui/note/reply.rs | 6++++++
Mcrates/notedeck_columns/src/ui/profile/mod.rs | 5+++++
Mcrates/notedeck_columns/src/ui/search/mod.rs | 6+++++-
Mcrates/notedeck_columns/src/ui/thread.rs | 5+++++
Mcrates/notedeck_columns/src/ui/timeline.rs | 11+++++++++++
Mcrates/notedeck_dave/src/lib.rs | 9++++++++-
Mcrates/notedeck_dave/src/ui/dave.rs | 26++++++++++++++++++++------
Mcrates/notedeck_ui/src/note/contents.rs | 11+++++++++--
Mcrates/notedeck_ui/src/note/mod.rs | 27++++++++++++++++++++++++---
Mcrates/notedeck_ui/src/note/reply_description.rs | 56++++++++++++++++++++++++++++++--------------------------
15 files changed, 154 insertions(+), 43 deletions(-)

diff --git a/crates/notedeck/src/note/mod.rs b/crates/notedeck/src/note/mod.rs @@ -4,6 +4,7 @@ mod context; pub use action::{NoteAction, ZapAction, ZapTargetAmount}; pub use context::{BroadcastContext, ContextSelection, NoteContextSelection}; +use crate::JobPool; use crate::{notecache::NoteCache, zaps::Zaps, Images}; use enostr::{NoteId, RelayPool}; use nostrdb::{Ndb, Note, NoteKey, QueryResult, Transaction}; @@ -19,6 +20,7 @@ pub struct NoteContext<'d> { pub note_cache: &'d mut NoteCache, pub zaps: &'d mut Zaps, pub pool: &'d mut RelayPool, + pub job_pool: &'d mut JobPool, } #[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs @@ -280,6 +280,7 @@ fn render_nav_body( note_cache: ctx.note_cache, zaps: ctx.zaps, pool: ctx.pool, + job_pool: ctx.job_pool, }; match top { Route::Timeline(kind) => render_timeline_route( @@ -292,6 +293,7 @@ fn render_nav_body( depth, ui, &mut note_context, + &mut app.jobs, ), Route::Accounts(amr) => { @@ -348,6 +350,7 @@ fn render_nav_body( &note, inner_rect, app.note_options, + &mut app.jobs, ) .id_source(id) .show(ui) @@ -384,6 +387,7 @@ fn render_nav_body( &note, inner_rect, app.note_options, + &mut app.jobs, ) .id_source(id) .show(ui) @@ -405,6 +409,7 @@ fn render_nav_body( kp, inner_rect, app.note_options, + &mut app.jobs, ) .ui(&txn, ui); @@ -424,8 +429,7 @@ fn render_nav_body( Route::Search => { let id = ui.id().with(("search", depth, col)); - let navigating = app - .columns_mut(ctx.accounts) + let navigating = get_active_columns_mut(ctx.accounts, &mut app.decks_cache) .column(col) .router() .navigating; @@ -448,6 +452,7 @@ fn render_nav_body( search_buffer, &mut note_context, &ctx.accounts.get_selected_account().map(|a| (&a.key).into()), + &mut app.jobs, ) .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 @@ -7,7 +7,7 @@ use crate::{ use enostr::Pubkey; use notedeck::{Accounts, MuteFun, NoteContext, UnknownIds}; -use notedeck_ui::NoteOptions; +use notedeck_ui::{jobs::JobsCache, NoteOptions}; #[allow(clippy::too_many_arguments)] pub fn render_timeline_route( @@ -20,6 +20,7 @@ pub fn render_timeline_route( depth: usize, ui: &mut egui::Ui, note_context: &mut NoteContext, + jobs: &mut JobsCache, ) -> Option<RenderNavAction> { if kind == &TimelineKind::Universe { note_options.set_hide_media(true); @@ -40,6 +41,7 @@ pub fn render_timeline_route( note_context, note_options, &accounts.get_selected_account().map(|a| (&a.key).into()), + jobs, ) .ui(ui); @@ -58,6 +60,7 @@ pub fn render_timeline_route( &accounts.mutefun(), note_options, note_context, + jobs, ) } else { // we render profiles like timelines if they are at the root @@ -68,6 +71,7 @@ pub fn render_timeline_route( note_context, note_options, &accounts.get_selected_account().map(|a| (&a.key).into()), + jobs, ) .ui(ui); @@ -88,6 +92,7 @@ pub fn render_timeline_route( &accounts.mutefun(), note_context, &accounts.get_selected_account().map(|a| (&a.key).into()), + jobs, ) .id_source(egui::Id::new(("threadscroll", col))) .ui(ui) @@ -107,6 +112,7 @@ pub fn render_profile_route( is_muted: &MuteFun, note_options: NoteOptions, note_context: &mut NoteContext, + jobs: &mut JobsCache, ) -> Option<RenderNavAction> { let action = ProfileView::new( pubkey, @@ -117,6 +123,7 @@ pub fn render_profile_route( unknown_ids, is_muted, note_context, + jobs, ) .ui(ui); diff --git a/crates/notedeck_columns/src/ui/note/post.rs b/crates/notedeck_columns/src/ui/note/post.rs @@ -14,6 +14,7 @@ use egui::{ }; use enostr::{FilledKeypair, FullKeypair, NoteId, Pubkey, RelayPool}; use nostrdb::{Ndb, Transaction}; +use notedeck_ui::jobs::JobsCache; use notedeck_ui::{ gif::{handle_repaint, retrieve_latest_texture}, images::render_images, @@ -32,6 +33,7 @@ pub struct PostView<'a, 'd> { id_source: Option<egui::Id>, inner_rect: egui::Rect, note_options: NoteOptions, + jobs: &'a mut JobsCache, } #[derive(Clone)] @@ -103,6 +105,7 @@ impl<'a, 'd> PostView<'a, 'd> { poster: FilledKeypair<'a>, inner_rect: egui::Rect, note_options: NoteOptions, + jobs: &'a mut JobsCache, ) -> Self { let id_source: Option<egui::Id> = None; PostView { @@ -113,6 +116,7 @@ impl<'a, 'd> PostView<'a, 'd> { post_type, inner_rect, note_options, + jobs, } } @@ -345,6 +349,7 @@ impl<'a, 'd> PostView<'a, 'd> { id.bytes(), nostrdb::NoteKey::new(0), self.note_options, + self.jobs, ) }) .inner @@ -696,6 +701,7 @@ mod preview { pub struct PostPreview { draft: Draft, poster: FullKeypair, + jobs: JobsCache, } impl PostPreview { @@ -725,6 +731,7 @@ mod preview { PostPreview { draft, poster: FullKeypair::generate(), + jobs: Default::default(), } } } @@ -738,6 +745,7 @@ mod preview { note_cache: app.note_cache, zaps: app.zaps, pool: app.pool, + job_pool: app.job_pool, }; PostView::new( @@ -747,6 +755,7 @@ mod preview { self.poster.to_filled(), ui.available_rect_before_wrap(), NoteOptions::default(), + &mut self.jobs, ) .ui(&txn, ui); diff --git a/crates/notedeck_columns/src/ui/note/quote_repost.rs b/crates/notedeck_columns/src/ui/note/quote_repost.rs @@ -6,7 +6,7 @@ use crate::{ use enostr::{FilledKeypair, NoteId}; use notedeck::NoteContext; -use notedeck_ui::NoteOptions; +use notedeck_ui::{jobs::JobsCache, NoteOptions}; pub struct QuoteRepostView<'a, 'd> { note_context: &'a mut NoteContext<'d>, @@ -16,6 +16,7 @@ pub struct QuoteRepostView<'a, 'd> { id_source: Option<egui::Id>, inner_rect: egui::Rect, note_options: NoteOptions, + jobs: &'a mut JobsCache, } impl<'a, 'd> QuoteRepostView<'a, 'd> { @@ -27,6 +28,7 @@ impl<'a, 'd> QuoteRepostView<'a, 'd> { quoting_note: &'a nostrdb::Note<'a>, inner_rect: egui::Rect, note_options: NoteOptions, + jobs: &'a mut JobsCache, ) -> Self { let id_source: Option<egui::Id> = None; QuoteRepostView { @@ -37,6 +39,7 @@ impl<'a, 'd> QuoteRepostView<'a, 'd> { id_source, inner_rect, note_options, + jobs, } } @@ -51,6 +54,7 @@ impl<'a, 'd> QuoteRepostView<'a, 'd> { self.poster, self.inner_rect, self.note_options, + self.jobs, ) .id_source(id) .ui(self.quoting_note.txn().unwrap(), ui); diff --git a/crates/notedeck_columns/src/ui/note/reply.rs b/crates/notedeck_columns/src/ui/note/reply.rs @@ -6,6 +6,7 @@ use crate::ui::{ use enostr::{FilledKeypair, NoteId}; use notedeck::NoteContext; +use notedeck_ui::jobs::JobsCache; use notedeck_ui::{NoteOptions, NoteView, ProfilePic}; pub struct PostReplyView<'a, 'd> { @@ -16,6 +17,7 @@ pub struct PostReplyView<'a, 'd> { id_source: Option<egui::Id>, inner_rect: egui::Rect, note_options: NoteOptions, + jobs: &'a mut JobsCache, } impl<'a, 'd> PostReplyView<'a, 'd> { @@ -27,6 +29,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> { note: &'a nostrdb::Note<'a>, inner_rect: egui::Rect, note_options: NoteOptions, + jobs: &'a mut JobsCache, ) -> Self { let id_source: Option<egui::Id> = None; PostReplyView { @@ -37,6 +40,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> { id_source, inner_rect, note_options, + jobs, } } @@ -71,6 +75,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> { &Some(self.poster.into()), self.note, self.note_options, + self.jobs, ) .truncate(false) .selectable_text(true) @@ -93,6 +98,7 @@ impl<'a, 'd> PostReplyView<'a, 'd> { self.poster, self.inner_rect, self.note_options, + self.jobs, ) .id_source(id) .ui(self.note.txn().unwrap(), ui) diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -15,6 +15,7 @@ use notedeck::{ NotedeckTextStyle, UnknownIds, }; use notedeck_ui::{ + jobs::JobsCache, profile::{about_section_widget, banner, display_name_widget}, NoteOptions, ProfilePic, }; @@ -28,6 +29,7 @@ pub struct ProfileView<'a, 'd> { unknown_ids: &'a mut UnknownIds, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + jobs: &'a mut JobsCache, } pub enum ProfileViewAction { @@ -46,6 +48,7 @@ impl<'a, 'd> ProfileView<'a, 'd> { unknown_ids: &'a mut UnknownIds, is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, + jobs: &'a mut JobsCache, ) -> Self { ProfileView { pubkey, @@ -56,6 +59,7 @@ impl<'a, 'd> ProfileView<'a, 'd> { unknown_ids, is_muted, note_context, + jobs, } } @@ -112,6 +116,7 @@ impl<'a, 'd> ProfileView<'a, 'd> { .accounts .get_selected_account() .map(|a| (&a.key).into()), + self.jobs, ) .show(ui) { diff --git a/crates/notedeck_columns/src/ui/search/mod.rs b/crates/notedeck_columns/src/ui/search/mod.rs @@ -5,7 +5,7 @@ use crate::ui::timeline::TimelineTabView; use egui_winit::clipboard::Clipboard; use nostrdb::{Filter, Transaction}; use notedeck::{MuteFun, NoteAction, NoteContext, NoteRef}; -use notedeck_ui::{icons::search_icon, padding, NoteOptions}; +use notedeck_ui::{icons::search_icon, jobs::JobsCache, padding, NoteOptions}; use std::time::{Duration, Instant}; use tracing::{error, info, warn}; @@ -20,6 +20,7 @@ pub struct SearchView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, } impl<'a, 'd> SearchView<'a, 'd> { @@ -30,6 +31,7 @@ impl<'a, 'd> SearchView<'a, 'd> { query: &'a mut SearchQueryState, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, ) -> Self { Self { txn, @@ -38,6 +40,7 @@ impl<'a, 'd> SearchView<'a, 'd> { note_options, note_context, cur_acc, + jobs, } } @@ -81,6 +84,7 @@ impl<'a, 'd> SearchView<'a, 'd> { 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 @@ -1,6 +1,7 @@ use enostr::KeypairUnowned; use nostrdb::Transaction; use notedeck::{MuteFun, NoteAction, NoteContext, RootNoteId, UnknownIds}; +use notedeck_ui::jobs::JobsCache; use notedeck_ui::NoteOptions; use tracing::error; @@ -16,6 +17,7 @@ pub struct ThreadView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, } impl<'a, 'd> ThreadView<'a, 'd> { @@ -28,6 +30,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, ) -> Self { let id_source = egui::Id::new("threadscroll_threadview"); ThreadView { @@ -39,6 +42,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { is_muted, note_context, cur_acc, + jobs, } } @@ -102,6 +106,7 @@ impl<'a, 'd> ThreadView<'a, 'd> { self.is_muted, self.note_context, self.cur_acc, + self.jobs, ) .show(ui) }) diff --git a/crates/notedeck_columns/src/ui/timeline.rs b/crates/notedeck_columns/src/ui/timeline.rs @@ -3,6 +3,7 @@ use egui::{vec2, Direction, Layout, Pos2, Stroke}; use egui_tabs::TabColor; use enostr::KeypairUnowned; use nostrdb::Transaction; +use notedeck_ui::jobs::JobsCache; use std::f32::consts::PI; use tracing::{error, warn}; @@ -21,6 +22,7 @@ pub struct TimelineView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, } impl<'a, 'd> TimelineView<'a, 'd> { @@ -32,6 +34,7 @@ impl<'a, 'd> TimelineView<'a, 'd> { note_context: &'a mut NoteContext<'d>, note_options: NoteOptions, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, ) -> Self { let reverse = false; TimelineView { @@ -42,6 +45,7 @@ impl<'a, 'd> TimelineView<'a, 'd> { is_muted, note_context, cur_acc, + jobs, } } @@ -55,6 +59,7 @@ impl<'a, 'd> TimelineView<'a, 'd> { self.is_muted, self.note_context, self.cur_acc, + self.jobs, ) } @@ -74,6 +79,7 @@ fn timeline_ui( is_muted: &MuteFun, note_context: &mut NoteContext, cur_acc: &Option<KeypairUnowned>, + jobs: &mut JobsCache, ) -> Option<NoteAction> { //padding(4.0, ui, |ui| ui.heading("Notifications")); /* @@ -152,6 +158,7 @@ fn timeline_ui( is_muted, note_context, cur_acc, + jobs, ) .show(ui) }); @@ -323,6 +330,7 @@ pub struct TimelineTabView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, } impl<'a, 'd> TimelineTabView<'a, 'd> { @@ -335,6 +343,7 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { is_muted: &'a MuteFun, note_context: &'a mut NoteContext<'d>, cur_acc: &'a Option<KeypairUnowned<'a>>, + jobs: &'a mut JobsCache, ) -> Self { Self { tab, @@ -344,6 +353,7 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { is_muted, note_context, cur_acc, + jobs, } } @@ -395,6 +405,7 @@ impl<'a, 'd> TimelineTabView<'a, 'd> { self.cur_acc, &note, self.note_options, + self.jobs, ) .show(ui); diff --git a/crates/notedeck_dave/src/lib.rs b/crates/notedeck_dave/src/lib.rs @@ -9,6 +9,7 @@ use enostr::KeypairUnowned; use futures::StreamExt; use nostrdb::Transaction; use notedeck::{AppAction, AppContext}; +use notedeck_ui::jobs::JobsCache; use std::collections::HashMap; use std::string::ToString; use std::sync::mpsc::{self, Receiver}; @@ -42,6 +43,7 @@ pub struct Dave { client: async_openai::Client<OpenAIConfig>, incoming_tokens: Option<Receiver<DaveApiResponse>>, model_config: ModelConfig, + jobs: JobsCache, } /// Calculate an anonymous user_id from a keypair @@ -106,6 +108,7 @@ You are an AI agent for the nostr protocol called Dave, created by Damus. nostr input, model_config, chat: vec![], + jobs: JobsCache::default(), } } @@ -177,7 +180,11 @@ You are an AI agent for the nostr protocol called Dave, created by Damus. nostr } fn ui(&mut self, app_ctx: &mut AppContext, ui: &mut egui::Ui) -> DaveResponse { - DaveUi::new(self.model_config.trial, &self.chat, &mut self.input).ui(app_ctx, ui) + DaveUi::new(self.model_config.trial, &self.chat, &mut self.input).ui( + app_ctx, + &mut self.jobs, + ui, + ) } fn handle_new_chat(&mut self) { diff --git a/crates/notedeck_dave/src/ui/dave.rs b/crates/notedeck_dave/src/ui/dave.rs @@ -5,7 +5,7 @@ use crate::{ use egui::{Align, Key, KeyboardShortcut, Layout, Modifiers}; use nostrdb::{Ndb, Transaction}; use notedeck::{AppContext, NoteAction, NoteContext}; -use notedeck_ui::{icons::search_icon, NoteOptions, ProfilePic}; +use notedeck_ui::{icons::search_icon, jobs::JobsCache, NoteOptions, ProfilePic}; /// DaveUi holds all of the data it needs to render itself pub struct DaveUi<'a> { @@ -83,7 +83,12 @@ impl<'a> DaveUi<'a> { } /// The main render function. Call this to render Dave - pub fn ui(&mut self, app_ctx: &mut AppContext, ui: &mut egui::Ui) -> DaveResponse { + pub fn ui( + &mut self, + app_ctx: &mut AppContext, + jobs: &mut JobsCache, + ui: &mut egui::Ui, + ) -> DaveResponse { let mut action: Option<DaveAction> = None; // Scroll area for chat messages let new_resp = { @@ -124,7 +129,7 @@ impl<'a> DaveUi<'a> { .show(ui, |ui| { Self::chat_frame(ui.ctx()) .show(ui, |ui| { - ui.vertical(|ui| self.render_chat(app_ctx, ui)).inner + ui.vertical(|ui| self.render_chat(app_ctx, jobs, ui)).inner }) .inner }) @@ -158,7 +163,12 @@ impl<'a> DaveUi<'a> { } /// Render a chat message (user, assistant, tool call/response, etc) - fn render_chat(&self, ctx: &mut AppContext, ui: &mut egui::Ui) -> Option<NoteAction> { + fn render_chat( + &self, + ctx: &mut AppContext, + jobs: &mut JobsCache, + ui: &mut egui::Ui, + ) -> Option<NoteAction> { let mut action: Option<NoteAction> = None; for message in self.chat { let r = match message { @@ -183,7 +193,7 @@ impl<'a> DaveUi<'a> { // have a debug option to show this None } - Message::ToolCalls(toolcalls) => Self::tool_calls_ui(ctx, toolcalls, ui), + Message::ToolCalls(toolcalls) => Self::tool_calls_ui(ctx, jobs, toolcalls, ui), }; if r.is_some() { @@ -208,6 +218,7 @@ impl<'a> DaveUi<'a> { /// The ai has asked us to render some notes, so we do that here fn present_notes_ui( ctx: &mut AppContext, + jobs: &mut JobsCache, call: &PresentNotesCall, ui: &mut egui::Ui, ) -> Option<NoteAction> { @@ -217,6 +228,7 @@ impl<'a> DaveUi<'a> { note_cache: ctx.note_cache, zaps: ctx.zaps, pool: ctx.pool, + job_pool: ctx.job_pool, }; let txn = Transaction::new(note_context.ndb).unwrap(); @@ -244,6 +256,7 @@ impl<'a> DaveUi<'a> { &None, &note, NoteOptions::default(), + jobs, ) .preview_style() .hide_media(true) @@ -266,6 +279,7 @@ impl<'a> DaveUi<'a> { fn tool_calls_ui( ctx: &mut AppContext, + jobs: &mut JobsCache, toolcalls: &[ToolCall], ui: &mut egui::Ui, ) -> Option<NoteAction> { @@ -275,7 +289,7 @@ impl<'a> DaveUi<'a> { for call in toolcalls { match call.calls() { ToolCalls::PresentNotes(call) => { - let r = Self::present_notes_ui(ctx, call, ui); + let r = Self::present_notes_ui(ctx, jobs, call, ui); if r.is_some() { note_action = r; } diff --git a/crates/notedeck_ui/src/note/contents.rs b/crates/notedeck_ui/src/note/contents.rs @@ -1,6 +1,7 @@ use crate::{ gif::{handle_repaint, retrieve_latest_texture}, images::{render_images, ImageType}, + jobs::JobsCache, note::{NoteAction, NoteOptions, NoteResponse, NoteView}, }; @@ -18,6 +19,7 @@ pub struct NoteContents<'a, 'd> { note: &'a Note<'a>, options: NoteOptions, pub action: Option<NoteAction>, + jobs: &'a mut JobsCache, } impl<'a, 'd> NoteContents<'a, 'd> { @@ -28,6 +30,7 @@ impl<'a, 'd> NoteContents<'a, 'd> { txn: &'a Transaction, note: &'a Note, options: NoteOptions, + jobs: &'a mut JobsCache, ) -> Self { NoteContents { note_context, @@ -36,6 +39,7 @@ impl<'a, 'd> NoteContents<'a, 'd> { note, options, action: None, + jobs, } } } @@ -49,6 +53,7 @@ impl egui::Widget for &mut NoteContents<'_, '_> { self.txn, self.note, self.options, + self.jobs, ); self.action = result.action; result.response @@ -67,6 +72,7 @@ pub fn render_note_preview( id: &[u8; 32], parent: NoteKey, note_options: NoteOptions, + jobs: &mut JobsCache, ) -> NoteResponse { let note = if let Ok(note) = note_context.ndb.get_note_by_id(txn, id) { // TODO: support other preview kinds @@ -91,7 +97,7 @@ pub fn render_note_preview( */ }; - NoteView::new(note_context, cur_acc, &note, note_options) + NoteView::new(note_context, cur_acc, &note, note_options, jobs) .preview_style() .parent(parent) .show(ui) @@ -106,6 +112,7 @@ pub fn render_note_contents( txn: &Transaction, note: &Note, options: NoteOptions, + jobs: &mut JobsCache, ) -> NoteResponse { let note_key = note.key().expect("todo: implement non-db notes"); let selectable = options.has_selectable_text(); @@ -254,7 +261,7 @@ pub fn render_note_contents( }); let preview_note_action = if let Some((id, _block_str)) = inline_note { - render_note_preview(ui, note_context, cur_acc, txn, id, note_key, options).action + render_note_preview(ui, note_context, cur_acc, txn, id, note_key, options, jobs).action } else { None }; diff --git a/crates/notedeck_ui/src/note/mod.rs b/crates/notedeck_ui/src/note/mod.rs @@ -3,6 +3,7 @@ pub mod context; pub mod options; pub mod reply_description; +use crate::jobs::JobsCache; use crate::{ profile::name::one_line_display_name_widget, widgets::x_button, ImagePulseTint, ProfilePic, ProfilePreview, Username, @@ -32,6 +33,7 @@ pub struct NoteView<'a, 'd> { note: &'a nostrdb::Note<'a>, framed: bool, flags: NoteOptions, + jobs: &'a mut JobsCache, } pub struct NoteResponse { @@ -73,6 +75,7 @@ impl<'a, 'd> NoteView<'a, 'd> { cur_acc: &'a Option<KeypairUnowned<'a>>, note: &'a nostrdb::Note<'a>, mut flags: NoteOptions, + jobs: &'a mut JobsCache, ) -> Self { flags.set_actionbar(true); flags.set_note_previews(true); @@ -87,6 +90,7 @@ impl<'a, 'd> NoteView<'a, 'd> { note, flags, framed, + jobs, } } @@ -212,6 +216,7 @@ impl<'a, 'd> NoteView<'a, 'd> { txn, self.note, self.flags, + self.jobs, )); //}); }) @@ -326,7 +331,14 @@ impl<'a, 'd> NoteView<'a, 'd> { .text_style(style.text_style()), ); }); - NoteView::new(self.note_context, self.cur_acc, &note_to_repost, self.flags).show(ui) + NoteView::new( + self.note_context, + self.cur_acc, + &note_to_repost, + self.flags, + self.jobs, + ) + .show(ui) } else { self.show_standard(ui) } @@ -426,6 +438,7 @@ impl<'a, 'd> NoteView<'a, 'd> { &note_reply, self.note_context, self.flags, + self.jobs, ) }) .inner; @@ -437,8 +450,14 @@ impl<'a, 'd> NoteView<'a, 'd> { }); }); - let mut contents = - NoteContents::new(self.note_context, self.cur_acc, txn, self.note, self.flags); + let mut contents = NoteContents::new( + self.note_context, + self.cur_acc, + txn, + self.note, + self.flags, + self.jobs, + ); ui.add(&mut contents); @@ -489,6 +508,7 @@ impl<'a, 'd> NoteView<'a, 'd> { &note_reply, self.note_context, self.flags, + self.jobs, ); if action.is_some() { @@ -503,6 +523,7 @@ impl<'a, 'd> NoteView<'a, 'd> { txn, self.note, self.flags, + self.jobs, ); ui.add(&mut contents); diff --git a/crates/notedeck_ui/src/note/reply_description.rs b/crates/notedeck_ui/src/note/reply_description.rs @@ -2,7 +2,7 @@ use egui::{Label, RichText, Sense}; use nostrdb::{Note, NoteReply, Transaction}; use super::NoteOptions; -use crate::{note::NoteView, Mention}; +use crate::{jobs::JobsCache, note::NoteView, Mention}; use enostr::KeypairUnowned; use notedeck::{NoteAction, NoteContext}; @@ -15,6 +15,7 @@ pub fn reply_desc( note_reply: &NoteReply, note_context: &mut NoteContext, note_options: NoteOptions, + jobs: &mut JobsCache, ) -> Option<NoteAction> { let mut note_action: Option<NoteAction> = None; let size = 10.0; @@ -24,28 +25,31 @@ pub fn reply_desc( let link_color = visuals.hyperlink_color; // note link renderer helper - let note_link = - |ui: &mut egui::Ui, note_context: &mut NoteContext, text: &str, note: &Note<'_>| { - let r = ui.add( - Label::new(RichText::new(text).size(size).color(link_color)) - .sense(Sense::click()) - .selectable(selectable), - ); - - if r.clicked() { - // TODO: jump to note - } + let note_link = |ui: &mut egui::Ui, + note_context: &mut NoteContext, + text: &str, + note: &Note<'_>, + jobs: &mut JobsCache| { + let r = ui.add( + Label::new(RichText::new(text).size(size).color(link_color)) + .sense(Sense::click()) + .selectable(selectable), + ); + + if r.clicked() { + // TODO: jump to note + } - 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) - .actionbar(false) - .wide(true) - .show(ui); - }); - } - }; + 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) + .actionbar(false) + .wide(true) + .show(ui); + }); + } + }; ui.add(Label::new(RichText::new("replying to").size(size).color(color)).selectable(selectable)); @@ -77,7 +81,7 @@ pub fn reply_desc( ui.add(Label::new(RichText::new("'s").size(size).color(color)).selectable(selectable)); - note_link(ui, note_context, "thread", &reply_note); + note_link(ui, note_context, "thread", &reply_note, jobs); } else if let Some(root) = note_reply.root() { // replying to another post in a thread, not the root @@ -103,7 +107,7 @@ pub fn reply_desc( Label::new(RichText::new("'s").size(size).color(color)).selectable(selectable), ); - note_link(ui, note_context, "note", &reply_note); + note_link(ui, note_context, "note", &reply_note, jobs); } else { // replying to bob in alice's thread @@ -126,7 +130,7 @@ pub fn reply_desc( Label::new(RichText::new("'s").size(size).color(color)).selectable(selectable), ); - note_link(ui, note_context, "note", &reply_note); + note_link(ui, note_context, "note", &reply_note, jobs); ui.add( Label::new(RichText::new("in").size(size).color(color)).selectable(selectable), @@ -151,7 +155,7 @@ pub fn reply_desc( Label::new(RichText::new("'s").size(size).color(color)).selectable(selectable), ); - note_link(ui, note_context, "thread", &root_note); + note_link(ui, note_context, "thread", &root_note, jobs); } } else { let action = Mention::new(