Merge is_following fixes from kernel

kernelkind (4):
      add `Accounts` to `NoteContext`
      remove `MuteFun` prop
      make `Contacts::is_following` use bytes instead of `Pubkey`
      migrate to check following through `Contacts::is_following`
This commit is contained in:
William Casarin
2025-07-16 08:50:42 -07:00
16 changed files with 84 additions and 268 deletions

View File

@@ -1,58 +1,5 @@
use nostrdb::{Filter, Ndb, Note, Transaction};
fn pk1_is_following_pk2(
ndb: &Ndb,
txn: &Transaction,
pk1: &[u8; 32],
pk2: &[u8; 32],
) -> Option<bool> {
let note = get_contacts_note(ndb, txn, pk1)?;
Some(note_follows(note, pk2))
}
pub fn trust_media_from_pk2(
ndb: &Ndb,
txn: &Transaction,
pk1: Option<&[u8; 32]>,
pk2: &[u8; 32],
) -> bool {
pk1.map(|pk| pk == pk2 || pk1_is_following_pk2(ndb, txn, pk, pk2).unwrap_or(false))
.unwrap_or(false)
}
fn get_contacts_note<'a>(ndb: &'a Ndb, txn: &'a Transaction, user: &[u8; 32]) -> Option<Note<'a>> {
Some(
ndb.query(txn, &[contacts_filter(user)], 1)
.ok()?
.first()?
.note
.clone(),
)
}
use nostrdb::Filter;
pub fn contacts_filter(pk: &[u8; 32]) -> Filter {
Filter::new().authors([pk]).kinds([3]).limit(1).build()
}
fn note_follows(contacts_note: Note<'_>, pk: &[u8; 32]) -> bool {
for tag in contacts_note.tags() {
if tag.count() < 2 {
continue;
}
let Some("p") = tag.get_str(0) else {
continue;
};
let Some(author) = tag.get_id(1) else {
continue;
};
if pk == author {
return true;
}
}
false
}

View File

@@ -2,23 +2,20 @@ use std::cell::OnceCell;
use crate::{
blur::imeta_blurhashes,
contacts::trust_media_from_pk2,
jobs::JobsCache,
note::{NoteAction, NoteOptions, NoteResponse, NoteView},
};
use egui::{Color32, Hyperlink, RichText};
use enostr::KeypairUnowned;
use nostrdb::{BlockType, Mention, Note, NoteKey, Transaction};
use tracing::warn;
use notedeck::NoteContext;
use notedeck::{IsFollowing, NoteContext};
use super::media::{find_renderable_media, image_carousel, RenderableMedia};
pub struct NoteContents<'a, 'd> {
note_context: &'a mut NoteContext<'d>,
cur_acc: Option<&'a KeypairUnowned<'a>>,
txn: &'a Transaction,
note: &'a Note<'a>,
options: NoteOptions,
@@ -30,7 +27,6 @@ impl<'a, 'd> NoteContents<'a, 'd> {
#[allow(clippy::too_many_arguments)]
pub fn new(
note_context: &'a mut NoteContext<'d>,
cur_acc: Option<&'a KeypairUnowned<'a>>,
txn: &'a Transaction,
note: &'a Note,
options: NoteOptions,
@@ -38,7 +34,6 @@ impl<'a, 'd> NoteContents<'a, 'd> {
) -> Self {
NoteContents {
note_context,
cur_acc,
txn,
note,
options,
@@ -53,7 +48,6 @@ impl egui::Widget for &mut NoteContents<'_, '_> {
let result = render_note_contents(
ui,
self.note_context,
self.cur_acc,
self.txn,
self.note,
self.options,
@@ -71,7 +65,6 @@ impl egui::Widget for &mut NoteContents<'_, '_> {
pub fn render_note_preview(
ui: &mut egui::Ui,
note_context: &mut NoteContext,
cur_acc: Option<&KeypairUnowned>,
txn: &Transaction,
id: &[u8; 32],
parent: NoteKey,
@@ -105,7 +98,7 @@ pub fn render_note_preview(
*/
};
NoteView::new(note_context, cur_acc, &note, note_options, jobs)
NoteView::new(note_context, &note, note_options, jobs)
.preview_style()
.parent(parent)
.show(ui)
@@ -116,7 +109,6 @@ pub fn render_note_preview(
pub fn render_note_contents(
ui: &mut egui::Ui,
note_context: &mut NoteContext,
cur_acc: Option<&KeypairUnowned>,
txn: &Transaction,
note: &Note,
options: NoteOptions,
@@ -275,7 +267,7 @@ pub fn render_note_contents(
});
let preview_note_action = inline_note.and_then(|(id, _)| {
render_note_preview(ui, note_context, cur_acc, txn, id, note_key, options, jobs)
render_note_preview(ui, note_context, txn, id, note_key, options, jobs)
.action
.map(|a| match a {
NoteAction::Note { note_id, .. } => NoteAction::Note {
@@ -291,12 +283,11 @@ pub fn render_note_contents(
ui.add_space(2.0);
let carousel_id = egui::Id::new(("carousel", note.key().expect("expected tx note")));
let trusted_media = trust_media_from_pk2(
note_context.ndb,
txn,
cur_acc.as_ref().map(|k| k.pubkey.bytes()),
note.pubkey(),
);
let trusted_media = note_context
.accounts
.get_selected_account()
.is_following(note.pubkey())
== IsFollowing::Yes;
media_action = image_carousel(
ui,

View File

@@ -33,7 +33,6 @@ use notedeck::{
pub struct NoteView<'a, 'd> {
note_context: &'a mut NoteContext<'d>,
zapping_acc: Option<&'a KeypairUnowned<'a>>,
parent: Option<NoteKey>,
note: &'a nostrdb::Note<'a>,
framed: bool,
@@ -85,7 +84,6 @@ impl egui::Widget for &mut NoteView<'_, '_> {
impl<'a, 'd> NoteView<'a, 'd> {
pub fn new(
note_context: &'a mut NoteContext<'d>,
zapping_acc: Option<&'a KeypairUnowned<'a>>,
note: &'a nostrdb::Note<'a>,
mut flags: NoteOptions,
jobs: &'a mut JobsCache,
@@ -98,7 +96,6 @@ impl<'a, 'd> NoteView<'a, 'd> {
Self {
note_context,
zapping_acc,
parent,
note,
flags,
@@ -231,7 +228,6 @@ impl<'a, 'd> NoteView<'a, 'd> {
ui.add(&mut NoteContents::new(
self.note_context,
self.zapping_acc,
txn,
self.note,
self.flags,
@@ -317,14 +313,7 @@ impl<'a, 'd> NoteView<'a, 'd> {
.text_style(style.text_style()),
);
});
NoteView::new(
self.note_context,
self.zapping_acc,
&note_to_repost,
self.flags,
self.jobs,
)
.show(ui)
NoteView::new(self.note_context, &note_to_repost, self.flags, self.jobs).show(ui)
}
pub fn show_impl(&mut self, ui: &mut egui::Ui) -> NoteResponse {
@@ -440,7 +429,6 @@ impl<'a, 'd> NoteView<'a, 'd> {
ui.horizontal(|ui| {
note_action = reply_desc(
ui,
self.zapping_acc,
txn,
&note_reply,
self.note_context,
@@ -455,32 +443,27 @@ impl<'a, 'd> NoteView<'a, 'd> {
})
.inner;
let mut contents = NoteContents::new(
self.note_context,
self.zapping_acc,
txn,
self.note,
self.flags,
self.jobs,
);
let mut contents =
NoteContents::new(self.note_context, txn, self.note, self.flags, self.jobs);
ui.add(&mut contents);
note_action = contents.action.or(note_action);
if self.options().contains(NoteOptions::ActionBar) {
note_action = render_note_actionbar(
ui,
self.zapping_acc.as_ref().map(|c| Zapper {
let zapper = {
let cur_acc = self.note_context.accounts.get_selected_account();
let has_wallet = cur_acc.wallet.is_some();
has_wallet.then_some(Zapper {
zaps: self.note_context.zaps,
cur_acc: c,
}),
self.note.id(),
self.note.pubkey(),
note_key,
)
.inner
.or(note_action);
cur_acc: cur_acc.keypair(),
})
};
note_action =
render_note_actionbar(ui, zapper, self.note.id(), self.note.pubkey(), note_key)
.inner
.or(note_action);
}
NoteUiResponse {
@@ -527,7 +510,6 @@ impl<'a, 'd> NoteView<'a, 'd> {
note_action = reply_desc(
ui,
self.zapping_acc,
txn,
&note_reply,
self.note_context,
@@ -537,25 +519,25 @@ impl<'a, 'd> NoteView<'a, 'd> {
.or(note_action.take());
});
let mut contents = NoteContents::new(
self.note_context,
self.zapping_acc,
txn,
self.note,
self.flags,
self.jobs,
);
let mut contents =
NoteContents::new(self.note_context, txn, self.note, self.flags, self.jobs);
ui.add(&mut contents);
note_action = contents.action.or(note_action);
let zapper = {
let cur_acc = self.note_context.accounts.get_selected_account();
let has_wallet = cur_acc.wallet.is_some();
has_wallet.then_some(Zapper {
zaps: self.note_context.zaps,
cur_acc: cur_acc.keypair(),
})
};
if self.options().contains(NoteOptions::ActionBar) {
note_action = render_note_actionbar(
ui,
self.zapping_acc.as_ref().map(|c| Zapper {
zaps: self.note_context.zaps,
cur_acc: c,
}),
zapper,
self.note.id(),
self.note.pubkey(),
note_key,
@@ -774,7 +756,7 @@ fn note_hitbox_clicked(
struct Zapper<'a> {
zaps: &'a Zaps,
cur_acc: &'a KeypairUnowned<'a>,
cur_acc: KeypairUnowned<'a>,
}
#[profiling::function]

View File

@@ -3,14 +3,12 @@ use nostrdb::{Note, NoteReply, Transaction};
use super::NoteOptions;
use crate::{jobs::JobsCache, note::NoteView, Mention};
use enostr::KeypairUnowned;
use notedeck::{NoteAction, NoteContext};
#[must_use = "Please handle the resulting note action"]
#[profiling::function]
pub fn reply_desc(
ui: &mut egui::Ui,
cur_acc: Option<&KeypairUnowned>,
txn: &Transaction,
note_reply: &NoteReply,
note_context: &mut NoteContext,
@@ -43,7 +41,7 @@ pub fn reply_desc(
if r.hovered() {
r.on_hover_ui_at_pointer(|ui| {
ui.set_max_width(400.0);
NoteView::new(note_context, cur_acc, note, note_options, jobs)
NoteView::new(note_context, note, note_options, jobs)
.actionbar(false)
.wide(true)
.show(ui);