notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

commit 80c9cbe5b2aca5a25561c2ba0584ec26286d064c
parent d141bb0ab5c0d8df9090375da0f04f6ce236b3a9
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 17 Sep 2024 09:29:04 -0700

Merge 'display kind 6 repost impl #302'

Merge kernel's changes for displaying kind6 reposts. We still need to
update the timeline code to fetch and include these in the queries.

kernelkind (2):
      kind 6 repost impl
      add suggested changes

Diffstat:
Aassets/icons/repost_icon_4x.png | 0
Aqueries/reposts.json | 7+++++++
Msrc/ui/note/mod.rs | 65++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Msrc/ui/profile/preview.rs | 15+++++++++++++++
4 files changed, 84 insertions(+), 3 deletions(-)

diff --git a/assets/icons/repost_icon_4x.png b/assets/icons/repost_icon_4x.png Binary files differ. diff --git a/queries/reposts.json b/queries/reposts.json @@ -0,0 +1,7 @@ +{ + "limit": 100, + "kinds": [ + 1, 6 + ], + "#p": ["32e1827635450ebb3c5a7d12c1f8e7b2b514439ac10a67eef3d9fd9c5c68e245"] +} diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs @@ -10,16 +10,18 @@ pub use reply::PostReplyView; use crate::{ actionbar::BarAction, + app_style::NotedeckTextStyle, colors, imgcache::ImageCache, notecache::{CachedNote, NoteCache}, - ui, - ui::View, + ui::{self, View}, }; use egui::{Label, RichText, Sense}; use enostr::NoteId; use nostrdb::{Ndb, Note, NoteKey, NoteReply, Transaction}; +use super::profile::preview::{get_display_name, one_line_display_name_widget}; + pub struct NoteView<'a> { ndb: &'a Ndb, note_cache: &'a mut NoteCache, @@ -325,7 +327,35 @@ impl<'a> NoteView<'a> { action: None, } } else { - self.show_standard(ui) + let txn = self.note.txn().expect("todo: support non-db notes"); + if let Some(note_to_repost) = get_reposted_note(self.ndb, txn, self.note) { + let profile = self.ndb.get_profile_by_pubkey(txn, self.note.pubkey()); + + ui.horizontal(|ui| { + ui.vertical(|ui| { + ui.add_space(2.0); + ui.add_sized([20.0, 20.0], repost_icon()); + }); + ui.add_space(6.0); + let resp = ui.add(one_line_display_name_widget(get_display_name( + profile.as_ref().ok(), + ))); + if let Ok(rec) = &profile { + resp.on_hover_ui_at_pointer(|ui| { + ui.set_max_width(300.0); + ui.add(ui::ProfilePreview::new(rec, self.img_cache)); + }); + } + ui.add_space(4.0); + ui.label( + RichText::new("Reposted") + .text_style(NotedeckTextStyle::Heading3.text_style()), + ); + }); + NoteView::new(self.ndb, self.note_cache, self.img_cache, &note_to_repost).show(ui) + } else { + self.show_standard(ui) + } } } @@ -445,6 +475,30 @@ impl<'a> NoteView<'a> { } } +fn get_reposted_note<'a>(ndb: &Ndb, txn: &'a Transaction, note: &Note) -> Option<Note<'a>> { + let new_note_id: &[u8; 32] = if note.kind() == 6 { + let mut res = None; + for tag in note.tags().iter() { + if tag.count() == 0 { + continue; + } + + if let Some("e") = tag.get(0).and_then(|t| t.variant().str()) { + if let Some(note_id) = tag.get(1).and_then(|f| f.variant().id()) { + res = Some(note_id); + break; + } + } + } + res? + } else { + return None; + }; + + let note = ndb.get_note_by_id(txn, new_note_id).ok(); + note.filter(|note| note.kind() == 1) +} + fn render_note_actionbar( ui: &mut egui::Ui, note_id: &[u8; 32], @@ -532,3 +586,8 @@ fn thread_button(ui: &mut egui::Ui, note_key: NoteKey) -> egui::Response { resp } + +fn repost_icon() -> egui::Image<'static> { + let img_data = egui::include_image!("../../../assets/icons/repost_icon_4x.png"); + egui::Image::new(img_data) +} diff --git a/src/ui/profile/preview.rs b/src/ui/profile/preview.rs @@ -198,6 +198,21 @@ fn display_name_widget( } } +pub fn one_line_display_name_widget(display_name: DisplayName<'_>) -> impl egui::Widget + '_ { + move |ui: &mut egui::Ui| match display_name { + DisplayName::One(n) => { + ui.label(RichText::new(n).text_style(NotedeckTextStyle::Heading3.text_style())) + } + + DisplayName::Both { + display_name, + username: _, + } => ui.label( + RichText::new(display_name).text_style(NotedeckTextStyle::Heading3.text_style()), + ), + } +} + fn about_section_widget<'a>(profile: &'a ProfileRecord<'a>) -> impl egui::Widget + 'a { |ui: &mut egui::Ui| { if let Some(about) = profile.record().profile().and_then(|p| p.about()) {