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);