From 2d7de8fdc0c78ebec1d2210e9b0082fc06d88d66 Mon Sep 17 00:00:00 2001 From: Ken Sedgwick Date: Thu, 19 Dec 2024 14:22:30 -0800 Subject: [PATCH 1/2] Add debug-widget-callstack and debug-interactive-widgets features - they need to be separate, both on at once is too much --features debug-widget-callstack Show callstack for the current widget on hover if all modifier keys are pressed down --features debug-interactive-widgets Show an overlay on all interactive widgets Notes: - debug-widget-callstack asserts `egui:callstack` feature when enabled - Only works in debug builds, compile error w/ release builds --- Cargo.lock | 1 + crates/notedeck_chrome/Cargo.toml | 2 ++ crates/notedeck_chrome/src/theme.rs | 21 +++++++++++++++++++-- 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 327a4709..5aa14f91 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1050,6 +1050,7 @@ checksum = "53eafabcce0cb2325a59a98736efe0bf060585b437763f8c476957fb274bb974" dependencies = [ "accesskit", "ahash", + "backtrace", "emath", "epaint", "log", diff --git a/crates/notedeck_chrome/Cargo.toml b/crates/notedeck_chrome/Cargo.toml index ff2c05fb..39882b98 100644 --- a/crates/notedeck_chrome/Cargo.toml +++ b/crates/notedeck_chrome/Cargo.toml @@ -42,6 +42,8 @@ path = "src/preview.rs" [features] default = [] profiling = ["notedeck_columns/puffin", "puffin", "puffin_egui"] +debug-widget-callstack = ["egui/callstack"] +debug-interactive-widgets = [] [target.'cfg(target_os = "android")'.dependencies] android_logger = "0.11.1" diff --git a/crates/notedeck_chrome/src/theme.rs b/crates/notedeck_chrome/src/theme.rs index c20da79b..1ec31309 100644 --- a/crates/notedeck_chrome/src/theme.rs +++ b/crates/notedeck_chrome/src/theme.rs @@ -124,9 +124,26 @@ pub fn add_custom_style(is_mobile: bool, style: &mut Style) { ..Interaction::default() }; - #[cfg(debug_assertions)] + // debug: show callstack for the current widget on hover if all + // modifier keys are pressed down. + #[cfg(feature = "debug-widget-callstack")] { - style.debug.show_interactive_widgets = true; + #[cfg(not(debug_assertions))] + compile_error!( + "The `debug-widget-callstack` feature requires a debug build, \ + release builds are unsupported." + ); style.debug.debug_on_hover_with_all_modifiers = true; } + + // debug: show an overlay on all interactive widgets + #[cfg(feature = "debug-interactive-widgets")] + { + #[cfg(not(debug_assertions))] + compile_error!( + "The `debug-interactive-widgets` feature requires a debug build, \ + release builds are unsupported." + ); + style.debug.show_interactive_widgets = true; + } } From e193e0053912288f640b02c2938d67893a3a6ea9 Mon Sep 17 00:00:00 2001 From: Ken Sedgwick Date: Thu, 19 Dec 2024 15:27:26 -0800 Subject: [PATCH 2/2] Mute rendering instead of ingress Previous approach was to keep muted content from getting inserted. Instead, this version alters it's display. This makes toggling mutes on and off externally much more stable (the display changes but we don't have to rebuild content trees) For now muted content is collapsed to a red "Muted" tombstone w/ a reason. --- crates/notedeck/src/accounts.rs | 10 ++-- crates/notedeck/src/muted.rs | 31 +++++++++--- crates/notedeck_columns/src/actionbar.rs | 39 ++++----------- crates/notedeck_columns/src/app.rs | 3 -- .../notedeck_columns/src/multi_subscriber.rs | 13 +---- crates/notedeck_columns/src/nav.rs | 3 -- crates/notedeck_columns/src/notes_holder.rs | 15 ++---- crates/notedeck_columns/src/profile.rs | 7 +-- crates/notedeck_columns/src/thread.rs | 3 +- crates/notedeck_columns/src/timeline/mod.rs | 29 +++-------- crates/notedeck_columns/src/timeline/route.rs | 2 +- crates/notedeck_columns/src/ui/add_column.rs | 1 - crates/notedeck_columns/src/ui/profile/mod.rs | 12 ++--- crates/notedeck_columns/src/ui/thread.rs | 6 +-- crates/notedeck_columns/src/ui/timeline.rs | 48 ++++++++++++------- 15 files changed, 95 insertions(+), 127 deletions(-) diff --git a/crates/notedeck/src/accounts.rs b/crates/notedeck/src/accounts.rs index 354be843..3eb27fc5 100644 --- a/crates/notedeck/src/accounts.rs +++ b/crates/notedeck/src/accounts.rs @@ -1,7 +1,7 @@ use tracing::{debug, error, info}; use crate::{ - KeyStorageResponse, KeyStorageType, Muted, SingleUnkIdAction, UnknownIds, UserAccount, + KeyStorageResponse, KeyStorageType, MuteFun, Muted, SingleUnkIdAction, UnknownIds, UserAccount, }; use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool}; use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction}; @@ -401,17 +401,19 @@ impl Accounts { self.key_store.select_key(None); } - pub fn mutefun(&self) -> Box bool> { + pub fn mutefun(&self) -> Box { if let Some(index) = self.currently_selected_account { if let Some(account) = self.accounts.get(index) { let pubkey = account.pubkey.bytes(); if let Some(account_data) = self.account_data.get(pubkey) { let muted = Arc::clone(&account_data.muted.muted); - return Box::new(move |note: &Note| muted.is_muted(note)); + return Box::new(move |note: &Note, thread: &[u8; 32]| { + muted.is_muted(note, thread) + }); } } } - Box::new(|_: &Note| false) + Box::new(|_: &Note, _: &[u8; 32]| None) } pub fn send_initial_filters(&mut self, pool: &mut RelayPool, relay_url: &str) { diff --git a/crates/notedeck/src/muted.rs b/crates/notedeck/src/muted.rs index c2cd2294..91e477b3 100644 --- a/crates/notedeck/src/muted.rs +++ b/crates/notedeck/src/muted.rs @@ -1,9 +1,10 @@ use nostrdb::Note; use std::collections::BTreeSet; -use tracing::debug; +use tracing::{debug, trace}; -pub type MuteFun = dyn Fn(&Note) -> bool; +// If the note is muted return a reason string, otherwise None +pub type MuteFun = dyn Fn(&Note, &[u8; 32]) -> Option; #[derive(Default)] pub struct Muted { @@ -32,14 +33,21 @@ impl std::fmt::Debug for Muted { } impl Muted { - pub fn is_muted(&self, note: &Note) -> bool { + // If the note is muted return a reason string, otherwise None + pub fn is_muted(&self, note: &Note, thread: &[u8; 32]) -> Option { + trace!( + "{}: thread: {}", + hex::encode(note.id()), + hex::encode(thread) + ); + if self.pubkeys.contains(note.pubkey()) { debug!( "{}: MUTED pubkey: {}", hex::encode(note.id()), hex::encode(note.pubkey()) ); - return true; + return Some(format!("pubkey {}", hex::encode(note.pubkey()))); } // FIXME - Implement hashtag muting here @@ -51,11 +59,20 @@ impl Muted { // for word in &self.words { // if content.contains(&word.to_lowercase()) { // debug!("{}: MUTED word: {}", hex::encode(note.id()), word); - // return true; + // return Some(format!("muted word {}", word)); // } // } - // FIXME - Implement thread muting here - false + if self.threads.contains(thread) { + debug!( + "{}: MUTED thread: {}", + hex::encode(note.id()), + hex::encode(thread) + ); + return Some(format!("thread {}", hex::encode(thread))); + } + + // if we get here it's not muted + None } } diff --git a/crates/notedeck_columns/src/actionbar.rs b/crates/notedeck_columns/src/actionbar.rs index e8d42f09..fd4ea7ef 100644 --- a/crates/notedeck_columns/src/actionbar.rs +++ b/crates/notedeck_columns/src/actionbar.rs @@ -8,7 +8,7 @@ use crate::{ use enostr::{NoteId, Pubkey, RelayPool}; use nostrdb::{Ndb, Transaction}; -use notedeck::{note::root_note_id_from_selected_id, MuteFun, NoteCache, NoteRef}; +use notedeck::{note::root_note_id_from_selected_id, NoteCache, NoteRef}; #[derive(Debug, Eq, PartialEq, Copy, Clone)] pub enum NoteAction { @@ -41,12 +41,11 @@ fn open_thread( pool: &mut RelayPool, threads: &mut NotesHolderStorage, selected_note: &[u8; 32], - is_muted: &MuteFun, ) -> Option { router.route_to(Route::thread(NoteId::new(selected_note.to_owned()))); let root_id = root_note_id_from_selected_id(ndb, note_cache, txn, selected_note); - Thread::open(ndb, note_cache, txn, pool, threads, root_id, is_muted) + Thread::open(ndb, note_cache, txn, pool, threads, root_id) } impl NoteAction { @@ -60,7 +59,6 @@ impl NoteAction { note_cache: &mut NoteCache, pool: &mut RelayPool, txn: &Transaction, - is_muted: &MuteFun, ) -> Option { match self { NoteAction::Reply(note_id) => { @@ -68,28 +66,13 @@ impl NoteAction { None } - NoteAction::OpenThread(note_id) => open_thread( - ndb, - txn, - router, - note_cache, - pool, - threads, - note_id.bytes(), - is_muted, - ), + NoteAction::OpenThread(note_id) => { + open_thread(ndb, txn, router, note_cache, pool, threads, note_id.bytes()) + } NoteAction::OpenProfile(pubkey) => { router.route_to(Route::profile(pubkey)); - Profile::open( - ndb, - note_cache, - txn, - pool, - profiles, - pubkey.bytes(), - is_muted, - ) + Profile::open(ndb, note_cache, txn, pool, profiles, pubkey.bytes()) } NoteAction::Quote(note_id) => { @@ -111,13 +94,10 @@ impl NoteAction { note_cache: &mut NoteCache, pool: &mut RelayPool, txn: &Transaction, - is_muted: &MuteFun, ) { let router = columns.column_mut(col).router_mut(); - if let Some(br) = self.execute( - ndb, router, threads, profiles, note_cache, pool, txn, is_muted, - ) { - br.process(ndb, note_cache, txn, threads, is_muted); + if let Some(br) = self.execute(ndb, router, threads, profiles, note_cache, pool, txn) { + br.process(ndb, note_cache, txn, threads); } } } @@ -133,13 +113,12 @@ impl NotesHolderResult { note_cache: &mut NoteCache, txn: &Transaction, storage: &mut NotesHolderStorage, - is_muted: &MuteFun, ) { match self { // update the thread for next render if we have new notes NotesHolderResult::NewNotes(new_notes) => { let holder = storage - .notes_holder_mutated(ndb, note_cache, txn, &new_notes.id, is_muted) + .notes_holder_mutated(ndb, note_cache, txn, &new_notes.id) .get_ptr(); new_notes.process(holder); } diff --git a/crates/notedeck_columns/src/app.rs b/crates/notedeck_columns/src/app.rs index 1f61bae1..62d8655b 100644 --- a/crates/notedeck_columns/src/app.rs +++ b/crates/notedeck_columns/src/app.rs @@ -138,7 +138,6 @@ fn try_process_event( app_ctx.pool, app_ctx.note_cache, timeline, - &app_ctx.accounts.mutefun(), app_ctx .accounts .get_selected_account() @@ -157,7 +156,6 @@ fn try_process_event( &txn, app_ctx.unknown_ids, app_ctx.note_cache, - &app_ctx.accounts.mutefun(), ) { error!("poll_notes_into_view: {err}"); } @@ -198,7 +196,6 @@ fn update_damus(damus: &mut Damus, app_ctx: &mut AppContext<'_>, ctx: &egui::Con app_ctx.ndb, app_ctx.note_cache, &mut damus.decks_cache, - &app_ctx.accounts.mutefun(), ) { warn!("update_damus init: {err}"); } diff --git a/crates/notedeck_columns/src/multi_subscriber.rs b/crates/notedeck_columns/src/multi_subscriber.rs index c1eed126..2c56ee17 100644 --- a/crates/notedeck_columns/src/multi_subscriber.rs +++ b/crates/notedeck_columns/src/multi_subscriber.rs @@ -4,7 +4,7 @@ use tracing::{debug, error, info}; use uuid::Uuid; use crate::Error; -use notedeck::{MuteFun, NoteRef, UnifiedSubscription}; +use notedeck::{NoteRef, UnifiedSubscription}; pub struct MultiSubscriber { filters: Vec, @@ -106,12 +106,7 @@ impl MultiSubscriber { } } - pub fn poll_for_notes( - &mut self, - ndb: &Ndb, - txn: &Transaction, - is_muted: &MuteFun, - ) -> Result, Error> { + pub fn poll_for_notes(&mut self, ndb: &Ndb, txn: &Transaction) -> Result, Error> { let sub = self.sub.as_ref().ok_or(notedeck::Error::no_active_sub())?; let new_note_keys = ndb.poll_for_notes(sub.local, 500); @@ -129,10 +124,6 @@ impl MultiSubscriber { continue; }; - if is_muted(¬e) { - continue; - } - notes.push(note); } diff --git a/crates/notedeck_columns/src/nav.rs b/crates/notedeck_columns/src/nav.rs index a9746c7c..40bfc017 100644 --- a/crates/notedeck_columns/src/nav.rs +++ b/crates/notedeck_columns/src/nav.rs @@ -161,7 +161,6 @@ impl RenderNavResponse { ctx.note_cache, ctx.pool, &txn, - &ctx.accounts.mutefun(), ); } @@ -196,7 +195,6 @@ impl RenderNavResponse { &mut app.threads, ctx.pool, root_id, - &ctx.accounts.mutefun(), ); } @@ -208,7 +206,6 @@ impl RenderNavResponse { &mut app.profiles, ctx.pool, pubkey.bytes(), - &ctx.accounts.mutefun(), ); } diff --git a/crates/notedeck_columns/src/notes_holder.rs b/crates/notedeck_columns/src/notes_holder.rs index f5d45360..b898edba 100644 --- a/crates/notedeck_columns/src/notes_holder.rs +++ b/crates/notedeck_columns/src/notes_holder.rs @@ -2,7 +2,7 @@ use std::collections::HashMap; use enostr::{Filter, RelayPool}; use nostrdb::{Ndb, Transaction}; -use notedeck::{MuteFun, NoteCache, NoteRef, NoteRefsUnkIdAction}; +use notedeck::{NoteCache, NoteRef, NoteRefsUnkIdAction}; use tracing::{debug, info, warn}; use crate::{ @@ -56,7 +56,6 @@ impl NotesHolderStorage { note_cache: &mut NoteCache, txn: &Transaction, id: &[u8; 32], - is_muted: &MuteFun, ) -> Vitality<'a, M> { // we can't use the naive hashmap entry API here because lookups // require a copy, wait until we have a raw entry api. We could @@ -90,7 +89,7 @@ impl NotesHolderStorage { self.id_to_object.insert( id.to_owned(), - M::new_notes_holder(txn, ndb, note_cache, id, M::filters(id), notes, is_muted), + M::new_notes_holder(txn, ndb, note_cache, id, M::filters(id), notes), ); Vitality::Fresh(self.id_to_object.get_mut(id).unwrap()) } @@ -109,7 +108,6 @@ pub trait NotesHolder { id: &[u8; 32], filters: Vec, notes: Vec, - is_muted: &MuteFun, ) -> Self; #[must_use = "process_action must be handled in the Ok(action) case"] @@ -117,11 +115,10 @@ pub trait NotesHolder { &mut self, txn: &Transaction, ndb: &Ndb, - is_muted: &MuteFun, ) -> Result { if let Some(multi_subscriber) = self.get_multi_subscriber() { let reversed = true; - let note_refs: Vec = multi_subscriber.poll_for_notes(ndb, txn, is_muted)?; + let note_refs: Vec = multi_subscriber.poll_for_notes(ndb, txn)?; self.get_view().insert(¬e_refs, reversed); Ok(NoteRefsUnkIdAction::new(note_refs)) } else { @@ -160,10 +157,9 @@ pub trait NotesHolder { notes_holder_storage: &mut NotesHolderStorage, pool: &mut RelayPool, id: &[u8; 32], - is_muted: &MuteFun, ) { let notes_holder = notes_holder_storage - .notes_holder_mutated(ndb, note_cache, txn, id, is_muted) + .notes_holder_mutated(ndb, note_cache, txn, id) .get_ptr(); if let Some(multi_subscriber) = notes_holder.get_multi_subscriber() { @@ -178,9 +174,8 @@ pub trait NotesHolder { pool: &mut RelayPool, storage: &mut NotesHolderStorage, id: &[u8; 32], - is_muted: &MuteFun, ) -> Option { - let vitality = storage.notes_holder_mutated(ndb, note_cache, txn, id, is_muted); + let vitality = storage.notes_holder_mutated(ndb, note_cache, txn, id); let (holder, result) = match vitality { Vitality::Stale(holder) => { diff --git a/crates/notedeck_columns/src/profile.rs b/crates/notedeck_columns/src/profile.rs index 644ffb1e..3d5a7b4c 100644 --- a/crates/notedeck_columns/src/profile.rs +++ b/crates/notedeck_columns/src/profile.rs @@ -1,7 +1,7 @@ use enostr::{Filter, Pubkey}; use nostrdb::{FilterBuilder, Ndb, ProfileRecord, Transaction}; -use notedeck::{filter::default_limit, FilterState, MuteFun, NoteCache, NoteRef}; +use notedeck::{filter::default_limit, FilterState, NoteCache, NoteRef}; use crate::{ multi_subscriber::MultiSubscriber, @@ -60,7 +60,6 @@ impl Profile { source: PubkeySource, filters: Vec, notes: Vec, - is_muted: &MuteFun, ) -> Self { let mut timeline = Timeline::new( TimelineKind::profile(source), @@ -68,7 +67,7 @@ impl Profile { TimelineTab::full_tabs(), ); - copy_notes_into_timeline(&mut timeline, txn, ndb, note_cache, notes, is_muted); + copy_notes_into_timeline(&mut timeline, txn, ndb, note_cache, notes); Profile { timeline, @@ -114,7 +113,6 @@ impl NotesHolder for Profile { id: &[u8; 32], filters: Vec, notes: Vec, - is_muted: &MuteFun, ) -> Self { Profile::new( txn, @@ -123,7 +121,6 @@ impl NotesHolder for Profile { PubkeySource::Explicit(Pubkey::new(*id)), filters, notes, - is_muted, ) } diff --git a/crates/notedeck_columns/src/thread.rs b/crates/notedeck_columns/src/thread.rs index 27864d29..1494ab9e 100644 --- a/crates/notedeck_columns/src/thread.rs +++ b/crates/notedeck_columns/src/thread.rs @@ -5,7 +5,7 @@ use crate::{ }; use nostrdb::{Filter, FilterBuilder, Ndb, Transaction}; -use notedeck::{MuteFun, NoteCache, NoteRef}; +use notedeck::{NoteCache, NoteRef}; #[derive(Default)] pub struct Thread { @@ -74,7 +74,6 @@ impl NotesHolder for Thread { _: &[u8; 32], _: Vec, notes: Vec, - _: &MuteFun, ) -> Self { Thread::new(notes) } diff --git a/crates/notedeck_columns/src/timeline/mod.rs b/crates/notedeck_columns/src/timeline/mod.rs index 6e52d82e..45eb3c2a 100644 --- a/crates/notedeck_columns/src/timeline/mod.rs +++ b/crates/notedeck_columns/src/timeline/mod.rs @@ -7,8 +7,7 @@ use crate::{ }; use notedeck::{ - filter, CachedNote, FilterError, FilterState, FilterStates, MuteFun, NoteCache, NoteRef, - UnknownIds, + filter, CachedNote, FilterError, FilterState, FilterStates, NoteCache, NoteRef, UnknownIds, }; use std::fmt; @@ -287,7 +286,6 @@ impl Timeline { txn: &Transaction, unknown_ids: &mut UnknownIds, note_cache: &mut NoteCache, - is_muted: &MuteFun, ) -> Result<()> { let timeline = timelines .get_mut(timeline_idx) @@ -312,9 +310,6 @@ impl Timeline { error!("hit race condition in poll_notes_into_view: https://github.com/damus-io/nostrdb/issues/35 note {:?} was not added to timeline", key); continue; }; - if is_muted(¬e) { - continue; - } UnknownIds::update_from_note(txn, ndb, unknown_ids, note_cache, ¬e); @@ -412,12 +407,11 @@ pub fn setup_new_timeline( pool: &mut RelayPool, 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, our_pk) { - if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline, is_muted) { + if is_timeline_ready(ndb, pool, note_cache, timeline, our_pk) { + if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline) { error!("setup_new_timeline: {err}"); } } @@ -547,7 +541,6 @@ fn setup_initial_timeline( timeline: &mut Timeline, note_cache: &mut NoteCache, filters: &[Filter], - is_muted: &MuteFun, ) -> Result<()> { timeline.subscription = Some(ndb.subscribe(filters)?); let txn = Transaction::new(ndb)?; @@ -562,7 +555,7 @@ fn setup_initial_timeline( .map(NoteRef::from_query_result) .collect(); - copy_notes_into_timeline(timeline, &txn, ndb, note_cache, notes, is_muted); + copy_notes_into_timeline(timeline, &txn, ndb, note_cache, notes); Ok(()) } @@ -573,7 +566,6 @@ pub fn copy_notes_into_timeline( ndb: &Ndb, note_cache: &mut NoteCache, notes: Vec, - is_muted: &MuteFun, ) { let filters = { let views = &timeline.views; @@ -585,9 +577,6 @@ pub fn copy_notes_into_timeline( for note_ref in notes { for (view, filter) in filters.iter().enumerate() { if let Ok(note) = ndb.get_note_by_key(txn, note_ref.key) { - if is_muted(¬e) { - continue; - } if filter( note_cache.cached_note_or_insert_mut(note_ref.key, ¬e), ¬e, @@ -603,12 +592,11 @@ pub fn setup_initial_nostrdb_subs( ndb: &Ndb, note_cache: &mut NoteCache, decks_cache: &mut DecksCache, - is_muted: &MuteFun, ) -> Result<()> { for decks in decks_cache.get_all_decks_mut() { for deck in decks.decks_mut() { for timeline in deck.columns_mut().timelines_mut() { - if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline, is_muted) { + if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline) { error!("setup_initial_nostrdb_subs: {err}"); } } @@ -622,7 +610,6 @@ fn setup_timeline_nostrdb_sub( ndb: &Ndb, note_cache: &mut NoteCache, timeline: &mut Timeline, - is_muted: &MuteFun, ) -> Result<()> { let filter_state = timeline .filter @@ -630,7 +617,7 @@ fn setup_timeline_nostrdb_sub( .ok_or(Error::App(notedeck::Error::empty_contact_list()))? .to_owned(); - setup_initial_timeline(ndb, timeline, note_cache, &filter_state, is_muted)?; + setup_initial_timeline(ndb, timeline, note_cache, &filter_state)?; Ok(()) } @@ -644,7 +631,6 @@ pub fn is_timeline_ready( pool: &mut RelayPool, 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 @@ -705,8 +691,7 @@ pub fn is_timeline_ready( // we just switched to the ready state, we should send initial // queries and setup the local subscription info!("Found contact list! Setting up local and remote contact list query"); - setup_initial_timeline(ndb, timeline, note_cache, &filter, is_muted) - .expect("setup init"); + setup_initial_timeline(ndb, timeline, note_cache, &filter).expect("setup init"); timeline .filter .set_relay_state(relay_id, FilterState::ready(filter.clone())); diff --git a/crates/notedeck_columns/src/timeline/route.rs b/crates/notedeck_columns/src/timeline/route.rs index 50485892..e72da11a 100644 --- a/crates/notedeck_columns/src/timeline/route.rs +++ b/crates/notedeck_columns/src/timeline/route.rs @@ -64,7 +64,7 @@ pub fn render_timeline_route( img_cache, note_options, ) - .ui(ui); + .ui(ui, &accounts.mutefun()); note_action.map(RenderNavAction::NoteAction) } diff --git a/crates/notedeck_columns/src/ui/add_column.rs b/crates/notedeck_columns/src/ui/add_column.rs index 5588c174..6a380000 100644 --- a/crates/notedeck_columns/src/ui/add_column.rs +++ b/crates/notedeck_columns/src/ui/add_column.rs @@ -503,7 +503,6 @@ pub fn render_add_column_routes( ctx.pool, ctx.note_cache, app.since_optimize, - &ctx.accounts.mutefun(), ctx.accounts .get_selected_account() .as_ref() diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs index a6ba48a6..4fab268d 100644 --- a/crates/notedeck_columns/src/ui/profile/mod.rs +++ b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -58,20 +58,14 @@ impl<'a> ProfileView<'a> { } let profile = self .profiles - .notes_holder_mutated( - self.ndb, - self.note_cache, - &txn, - self.pubkey.bytes(), - is_muted, - ) + .notes_holder_mutated(self.ndb, self.note_cache, &txn, self.pubkey.bytes()) .get_ptr(); profile.timeline.selected_view = tabs_ui(ui, profile.timeline.selected_view, &profile.timeline.views); // poll for new notes and insert them into our existing notes - if let Err(e) = profile.poll_notes_into_view(&txn, self.ndb, is_muted) { + if let Err(e) = profile.poll_notes_into_view(&txn, self.ndb) { error!("Profile::poll_notes_into_view: {e}"); } @@ -86,7 +80,7 @@ impl<'a> ProfileView<'a> { self.note_cache, self.img_cache, ) - .show(ui) + .show(ui, is_muted) }) .inner } diff --git a/crates/notedeck_columns/src/ui/thread.rs b/crates/notedeck_columns/src/ui/thread.rs index f62c9534..c28bc476 100644 --- a/crates/notedeck_columns/src/ui/thread.rs +++ b/crates/notedeck_columns/src/ui/thread.rs @@ -93,13 +93,13 @@ impl<'a> ThreadView<'a> { let thread = self .threads - .notes_holder_mutated(self.ndb, self.note_cache, &txn, root_id, is_muted) + .notes_holder_mutated(self.ndb, self.note_cache, &txn, root_id) .get_ptr(); // TODO(jb55): skip poll if ThreadResult is fresh? // poll for new notes and insert them into our existing notes - match thread.poll_notes_into_view(&txn, self.ndb, is_muted) { + match thread.poll_notes_into_view(&txn, self.ndb) { Ok(action) => { action.process_action(&txn, self.ndb, self.unknown_ids, self.note_cache) } @@ -120,7 +120,7 @@ impl<'a> ThreadView<'a> { self.note_cache, self.img_cache, ) - .show(ui) + .show(ui, is_muted) }) .inner } diff --git a/crates/notedeck_columns/src/ui/timeline.rs b/crates/notedeck_columns/src/ui/timeline.rs index 0732e6f1..1b3decfd 100644 --- a/crates/notedeck_columns/src/ui/timeline.rs +++ b/crates/notedeck_columns/src/ui/timeline.rs @@ -7,10 +7,11 @@ use crate::{ ui::note::NoteOptions, }; use egui::containers::scroll_area::ScrollBarVisibility; -use egui::{Direction, Layout}; +use egui::{Color32, Direction, Layout}; use egui_tabs::TabColor; use nostrdb::{Ndb, Transaction}; -use notedeck::{ImageCache, NoteCache}; +use notedeck::note::root_note_id_from_selected_id; +use notedeck::{ImageCache, MuteFun, NoteCache}; use tracing::{error, warn}; pub struct TimelineView<'a> { @@ -44,7 +45,7 @@ impl<'a> TimelineView<'a> { } } - pub fn ui(&mut self, ui: &mut egui::Ui) -> Option { + pub fn ui(&mut self, ui: &mut egui::Ui, is_muted: &MuteFun) -> Option { timeline_ui( ui, self.ndb, @@ -54,6 +55,7 @@ impl<'a> TimelineView<'a> { self.img_cache, self.reverse, self.note_options, + is_muted, ) } @@ -73,6 +75,7 @@ fn timeline_ui( img_cache: &mut ImageCache, reversed: bool, note_options: NoteOptions, + is_muted: &MuteFun, ) -> Option { //padding(4.0, ui, |ui| ui.heading("Notifications")); /* @@ -124,7 +127,7 @@ fn timeline_ui( note_cache, img_cache, ) - .show(ui) + .show(ui, is_muted) }) .inner } @@ -247,7 +250,7 @@ impl<'a> TimelineTabView<'a> { } } - pub fn show(&mut self, ui: &mut egui::Ui) -> Option { + pub fn show(&mut self, ui: &mut egui::Ui, is_muted: &MuteFun) -> Option { let mut action: Option = None; let len = self.tab.notes.len(); @@ -275,17 +278,30 @@ impl<'a> TimelineTabView<'a> { }; ui::padding(8.0, ui, |ui| { - let resp = ui::NoteView::new(self.ndb, self.note_cache, self.img_cache, ¬e) - .note_options(self.note_options) - .show(ui); - - if let Some(note_action) = resp.action { - action = Some(note_action) - } - - if let Some(context) = resp.context_selection { - context.process(ui, ¬e); - } + if let Some(muted_reason) = is_muted( + ¬e, + root_note_id_from_selected_id( + self.ndb, + self.note_cache, + self.txn, + note.id(), + ), + ) { + ui.colored_label(Color32::RED, format!("MUTED {}", muted_reason)); + } else { + let resp = + ui::NoteView::new(self.ndb, self.note_cache, self.img_cache, ¬e) + .note_options(self.note_options) + .show(ui); + + if let Some(note_action) = resp.action { + action = Some(note_action) + } + + if let Some(context) = resp.context_selection { + context.process(ui, ¬e); + } + }; }); ui::hline(ui);