Skip muted content
This commit is contained in:
@@ -1,11 +1,12 @@
|
|||||||
use std::cmp::Ordering;
|
use std::cmp::Ordering;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use url::Url;
|
use url::Url;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use enostr::{ClientMessage, FilledKeypair, FullKeypair, Keypair, RelayPool};
|
use enostr::{ClientMessage, FilledKeypair, FullKeypair, Keypair, RelayPool};
|
||||||
use nostrdb::{Filter, Ndb, NoteKey, Subscription, Transaction};
|
use nostrdb::{Filter, Ndb, Note, NoteKey, Subscription, Transaction};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
column::Columns,
|
column::Columns,
|
||||||
@@ -121,7 +122,7 @@ pub struct AccountMutedData {
|
|||||||
filter: Filter,
|
filter: Filter,
|
||||||
subid: String,
|
subid: String,
|
||||||
sub: Option<Subscription>,
|
sub: Option<Subscription>,
|
||||||
muted: Muted,
|
muted: Arc<Muted>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AccountMutedData {
|
impl AccountMutedData {
|
||||||
@@ -160,7 +161,7 @@ impl AccountMutedData {
|
|||||||
filter,
|
filter,
|
||||||
subid,
|
subid,
|
||||||
sub: Some(ndbsub),
|
sub: Some(ndbsub),
|
||||||
muted,
|
muted: Arc::new(muted),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -440,6 +441,19 @@ impl Accounts {
|
|||||||
self.key_store.select_key(None);
|
self.key_store.select_key(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn mutefun(&self) -> Box<dyn Fn(&Note) -> bool> {
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Box::new(|_: &Note| false)
|
||||||
|
}
|
||||||
|
|
||||||
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) {
|
||||||
for data in self.account_data.values() {
|
for data in self.account_data.values() {
|
||||||
pool.send_to(
|
pool.send_to(
|
||||||
@@ -510,7 +524,7 @@ impl Accounts {
|
|||||||
let txn = Transaction::new(ndb).expect("txn");
|
let txn = Transaction::new(ndb).expect("txn");
|
||||||
let muted = AccountMutedData::harvest_nip51_muted(ndb, &txn, &nks);
|
let muted = AccountMutedData::harvest_nip51_muted(ndb, &txn, &nks);
|
||||||
debug!("pubkey {}: updated muted {:?}", hex::encode(pubkey), muted);
|
debug!("pubkey {}: updated muted {:?}", hex::encode(pubkey), muted);
|
||||||
data.muted.muted = muted;
|
data.muted.muted = Arc::new(muted);
|
||||||
changed = true;
|
changed = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
column::Columns,
|
column::Columns,
|
||||||
|
muted::MuteFun,
|
||||||
note::NoteRef,
|
note::NoteRef,
|
||||||
notecache::NoteCache,
|
notecache::NoteCache,
|
||||||
notes_holder::{NotesHolder, NotesHolderStorage},
|
notes_holder::{NotesHolder, NotesHolderStorage},
|
||||||
@@ -32,6 +33,7 @@ pub enum NotesHolderResult {
|
|||||||
/// making sure the thread is up to date. In a sense, it's a model for
|
/// making sure the thread is up to date. In a sense, it's a model for
|
||||||
/// the thread view. We don't have a concept of model/view/controller etc
|
/// the thread view. We don't have a concept of model/view/controller etc
|
||||||
/// in egui, but this is the closest thing to that.
|
/// in egui, but this is the closest thing to that.
|
||||||
|
#[allow(clippy::too_many_arguments)]
|
||||||
fn open_thread(
|
fn open_thread(
|
||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
txn: &Transaction,
|
txn: &Transaction,
|
||||||
@@ -40,11 +42,12 @@ 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 = crate::note::root_note_id_from_selected_id(ndb, note_cache, txn, selected_note);
|
let root_id = crate::note::root_note_id_from_selected_id(ndb, note_cache, txn, selected_note);
|
||||||
Thread::open(ndb, note_cache, txn, pool, threads, root_id)
|
Thread::open(ndb, note_cache, txn, pool, threads, root_id, is_muted)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NoteAction {
|
impl NoteAction {
|
||||||
@@ -58,6 +61,7 @@ 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) => {
|
||||||
@@ -65,13 +69,28 @@ impl NoteAction {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteAction::OpenThread(note_id) => {
|
NoteAction::OpenThread(note_id) => open_thread(
|
||||||
open_thread(ndb, txn, router, note_cache, pool, threads, note_id.bytes())
|
ndb,
|
||||||
}
|
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(ndb, note_cache, txn, pool, profiles, pubkey.bytes())
|
Profile::open(
|
||||||
|
ndb,
|
||||||
|
note_cache,
|
||||||
|
txn,
|
||||||
|
pool,
|
||||||
|
profiles,
|
||||||
|
pubkey.bytes(),
|
||||||
|
is_muted,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
NoteAction::Quote(note_id) => {
|
NoteAction::Quote(note_id) => {
|
||||||
@@ -93,10 +112,13 @@ 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(ndb, router, threads, profiles, note_cache, pool, txn) {
|
if let Some(br) = self.execute(
|
||||||
br.process(ndb, note_cache, txn, threads);
|
ndb, router, threads, profiles, note_cache, pool, txn, is_muted,
|
||||||
|
) {
|
||||||
|
br.process(ndb, note_cache, txn, threads, is_muted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -112,12 +134,13 @@ 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)
|
.notes_holder_mutated(ndb, note_cache, txn, &new_notes.id, is_muted)
|
||||||
.get_ptr();
|
.get_ptr();
|
||||||
new_notes.process(holder);
|
new_notes.process(holder);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -147,6 +147,7 @@ fn try_process_event(damus: &mut Damus, ctx: &egui::Context) -> Result<()> {
|
|||||||
&mut damus.pool,
|
&mut damus.pool,
|
||||||
&mut damus.note_cache,
|
&mut damus.note_cache,
|
||||||
timeline,
|
timeline,
|
||||||
|
&damus.accounts.mutefun(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,6 +161,7 @@ fn try_process_event(damus: &mut Damus, ctx: &egui::Context) -> Result<()> {
|
|||||||
&txn,
|
&txn,
|
||||||
&mut damus.unknown_ids,
|
&mut damus.unknown_ids,
|
||||||
&mut damus.note_cache,
|
&mut damus.note_cache,
|
||||||
|
&damus.accounts.mutefun(),
|
||||||
) {
|
) {
|
||||||
error!("poll_notes_into_view: {err}");
|
error!("poll_notes_into_view: {err}");
|
||||||
}
|
}
|
||||||
@@ -208,6 +210,7 @@ fn update_damus(damus: &mut Damus, ctx: &egui::Context) {
|
|||||||
&damus.ndb,
|
&damus.ndb,
|
||||||
&mut damus.note_cache,
|
&mut damus.note_cache,
|
||||||
&mut damus.columns,
|
&mut damus.columns,
|
||||||
|
&damus.accounts.mutefun(),
|
||||||
) {
|
) {
|
||||||
warn!("update_damus init: {err}");
|
warn!("update_damus init: {err}");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use nostrdb::{Ndb, Note, Transaction};
|
|||||||
use tracing::{debug, error, info};
|
use tracing::{debug, error, info};
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
use crate::{filter::UnifiedSubscription, note::NoteRef, Error};
|
use crate::{filter::UnifiedSubscription, muted::MuteFun, note::NoteRef, Error};
|
||||||
|
|
||||||
pub struct MultiSubscriber {
|
pub struct MultiSubscriber {
|
||||||
filters: Vec<Filter>,
|
filters: Vec<Filter>,
|
||||||
@@ -105,7 +105,12 @@ impl MultiSubscriber {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn poll_for_notes(&mut self, ndb: &Ndb, txn: &Transaction) -> Result<Vec<NoteRef>, Error> {
|
pub fn poll_for_notes(
|
||||||
|
&mut self,
|
||||||
|
ndb: &Ndb,
|
||||||
|
txn: &Transaction,
|
||||||
|
is_muted: &MuteFun,
|
||||||
|
) -> Result<Vec<NoteRef>, Error> {
|
||||||
let sub = self.sub.as_ref().ok_or(Error::no_active_sub())?;
|
let sub = self.sub.as_ref().ok_or(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);
|
||||||
|
|
||||||
@@ -123,6 +128,10 @@ impl MultiSubscriber {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if is_muted(¬e) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
notes.push(note);
|
notes.push(note);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ use std::collections::BTreeSet;
|
|||||||
|
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
|
pub type MuteFun = dyn Fn(&Note) -> bool;
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
pub struct Muted {
|
pub struct Muted {
|
||||||
// TODO - implement private mutes
|
// TODO - implement private mutes
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ impl RenderNavResponse {
|
|||||||
&mut app.note_cache,
|
&mut app.note_cache,
|
||||||
&mut app.pool,
|
&mut app.pool,
|
||||||
&txn,
|
&txn,
|
||||||
|
&app.accounts.mutefun(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,6 +110,7 @@ impl RenderNavResponse {
|
|||||||
&mut app.threads,
|
&mut app.threads,
|
||||||
&mut app.pool,
|
&mut app.pool,
|
||||||
root_id,
|
root_id,
|
||||||
|
&app.accounts.mutefun(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +122,7 @@ impl RenderNavResponse {
|
|||||||
&mut app.profiles,
|
&mut app.profiles,
|
||||||
&mut app.pool,
|
&mut app.pool,
|
||||||
pubkey.bytes(),
|
pubkey.bytes(),
|
||||||
|
&app.accounts.mutefun(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
col_changed = true;
|
col_changed = true;
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ use nostrdb::{Ndb, Transaction};
|
|||||||
use tracing::{debug, info, warn};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actionbar::NotesHolderResult, multi_subscriber::MultiSubscriber, note::NoteRef,
|
actionbar::NotesHolderResult, multi_subscriber::MultiSubscriber, muted::MuteFun, note::NoteRef,
|
||||||
notecache::NoteCache, timeline::TimelineTab, unknowns::NoteRefsUnkIdAction, Error, Result,
|
notecache::NoteCache, timeline::TimelineTab, unknowns::NoteRefsUnkIdAction, Error, Result,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -55,6 +55,7 @@ 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
|
||||||
@@ -88,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),
|
M::new_notes_holder(txn, ndb, note_cache, id, M::filters(id), notes, is_muted),
|
||||||
);
|
);
|
||||||
Vitality::Fresh(self.id_to_object.get_mut(id).unwrap())
|
Vitality::Fresh(self.id_to_object.get_mut(id).unwrap())
|
||||||
}
|
}
|
||||||
@@ -107,6 +108,7 @@ 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"]
|
||||||
@@ -114,10 +116,11 @@ 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)?;
|
let note_refs: Vec<NoteRef> = multi_subscriber.poll_for_notes(ndb, txn, is_muted)?;
|
||||||
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 {
|
||||||
@@ -156,9 +159,10 @@ 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)
|
.notes_holder_mutated(ndb, note_cache, txn, id, is_muted)
|
||||||
.get_ptr();
|
.get_ptr();
|
||||||
|
|
||||||
if let Some(multi_subscriber) = notes_holder.get_multi_subscriber() {
|
if let Some(multi_subscriber) = notes_holder.get_multi_subscriber() {
|
||||||
@@ -173,8 +177,9 @@ 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);
|
let vitality = storage.notes_holder_mutated(ndb, note_cache, txn, id, is_muted);
|
||||||
|
|
||||||
let (holder, result) = match vitality {
|
let (holder, result) = match vitality {
|
||||||
Vitality::Stale(holder) => {
|
Vitality::Stale(holder) => {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use nostrdb::{FilterBuilder, Ndb, ProfileRecord, Transaction};
|
|||||||
use crate::{
|
use crate::{
|
||||||
filter::{self, FilterState},
|
filter::{self, FilterState},
|
||||||
multi_subscriber::MultiSubscriber,
|
multi_subscriber::MultiSubscriber,
|
||||||
|
muted::MuteFun,
|
||||||
note::NoteRef,
|
note::NoteRef,
|
||||||
notecache::NoteCache,
|
notecache::NoteCache,
|
||||||
notes_holder::NotesHolder,
|
notes_holder::NotesHolder,
|
||||||
@@ -61,11 +62,12 @@ 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 =
|
let mut timeline =
|
||||||
Timeline::new(TimelineKind::profile(source), FilterState::ready(filters));
|
Timeline::new(TimelineKind::profile(source), FilterState::ready(filters));
|
||||||
|
|
||||||
copy_notes_into_timeline(&mut timeline, txn, ndb, note_cache, notes);
|
copy_notes_into_timeline(&mut timeline, txn, ndb, note_cache, notes, is_muted);
|
||||||
|
|
||||||
Profile {
|
Profile {
|
||||||
timeline,
|
timeline,
|
||||||
@@ -111,6 +113,7 @@ 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,
|
||||||
@@ -119,6 +122,7 @@ impl NotesHolder for Profile {
|
|||||||
PubkeySource::Explicit(Pubkey::new(*id)),
|
PubkeySource::Explicit(Pubkey::new(*id)),
|
||||||
filters,
|
filters,
|
||||||
notes,
|
notes,
|
||||||
|
is_muted,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
multi_subscriber::MultiSubscriber,
|
multi_subscriber::MultiSubscriber,
|
||||||
|
muted::MuteFun,
|
||||||
note::NoteRef,
|
note::NoteRef,
|
||||||
notecache::NoteCache,
|
notecache::NoteCache,
|
||||||
notes_holder::NotesHolder,
|
notes_holder::NotesHolder,
|
||||||
@@ -74,6 +75,7 @@ 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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ use crate::{
|
|||||||
column::Columns,
|
column::Columns,
|
||||||
error::{Error, FilterError},
|
error::{Error, FilterError},
|
||||||
filter::{self, FilterState, FilterStates},
|
filter::{self, FilterState, FilterStates},
|
||||||
|
muted::MuteFun,
|
||||||
note::NoteRef,
|
note::NoteRef,
|
||||||
notecache::{CachedNote, NoteCache},
|
notecache::{CachedNote, NoteCache},
|
||||||
subscriptions::{self, SubKind, Subscriptions},
|
subscriptions::{self, SubKind, Subscriptions},
|
||||||
@@ -277,6 +278,7 @@ 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)
|
||||||
@@ -299,6 +301,9 @@ 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);
|
||||||
|
|
||||||
@@ -407,10 +412,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,
|
||||||
) {
|
) {
|
||||||
// if we're ready, setup local subs
|
// if we're ready, setup local subs
|
||||||
if is_timeline_ready(ndb, pool, note_cache, timeline) {
|
if is_timeline_ready(ndb, pool, note_cache, timeline, is_muted) {
|
||||||
if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline) {
|
if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline, is_muted) {
|
||||||
error!("setup_new_timeline: {err}");
|
error!("setup_new_timeline: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -540,6 +546,7 @@ 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)?;
|
||||||
@@ -554,7 +561,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);
|
copy_notes_into_timeline(timeline, &txn, ndb, note_cache, notes, is_muted);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -565,6 +572,7 @@ 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;
|
||||||
@@ -576,6 +584,9 @@ 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,
|
||||||
@@ -591,9 +602,10 @@ pub fn setup_initial_nostrdb_subs(
|
|||||||
ndb: &Ndb,
|
ndb: &Ndb,
|
||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
columns: &mut Columns,
|
columns: &mut Columns,
|
||||||
|
is_muted: &MuteFun,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for timeline in columns.timelines_mut() {
|
for timeline in columns.timelines_mut() {
|
||||||
if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline) {
|
if let Err(err) = setup_timeline_nostrdb_sub(ndb, note_cache, timeline, is_muted) {
|
||||||
error!("setup_initial_nostrdb_subs: {err}");
|
error!("setup_initial_nostrdb_subs: {err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -605,6 +617,7 @@ 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
|
||||||
@@ -612,7 +625,7 @@ fn setup_timeline_nostrdb_sub(
|
|||||||
.ok_or(Error::empty_contact_list())?
|
.ok_or(Error::empty_contact_list())?
|
||||||
.to_owned();
|
.to_owned();
|
||||||
|
|
||||||
setup_initial_timeline(ndb, timeline, note_cache, &filter_state)?;
|
setup_initial_timeline(ndb, timeline, note_cache, &filter_state, is_muted)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -626,6 +639,7 @@ 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,
|
||||||
) -> 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
|
||||||
// seen all of the different contact lists from each relay
|
// seen all of the different contact lists from each relay
|
||||||
@@ -680,7 +694,8 @@ 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).expect("setup init");
|
setup_initial_timeline(ndb, timeline, note_cache, &filter, is_muted)
|
||||||
|
.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()));
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ use crate::{
|
|||||||
column::Columns,
|
column::Columns,
|
||||||
draft::Drafts,
|
draft::Drafts,
|
||||||
imgcache::ImageCache,
|
imgcache::ImageCache,
|
||||||
|
muted::MuteFun,
|
||||||
nav::RenderNavAction,
|
nav::RenderNavAction,
|
||||||
notecache::NoteCache,
|
notecache::NoteCache,
|
||||||
notes_holder::NotesHolderStorage,
|
notes_holder::NotesHolderStorage,
|
||||||
@@ -82,7 +83,7 @@ pub fn render_timeline_route(
|
|||||||
textmode,
|
textmode,
|
||||||
)
|
)
|
||||||
.id_source(egui::Id::new(("threadscroll", col)))
|
.id_source(egui::Id::new(("threadscroll", col)))
|
||||||
.ui(ui)
|
.ui(ui, &accounts.mutefun())
|
||||||
.map(Into::into),
|
.map(Into::into),
|
||||||
|
|
||||||
TimelineRoute::Reply(id) => {
|
TimelineRoute::Reply(id) => {
|
||||||
@@ -118,9 +119,16 @@ pub fn render_timeline_route(
|
|||||||
action.map(Into::into)
|
action.map(Into::into)
|
||||||
}
|
}
|
||||||
|
|
||||||
TimelineRoute::Profile(pubkey) => {
|
TimelineRoute::Profile(pubkey) => render_profile_route(
|
||||||
render_profile_route(&pubkey, ndb, profiles, img_cache, note_cache, col, ui)
|
&pubkey,
|
||||||
}
|
ndb,
|
||||||
|
profiles,
|
||||||
|
img_cache,
|
||||||
|
note_cache,
|
||||||
|
col,
|
||||||
|
ui,
|
||||||
|
&accounts.mutefun(),
|
||||||
|
),
|
||||||
|
|
||||||
TimelineRoute::Quote(id) => {
|
TimelineRoute::Quote(id) => {
|
||||||
let txn = Transaction::new(ndb).expect("txn");
|
let txn = Transaction::new(ndb).expect("txn");
|
||||||
@@ -157,6 +165,7 @@ pub fn render_profile_route(
|
|||||||
note_cache: &mut NoteCache,
|
note_cache: &mut NoteCache,
|
||||||
col: usize,
|
col: usize,
|
||||||
ui: &mut egui::Ui,
|
ui: &mut egui::Ui,
|
||||||
|
is_muted: &MuteFun,
|
||||||
) -> Option<RenderNavAction> {
|
) -> Option<RenderNavAction> {
|
||||||
let note_action = ProfileView::new(
|
let note_action = ProfileView::new(
|
||||||
pubkey,
|
pubkey,
|
||||||
@@ -167,7 +176,7 @@ pub fn render_profile_route(
|
|||||||
img_cache,
|
img_cache,
|
||||||
NoteOptions::default(),
|
NoteOptions::default(),
|
||||||
)
|
)
|
||||||
.ui(ui);
|
.ui(ui, is_muted);
|
||||||
|
|
||||||
note_action.map(RenderNavAction::NoteAction)
|
note_action.map(RenderNavAction::NoteAction)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,6 +374,7 @@ pub fn render_add_column_routes(
|
|||||||
&mut app.pool,
|
&mut app.pool,
|
||||||
&mut app.note_cache,
|
&mut app.note_cache,
|
||||||
app.since_optimize,
|
app.since_optimize,
|
||||||
|
&app.accounts.mutefun(),
|
||||||
);
|
);
|
||||||
app.columns_mut().add_timeline_to_column(col, timeline);
|
app.columns_mut().add_timeline_to_column(col, timeline);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub use picture::ProfilePic;
|
|||||||
pub use preview::ProfilePreview;
|
pub use preview::ProfilePreview;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
actionbar::NoteAction, imgcache::ImageCache, notecache::NoteCache,
|
actionbar::NoteAction, imgcache::ImageCache, muted::MuteFun, notecache::NoteCache,
|
||||||
notes_holder::NotesHolderStorage, profile::Profile,
|
notes_holder::NotesHolderStorage, profile::Profile,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ impl<'a> ProfileView<'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> {
|
||||||
let scroll_id = egui::Id::new(("profile_scroll", self.col_id, self.pubkey));
|
let scroll_id = egui::Id::new(("profile_scroll", self.col_id, self.pubkey));
|
||||||
|
|
||||||
ScrollArea::vertical()
|
ScrollArea::vertical()
|
||||||
@@ -58,7 +58,13 @@ impl<'a> ProfileView<'a> {
|
|||||||
}
|
}
|
||||||
let profile = self
|
let profile = self
|
||||||
.profiles
|
.profiles
|
||||||
.notes_holder_mutated(self.ndb, self.note_cache, &txn, self.pubkey.bytes())
|
.notes_holder_mutated(
|
||||||
|
self.ndb,
|
||||||
|
self.note_cache,
|
||||||
|
&txn,
|
||||||
|
self.pubkey.bytes(),
|
||||||
|
is_muted,
|
||||||
|
)
|
||||||
.get_ptr();
|
.get_ptr();
|
||||||
|
|
||||||
profile.timeline.selected_view = tabs_ui(ui);
|
profile.timeline.selected_view = tabs_ui(ui);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
actionbar::NoteAction,
|
actionbar::NoteAction,
|
||||||
imgcache::ImageCache,
|
imgcache::ImageCache,
|
||||||
|
muted::MuteFun,
|
||||||
notecache::NoteCache,
|
notecache::NoteCache,
|
||||||
notes_holder::{NotesHolder, NotesHolderStorage},
|
notes_holder::{NotesHolder, NotesHolderStorage},
|
||||||
thread::Thread,
|
thread::Thread,
|
||||||
@@ -52,7 +53,7 @@ impl<'a> ThreadView<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
let txn = Transaction::new(self.ndb).expect("txn");
|
let txn = Transaction::new(self.ndb).expect("txn");
|
||||||
|
|
||||||
let selected_note_key = if let Ok(key) = self
|
let selected_note_key = if let Ok(key) = self
|
||||||
@@ -97,13 +98,13 @@ impl<'a> ThreadView<'a> {
|
|||||||
|
|
||||||
let thread = self
|
let thread = self
|
||||||
.threads
|
.threads
|
||||||
.notes_holder_mutated(self.ndb, self.note_cache, &txn, root_id)
|
.notes_holder_mutated(self.ndb, self.note_cache, &txn, root_id, is_muted)
|
||||||
.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) {
|
match thread.poll_notes_into_view(&txn, self.ndb, is_muted) {
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user