mirror of
https://github.com/aljazceru/notedeck.git
synced 2025-12-20 01:44:19 +01:00
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.
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
KeyStorageResponse, KeyStorageType, Muted, SingleUnkIdAction, UnknownIds, UserAccount,
|
KeyStorageResponse, KeyStorageType, MuteFun, Muted, SingleUnkIdAction, UnknownIds, UserAccount,
|
||||||
};
|
};
|
||||||
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
|
use enostr::{ClientMessage, FilledKeypair, Keypair, RelayPool};
|
||||||
use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction};
|
use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction};
|
||||||
@@ -401,17 +401,19 @@ impl Accounts {
|
|||||||
self.key_store.select_key(None);
|
self.key_store.select_key(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mutefun(&self) -> Box<dyn Fn(&Note) -> bool> {
|
pub fn mutefun(&self) -> Box<MuteFun> {
|
||||||
if let Some(index) = self.currently_selected_account {
|
if let Some(index) = self.currently_selected_account {
|
||||||
if let Some(account) = self.accounts.get(index) {
|
if let Some(account) = self.accounts.get(index) {
|
||||||
let pubkey = account.pubkey.bytes();
|
let pubkey = account.pubkey.bytes();
|
||||||
if let Some(account_data) = self.account_data.get(pubkey) {
|
if let Some(account_data) = self.account_data.get(pubkey) {
|
||||||
let muted = Arc::clone(&account_data.muted.muted);
|
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) {
|
pub fn send_initial_filters(&mut self, pool: &mut RelayPool, relay_url: &str) {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use nostrdb::Note;
|
use nostrdb::Note;
|
||||||
use std::collections::BTreeSet;
|
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<String>;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Muted {
|
pub struct Muted {
|
||||||
@@ -32,14 +33,21 @@ impl std::fmt::Debug for Muted {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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<String> {
|
||||||
|
trace!(
|
||||||
|
"{}: thread: {}",
|
||||||
|
hex::encode(note.id()),
|
||||||
|
hex::encode(thread)
|
||||||
|
);
|
||||||
|
|
||||||
if self.pubkeys.contains(note.pubkey()) {
|
if self.pubkeys.contains(note.pubkey()) {
|
||||||
debug!(
|
debug!(
|
||||||
"{}: MUTED pubkey: {}",
|
"{}: MUTED pubkey: {}",
|
||||||
hex::encode(note.id()),
|
hex::encode(note.id()),
|
||||||
hex::encode(note.pubkey())
|
hex::encode(note.pubkey())
|
||||||
);
|
);
|
||||||
return true;
|
return Some(format!("pubkey {}", hex::encode(note.pubkey())));
|
||||||
}
|
}
|
||||||
// FIXME - Implement hashtag muting here
|
// FIXME - Implement hashtag muting here
|
||||||
|
|
||||||
@@ -51,11 +59,20 @@ impl Muted {
|
|||||||
// for word in &self.words {
|
// for word in &self.words {
|
||||||
// if content.contains(&word.to_lowercase()) {
|
// if content.contains(&word.to_lowercase()) {
|
||||||
// debug!("{}: MUTED word: {}", hex::encode(note.id()), word);
|
// debug!("{}: MUTED word: {}", hex::encode(note.id()), word);
|
||||||
// return true;
|
// return Some(format!("muted word {}", word));
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// FIXME - Implement thread muting here
|
if self.threads.contains(thread) {
|
||||||
false
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use crate::{
|
|||||||
|
|
||||||
use enostr::{NoteId, Pubkey, RelayPool};
|
use enostr::{NoteId, Pubkey, RelayPool};
|
||||||
use nostrdb::{Ndb, Transaction};
|
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)]
|
#[derive(Debug, Eq, PartialEq, Copy, Clone)]
|
||||||
pub enum NoteAction {
|
pub enum NoteAction {
|
||||||
@@ -41,12 +41,11 @@ fn open_thread(
|
|||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
threads: &mut NotesHolderStorage<Thread>,
|
threads: &mut NotesHolderStorage<Thread>,
|
||||||
selected_note: &[u8; 32],
|
selected_note: &[u8; 32],
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Option<NotesHolderResult> {
|
) -> Option<NotesHolderResult> {
|
||||||
router.route_to(Route::thread(NoteId::new(selected_note.to_owned())));
|
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);
|
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 {
|
impl NoteAction {
|
||||||
@@ -60,7 +59,6 @@ impl NoteAction {
|
|||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Option<NotesHolderResult> {
|
) -> Option<NotesHolderResult> {
|
||||||
match self {
|
match self {
|
||||||
NoteAction::Reply(note_id) => {
|
NoteAction::Reply(note_id) => {
|
||||||
@@ -68,28 +66,13 @@ impl NoteAction {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteAction::OpenThread(note_id) => open_thread(
|
NoteAction::OpenThread(note_id) => {
|
||||||
ndb,
|
open_thread(ndb, txn, router, note_cache, pool, threads, note_id.bytes())
|
||||||
txn,
|
}
|
||||||
router,
|
|
||||||
note_cache,
|
|
||||||
pool,
|
|
||||||
threads,
|
|
||||||
note_id.bytes(),
|
|
||||||
is_muted,
|
|
||||||
),
|
|
||||||
|
|
||||||
NoteAction::OpenProfile(pubkey) => {
|
NoteAction::OpenProfile(pubkey) => {
|
||||||
router.route_to(Route::profile(pubkey));
|
router.route_to(Route::profile(pubkey));
|
||||||
Profile::open(
|
Profile::open(ndb, note_cache, txn, pool, profiles, pubkey.bytes())
|
||||||
ndb,
|
|
||||||
note_cache,
|
|
||||||
txn,
|
|
||||||
pool,
|
|
||||||
profiles,
|
|
||||||
pubkey.bytes(),
|
|
||||||
is_muted,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteAction::Quote(note_id) => {
|
NoteAction::Quote(note_id) => {
|
||||||
@@ -111,13 +94,10 @@ impl NoteAction {
|
|||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) {
|
) {
|
||||||
let router = columns.column_mut(col).router_mut();
|
let router = columns.column_mut(col).router_mut();
|
||||||
if let Some(br) = self.execute(
|
if let Some(br) = self.execute(ndb, router, threads, profiles, note_cache, pool, txn) {
|
||||||
ndb, router, threads, profiles, note_cache, pool, txn, is_muted,
|
br.process(ndb, note_cache, txn, threads);
|
||||||
) {
|
|
||||||
br.process(ndb, note_cache, txn, threads, is_muted);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,13 +113,12 @@ impl NotesHolderResult {
|
|||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
storage: &mut NotesHolderStorage<N>,
|
storage: &mut NotesHolderStorage<N>,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
// update the thread for next render if we have new notes
|
// update the thread for next render if we have new notes
|
||||||
NotesHolderResult::NewNotes(new_notes) => {
|
NotesHolderResult::NewNotes(new_notes) => {
|
||||||
let holder = storage
|
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();
|
.get_ptr();
|
||||||
new_notes.process(holder);
|
new_notes.process(holder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,7 +138,6 @@ fn try_process_event(
|
|||||||
app_ctx.pool,
|
app_ctx.pool,
|
||||||
app_ctx.note_cache,
|
app_ctx.note_cache,
|
||||||
timeline,
|
timeline,
|
||||||
&app_ctx.accounts.mutefun(),
|
|
||||||
app_ctx
|
app_ctx
|
||||||
.accounts
|
.accounts
|
||||||
.get_selected_account()
|
.get_selected_account()
|
||||||
@@ -157,7 +156,6 @@ fn try_process_event(
|
|||||||
&txn,
|
&txn,
|
||||||
app_ctx.unknown_ids,
|
app_ctx.unknown_ids,
|
||||||
app_ctx.note_cache,
|
app_ctx.note_cache,
|
||||||
&app_ctx.accounts.mutefun(),
|
|
||||||
) {
|
) {
|
||||||
error!("poll_notes_into_view: {err}");
|
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.ndb,
|
||||||
app_ctx.note_cache,
|
app_ctx.note_cache,
|
||||||
&mut damus.decks_cache,
|
&mut damus.decks_cache,
|
||||||
&app_ctx.accounts.mutefun(),
|
|
||||||
) {
|
) {
|
||||||
warn!("update_damus init: {err}");
|
warn!("update_damus init: {err}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use tracing::{debug, error, info};
|
|||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::Error;
|
use crate::Error;
|
||||||
use notedeck::{MuteFun, NoteRef, UnifiedSubscription};
|
use notedeck::{NoteRef, UnifiedSubscription};
|
||||||
|
|
||||||
pub struct MultiSubscriber {
|
pub struct MultiSubscriber {
|
||||||
filters: Vec<Filter>,
|
filters: Vec<Filter>,
|
||||||
@@ -106,12 +106,7 @@ impl MultiSubscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_for_notes(
|
pub fn poll_for_notes(&mut self, ndb: &Ndb, txn: &Transaction) -> Result<Vec<NoteRef>, Error> {
|
||||||
&mut self,
|
|
||||||
ndb: &Ndb,
|
|
||||||
txn: &Transaction,
|
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Result<Vec<NoteRef>, Error> {
|
|
||||||
let sub = self.sub.as_ref().ok_or(notedeck::Error::no_active_sub())?;
|
let sub = self.sub.as_ref().ok_or(notedeck::Error::no_active_sub())?;
|
||||||
let new_note_keys = ndb.poll_for_notes(sub.local, 500);
|
let new_note_keys = ndb.poll_for_notes(sub.local, 500);
|
||||||
|
|
||||||
@@ -129,10 +124,6 @@ impl MultiSubscriber {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if is_muted(¬e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
notes.push(note);
|
notes.push(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -161,7 +161,6 @@ impl RenderNavResponse {
|
|||||||
ctx.note_cache,
|
ctx.note_cache,
|
||||||
ctx.pool,
|
ctx.pool,
|
||||||
&txn,
|
&txn,
|
||||||
&ctx.accounts.mutefun(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +195,6 @@ impl RenderNavResponse {
|
|||||||
&mut app.threads,
|
&mut app.threads,
|
||||||
ctx.pool,
|
ctx.pool,
|
||||||
root_id,
|
root_id,
|
||||||
&ctx.accounts.mutefun(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +206,6 @@ impl RenderNavResponse {
|
|||||||
&mut app.profiles,
|
&mut app.profiles,
|
||||||
ctx.pool,
|
ctx.pool,
|
||||||
pubkey.bytes(),
|
pubkey.bytes(),
|
||||||
&ctx.accounts.mutefun(),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ use std::collections::HashMap;
|
|||||||
|
|
||||||
use enostr::{Filter, RelayPool};
|
use enostr::{Filter, RelayPool};
|
||||||
use nostrdb::{Ndb, Transaction};
|
use nostrdb::{Ndb, Transaction};
|
||||||
use notedeck::{MuteFun, NoteCache, NoteRef, NoteRefsUnkIdAction};
|
use notedeck::{NoteCache, NoteRef, NoteRefsUnkIdAction};
|
||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
@@ -56,7 +56,6 @@ impl<M: NotesHolder> NotesHolderStorage<M> {
|
|||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
id: &[u8; 32],
|
id: &[u8; 32],
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Vitality<'a, M> {
|
) -> Vitality<'a, M> {
|
||||||
// we can't use the naive hashmap entry API here because lookups
|
// 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
|
// require a copy, wait until we have a raw entry api. We could
|
||||||
@@ -90,7 +89,7 @@ impl<M: NotesHolder> NotesHolderStorage<M> {
|
|||||||
|
|
||||||
self.id_to_object.insert(
|
self.id_to_object.insert(
|
||||||
id.to_owned(),
|
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())
|
Vitality::Fresh(self.id_to_object.get_mut(id).unwrap())
|
||||||
}
|
}
|
||||||
@@ -109,7 +108,6 @@ pub trait NotesHolder {
|
|||||||
id: &[u8; 32],
|
id: &[u8; 32],
|
||||||
filters: Vec<Filter>,
|
filters: Vec<Filter>,
|
||||||
notes: Vec<NoteRef>,
|
notes: Vec<NoteRef>,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Self;
|
) -> Self;
|
||||||
|
|
||||||
#[must_use = "process_action must be handled in the Ok(action) case"]
|
#[must_use = "process_action must be handled in the Ok(action) case"]
|
||||||
@@ -117,11 +115,10 @@ pub trait NotesHolder {
|
|||||||
&mut self,
|
&mut self,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Result<NoteRefsUnkIdAction> {
|
) -> Result<NoteRefsUnkIdAction> {
|
||||||
if let Some(multi_subscriber) = self.get_multi_subscriber() {
|
if let Some(multi_subscriber) = self.get_multi_subscriber() {
|
||||||
let reversed = true;
|
let reversed = true;
|
||||||
let note_refs: Vec<NoteRef> = multi_subscriber.poll_for_notes(ndb, txn, is_muted)?;
|
let note_refs: Vec<NoteRef> = multi_subscriber.poll_for_notes(ndb, txn)?;
|
||||||
self.get_view().insert(¬e_refs, reversed);
|
self.get_view().insert(¬e_refs, reversed);
|
||||||
Ok(NoteRefsUnkIdAction::new(note_refs))
|
Ok(NoteRefsUnkIdAction::new(note_refs))
|
||||||
} else {
|
} else {
|
||||||
@@ -160,10 +157,9 @@ pub trait NotesHolder {
|
|||||||
notes_holder_storage: &mut NotesHolderStorage<M>,
|
notes_holder_storage: &mut NotesHolderStorage<M>,
|
||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
id: &[u8; 32],
|
id: &[u8; 32],
|
||||||
is_muted: &MuteFun,
|
|
||||||
) {
|
) {
|
||||||
let notes_holder = notes_holder_storage
|
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();
|
.get_ptr();
|
||||||
|
|
||||||
if let Some(multi_subscriber) = notes_holder.get_multi_subscriber() {
|
if let Some(multi_subscriber) = notes_holder.get_multi_subscriber() {
|
||||||
@@ -178,9 +174,8 @@ pub trait NotesHolder {
|
|||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
storage: &mut NotesHolderStorage<M>,
|
storage: &mut NotesHolderStorage<M>,
|
||||||
id: &[u8; 32],
|
id: &[u8; 32],
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Option<NotesHolderResult> {
|
) -> Option<NotesHolderResult> {
|
||||||
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 {
|
let (holder, result) = match vitality {
|
||||||
Vitality::Stale(holder) => {
|
Vitality::Stale(holder) => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
use enostr::{Filter, Pubkey};
|
use enostr::{Filter, Pubkey};
|
||||||
use nostrdb::{FilterBuilder, Ndb, ProfileRecord, Transaction};
|
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::{
|
use crate::{
|
||||||
multi_subscriber::MultiSubscriber,
|
multi_subscriber::MultiSubscriber,
|
||||||
@@ -60,7 +60,6 @@ impl Profile {
|
|||||||
source: PubkeySource,
|
source: PubkeySource,
|
||||||
filters: Vec<Filter>,
|
filters: Vec<Filter>,
|
||||||
notes: Vec<NoteRef>,
|
notes: Vec<NoteRef>,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut timeline = Timeline::new(
|
let mut timeline = Timeline::new(
|
||||||
TimelineKind::profile(source),
|
TimelineKind::profile(source),
|
||||||
@@ -68,7 +67,7 @@ impl Profile {
|
|||||||
TimelineTab::full_tabs(),
|
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 {
|
Profile {
|
||||||
timeline,
|
timeline,
|
||||||
@@ -114,7 +113,6 @@ impl NotesHolder for Profile {
|
|||||||
id: &[u8; 32],
|
id: &[u8; 32],
|
||||||
filters: Vec<Filter>,
|
filters: Vec<Filter>,
|
||||||
notes: Vec<NoteRef>,
|
notes: Vec<NoteRef>,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Profile::new(
|
Profile::new(
|
||||||
txn,
|
txn,
|
||||||
@@ -123,7 +121,6 @@ impl NotesHolder for Profile {
|
|||||||
PubkeySource::Explicit(Pubkey::new(*id)),
|
PubkeySource::Explicit(Pubkey::new(*id)),
|
||||||
filters,
|
filters,
|
||||||
notes,
|
notes,
|
||||||
is_muted,
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use nostrdb::{Filter, FilterBuilder, Ndb, Transaction};
|
use nostrdb::{Filter, FilterBuilder, Ndb, Transaction};
|
||||||
use notedeck::{MuteFun, NoteCache, NoteRef};
|
use notedeck::{NoteCache, NoteRef};
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Thread {
|
pub struct Thread {
|
||||||
@@ -74,7 +74,6 @@ impl NotesHolder for Thread {
|
|||||||
_: &[u8; 32],
|
_: &[u8; 32],
|
||||||
_: Vec<Filter>,
|
_: Vec<Filter>,
|
||||||
notes: Vec<NoteRef>,
|
notes: Vec<NoteRef>,
|
||||||
_: &MuteFun,
|
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Thread::new(notes)
|
Thread::new(notes)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ use crate::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use notedeck::{
|
use notedeck::{
|
||||||
filter, CachedNote, FilterError, FilterState, FilterStates, MuteFun, NoteCache, NoteRef,
|
filter, CachedNote, FilterError, FilterState, FilterStates, NoteCache, NoteRef, UnknownIds,
|
||||||
UnknownIds,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
@@ -287,7 +286,6 @@ impl Timeline {
|
|||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
unknown_ids: &mut UnknownIds,
|
unknown_ids: &mut UnknownIds,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let timeline = timelines
|
let timeline = timelines
|
||||||
.get_mut(timeline_idx)
|
.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);
|
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;
|
continue;
|
||||||
};
|
};
|
||||||
if is_muted(¬e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
UnknownIds::update_from_note(txn, ndb, unknown_ids, note_cache, ¬e);
|
UnknownIds::update_from_note(txn, ndb, unknown_ids, note_cache, ¬e);
|
||||||
|
|
||||||
@@ -412,12 +407,11 @@ pub fn setup_new_timeline(
|
|||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
since_optimize: bool,
|
since_optimize: bool,
|
||||||
is_muted: &MuteFun,
|
|
||||||
our_pk: Option<&Pubkey>,
|
our_pk: Option<&Pubkey>,
|
||||||
) {
|
) {
|
||||||
// if we're ready, setup local subs
|
// if we're ready, setup local subs
|
||||||
if is_timeline_ready(ndb, pool, note_cache, timeline, is_muted, our_pk) {
|
if is_timeline_ready(ndb, pool, note_cache, timeline, our_pk) {
|
||||||
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_new_timeline: {err}");
|
error!("setup_new_timeline: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -547,7 +541,6 @@ fn setup_initial_timeline(
|
|||||||
timeline: &mut Timeline,
|
timeline: &mut Timeline,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
filters: &[Filter],
|
filters: &[Filter],
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
timeline.subscription = Some(ndb.subscribe(filters)?);
|
timeline.subscription = Some(ndb.subscribe(filters)?);
|
||||||
let txn = Transaction::new(ndb)?;
|
let txn = Transaction::new(ndb)?;
|
||||||
@@ -562,7 +555,7 @@ fn setup_initial_timeline(
|
|||||||
.map(NoteRef::from_query_result)
|
.map(NoteRef::from_query_result)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
copy_notes_into_timeline(timeline, &txn, ndb, note_cache, notes, is_muted);
|
copy_notes_into_timeline(timeline, &txn, ndb, note_cache, notes);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -573,7 +566,6 @@ pub fn copy_notes_into_timeline(
|
|||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
notes: Vec<NoteRef>,
|
notes: Vec<NoteRef>,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) {
|
) {
|
||||||
let filters = {
|
let filters = {
|
||||||
let views = &timeline.views;
|
let views = &timeline.views;
|
||||||
@@ -585,9 +577,6 @@ pub fn copy_notes_into_timeline(
|
|||||||
for note_ref in notes {
|
for note_ref in notes {
|
||||||
for (view, filter) in filters.iter().enumerate() {
|
for (view, filter) in filters.iter().enumerate() {
|
||||||
if let Ok(note) = ndb.get_note_by_key(txn, note_ref.key) {
|
if let Ok(note) = ndb.get_note_by_key(txn, note_ref.key) {
|
||||||
if is_muted(¬e) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if filter(
|
if filter(
|
||||||
note_cache.cached_note_or_insert_mut(note_ref.key, ¬e),
|
note_cache.cached_note_or_insert_mut(note_ref.key, ¬e),
|
||||||
¬e,
|
¬e,
|
||||||
@@ -603,12 +592,11 @@ pub fn setup_initial_nostrdb_subs(
|
|||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
decks_cache: &mut DecksCache,
|
decks_cache: &mut DecksCache,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for decks in decks_cache.get_all_decks_mut() {
|
for decks in decks_cache.get_all_decks_mut() {
|
||||||
for deck in decks.decks_mut() {
|
for deck in decks.decks_mut() {
|
||||||
for timeline in deck.columns_mut().timelines_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}");
|
error!("setup_initial_nostrdb_subs: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -622,7 +610,6 @@ fn setup_timeline_nostrdb_sub(
|
|||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
timeline: &mut Timeline,
|
timeline: &mut Timeline,
|
||||||
is_muted: &MuteFun,
|
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let filter_state = timeline
|
let filter_state = timeline
|
||||||
.filter
|
.filter
|
||||||
@@ -630,7 +617,7 @@ fn setup_timeline_nostrdb_sub(
|
|||||||
.ok_or(Error::App(notedeck::Error::empty_contact_list()))?
|
.ok_or(Error::App(notedeck::Error::empty_contact_list()))?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
setup_initial_timeline(ndb, timeline, note_cache, &filter_state, is_muted)?;
|
setup_initial_timeline(ndb, timeline, note_cache, &filter_state)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -644,7 +631,6 @@ pub fn is_timeline_ready(
|
|||||||
pool: &mut RelayPool,
|
pool: &mut RelayPool,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
timeline: &mut Timeline,
|
timeline: &mut Timeline,
|
||||||
is_muted: &MuteFun,
|
|
||||||
our_pk: Option<&Pubkey>,
|
our_pk: Option<&Pubkey>,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
// TODO: we should debounce the filter states a bit to make sure we have
|
// 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
|
// we just switched to the ready state, we should send initial
|
||||||
// queries and setup the local subscription
|
// queries and setup the local subscription
|
||||||
info!("Found contact list! Setting up local and remote contact list query");
|
info!("Found contact list! Setting up local and remote contact list query");
|
||||||
setup_initial_timeline(ndb, timeline, note_cache, &filter, is_muted)
|
setup_initial_timeline(ndb, timeline, note_cache, &filter).expect("setup init");
|
||||||
.expect("setup init");
|
|
||||||
timeline
|
timeline
|
||||||
.filter
|
.filter
|
||||||
.set_relay_state(relay_id, FilterState::ready(filter.clone()));
|
.set_relay_state(relay_id, FilterState::ready(filter.clone()));
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ pub fn render_timeline_route(
|
|||||||
img_cache,
|
img_cache,
|
||||||
note_options,
|
note_options,
|
||||||
)
|
)
|
||||||
.ui(ui);
|
.ui(ui, &accounts.mutefun());
|
||||||
|
|
||||||
note_action.map(RenderNavAction::NoteAction)
|
note_action.map(RenderNavAction::NoteAction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -503,7 +503,6 @@ pub fn render_add_column_routes(
|
|||||||
ctx.pool,
|
ctx.pool,
|
||||||
ctx.note_cache,
|
ctx.note_cache,
|
||||||
app.since_optimize,
|
app.since_optimize,
|
||||||
&ctx.accounts.mutefun(),
|
|
||||||
ctx.accounts
|
ctx.accounts
|
||||||
.get_selected_account()
|
.get_selected_account()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@@ -58,20 +58,14 @@ impl<'a> ProfileView<'a> {
|
|||||||
}
|
}
|
||||||
let profile = self
|
let profile = self
|
||||||
.profiles
|
.profiles
|
||||||
.notes_holder_mutated(
|
.notes_holder_mutated(self.ndb, self.note_cache, &txn, self.pubkey.bytes())
|
||||||
self.ndb,
|
|
||||||
self.note_cache,
|
|
||||||
&txn,
|
|
||||||
self.pubkey.bytes(),
|
|
||||||
is_muted,
|
|
||||||
)
|
|
||||||
.get_ptr();
|
.get_ptr();
|
||||||
|
|
||||||
profile.timeline.selected_view =
|
profile.timeline.selected_view =
|
||||||
tabs_ui(ui, profile.timeline.selected_view, &profile.timeline.views);
|
tabs_ui(ui, profile.timeline.selected_view, &profile.timeline.views);
|
||||||
|
|
||||||
// poll for new notes and insert them into our existing notes
|
// 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}");
|
error!("Profile::poll_notes_into_view: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,7 +80,7 @@ impl<'a> ProfileView<'a> {
|
|||||||
self.note_cache,
|
self.note_cache,
|
||||||
self.img_cache,
|
self.img_cache,
|
||||||
)
|
)
|
||||||
.show(ui)
|
.show(ui, is_muted)
|
||||||
})
|
})
|
||||||
.inner
|
.inner
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,13 +93,13 @@ impl<'a> ThreadView<'a> {
|
|||||||
|
|
||||||
let thread = self
|
let thread = self
|
||||||
.threads
|
.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();
|
.get_ptr();
|
||||||
|
|
||||||
// TODO(jb55): skip poll if ThreadResult is fresh?
|
// TODO(jb55): skip poll if ThreadResult is fresh?
|
||||||
|
|
||||||
// poll for new notes and insert them into our existing notes
|
// 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) => {
|
Ok(action) => {
|
||||||
action.process_action(&txn, self.ndb, self.unknown_ids, self.note_cache)
|
action.process_action(&txn, self.ndb, self.unknown_ids, self.note_cache)
|
||||||
}
|
}
|
||||||
@@ -120,7 +120,7 @@ impl<'a> ThreadView<'a> {
|
|||||||
self.note_cache,
|
self.note_cache,
|
||||||
self.img_cache,
|
self.img_cache,
|
||||||
)
|
)
|
||||||
.show(ui)
|
.show(ui, is_muted)
|
||||||
})
|
})
|
||||||
.inner
|
.inner
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,10 +7,11 @@ use crate::{
|
|||||||
ui::note::NoteOptions,
|
ui::note::NoteOptions,
|
||||||
};
|
};
|
||||||
use egui::containers::scroll_area::ScrollBarVisibility;
|
use egui::containers::scroll_area::ScrollBarVisibility;
|
||||||
use egui::{Direction, Layout};
|
use egui::{Color32, Direction, Layout};
|
||||||
use egui_tabs::TabColor;
|
use egui_tabs::TabColor;
|
||||||
use nostrdb::{Ndb, Transaction};
|
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};
|
use tracing::{error, warn};
|
||||||
|
|
||||||
pub struct TimelineView<'a> {
|
pub struct TimelineView<'a> {
|
||||||
@@ -44,7 +45,7 @@ impl<'a> TimelineView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ui(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
pub fn ui(&mut self, ui: &mut egui::Ui, is_muted: &MuteFun) -> Option<NoteAction> {
|
||||||
timeline_ui(
|
timeline_ui(
|
||||||
ui,
|
ui,
|
||||||
self.ndb,
|
self.ndb,
|
||||||
@@ -54,6 +55,7 @@ impl<'a> TimelineView<'a> {
|
|||||||
self.img_cache,
|
self.img_cache,
|
||||||
self.reverse,
|
self.reverse,
|
||||||
self.note_options,
|
self.note_options,
|
||||||
|
is_muted,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,6 +75,7 @@ fn timeline_ui(
|
|||||||
img_cache: &mut ImageCache,
|
img_cache: &mut ImageCache,
|
||||||
reversed: bool,
|
reversed: bool,
|
||||||
note_options: NoteOptions,
|
note_options: NoteOptions,
|
||||||
|
is_muted: &MuteFun,
|
||||||
) -> Option<NoteAction> {
|
) -> Option<NoteAction> {
|
||||||
//padding(4.0, ui, |ui| ui.heading("Notifications"));
|
//padding(4.0, ui, |ui| ui.heading("Notifications"));
|
||||||
/*
|
/*
|
||||||
@@ -124,7 +127,7 @@ fn timeline_ui(
|
|||||||
note_cache,
|
note_cache,
|
||||||
img_cache,
|
img_cache,
|
||||||
)
|
)
|
||||||
.show(ui)
|
.show(ui, is_muted)
|
||||||
})
|
})
|
||||||
.inner
|
.inner
|
||||||
}
|
}
|
||||||
@@ -247,7 +250,7 @@ impl<'a> TimelineTabView<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn show(&mut self, ui: &mut egui::Ui) -> Option<NoteAction> {
|
pub fn show(&mut self, ui: &mut egui::Ui, is_muted: &MuteFun) -> Option<NoteAction> {
|
||||||
let mut action: Option<NoteAction> = None;
|
let mut action: Option<NoteAction> = None;
|
||||||
let len = self.tab.notes.len();
|
let len = self.tab.notes.len();
|
||||||
|
|
||||||
@@ -275,7 +278,19 @@ impl<'a> TimelineTabView<'a> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ui::padding(8.0, ui, |ui| {
|
ui::padding(8.0, ui, |ui| {
|
||||||
let resp = ui::NoteView::new(self.ndb, self.note_cache, self.img_cache, ¬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)
|
.note_options(self.note_options)
|
||||||
.show(ui);
|
.show(ui);
|
||||||
|
|
||||||
@@ -286,6 +301,7 @@ impl<'a> TimelineTabView<'a> {
|
|||||||
if let Some(context) = resp.context_selection {
|
if let Some(context) = resp.context_selection {
|
||||||
context.process(ui, ¬e);
|
context.process(ui, ¬e);
|
||||||
}
|
}
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
ui::hline(ui);
|
ui::hline(ui);
|
||||||
|
|||||||
Reference in New Issue
Block a user