notedeck

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

commit af8d7d222c05d4b0be296c3b62958d0133d988fb
parent 61bc9d99192c24e71fd5a7bed03a3b1f7d64703e
Author: William Casarin <jb55@jb55.com>
Date:   Wed, 10 Jul 2024 09:53:51 -0700

Add note wide mode for reposts

This adds a 'wide' note design for note previews. This is a mode
where the note contents does not have padding at the start. This makes
notes previews a bit nicer.

Screenshot: https://cdn.jb55.com/s/84271f386d564c34.png
Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/ui/note/contents.rs | 1+
Msrc/ui/note/mod.rs | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Msrc/ui/note/options.rs | 20++++++++++++++++++++
3 files changed, 112 insertions(+), 45 deletions(-)

diff --git a/src/ui/note/contents.rs b/src/ui/note/contents.rs @@ -92,6 +92,7 @@ fn render_note_preview( ui::NoteView::new(app, &note) .actionbar(false) .small_pfp(true) + .wide(true) .note_previews(false) .show(ui); }) diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs @@ -10,7 +10,7 @@ pub use reply::PostReplyView; use crate::{colors, notecache::CachedNote, ui, ui::View, Damus}; use egui::{Label, RichText, Sense}; -use nostrdb::{NoteKey, Transaction}; +use nostrdb::{Note, NoteKey, NoteReply, Transaction}; pub struct NoteView<'a> { app: &'a mut Damus, @@ -29,35 +29,22 @@ impl<'a> View for NoteView<'a> { } } -fn reply_desc( - ui: &mut egui::Ui, - txn: &Transaction, - app: &mut Damus, - note_key: NoteKey, - note: &nostrdb::Note<'_>, -) { +fn reply_desc(ui: &mut egui::Ui, txn: &Transaction, note_reply: &NoteReply, app: &mut Damus) { #[cfg(feature = "profiling")] puffin::profile_function!(); - let note_reply = app - .note_cache_mut() - .cached_note_or_insert_mut(note_key, note) - .reply - .borrow(note.tags()); + ui.add(Label::new( + RichText::new("replying to") + .size(10.0) + .color(colors::GRAY_SECONDARY), + )); let reply = if let Some(reply) = note_reply.reply() { reply } else { - // not a reply, nothing to do here return; }; - ui.add(Label::new( - RichText::new("replying to") - .size(10.0) - .color(colors::GRAY_SECONDARY), - )); - let reply_note = if let Ok(reply_note) = app.ndb.get_note_by_id(txn, reply.id) { reply_note } else { @@ -140,6 +127,11 @@ impl<'a> NoteView<'a> { self } + pub fn wide(mut self, enable: bool) -> Self { + self.options_mut().set_wide(enable); + self + } + pub fn options(&self) -> NoteOptions { self.flags } @@ -196,15 +188,13 @@ impl<'a> NoteView<'a> { profile: &Result<nostrdb::ProfileRecord<'_>, nostrdb::Error>, ui: &mut egui::Ui, ) { - ui.spacing_mut().item_spacing.x = 16.0; - - let pfp_size = if self.options().has_small_pfp() { - ui::ProfilePic::small_size() - } else if self.options().has_medium_pfp() { - ui::ProfilePic::medium_size() + if !self.options().has_wide() { + ui.spacing_mut().item_spacing.x = 16.0; } else { - ui::ProfilePic::default_size() - }; + ui.spacing_mut().item_spacing.x = 4.0; + } + + let pfp_size = self.options().pfp_size(); match profile .as_ref() @@ -262,6 +252,26 @@ impl<'a> NoteView<'a> { } } + fn note_header( + ui: &mut egui::Ui, + app: &mut Damus, + note: &Note, + profile: &Result<nostrdb::ProfileRecord<'_>, nostrdb::Error>, + ) -> egui::Response { + let note_key = note.key().unwrap(); + + ui.horizontal(|ui| { + ui.spacing_mut().item_spacing.x = 2.0; + ui.add(ui::Username::new(profile.as_ref().ok(), note.pubkey()).abbreviated(20)); + + let cached_note = app + .note_cache_mut() + .cached_note_or_insert_mut(note_key, note); + render_reltime(ui, cached_note, true); + }) + .response + } + fn show_standard(&mut self, ui: &mut egui::Ui) -> NoteResponse { #[cfg(feature = "profiling")] puffin::profile_function!(); @@ -270,34 +280,69 @@ impl<'a> NoteView<'a> { let mut note_action: Option<BarAction> = None; let profile = self.app.ndb.get_profile_by_pubkey(txn, self.note.pubkey()); - if self.options().has_wide() { - ui.horizontal_centered(|ui| { + // wide design + let response = if self.options().has_wide() { + ui.horizontal(|ui| { self.pfp(note_key, &profile, ui); + + let size = ui.available_size(); + ui.vertical(|ui| { + ui.add_sized([size.x, self.options().pfp_size()], |ui: &mut egui::Ui| { + ui.horizontal_centered(|ui| { + NoteView::note_header(ui, self.app, self.note, &profile); + }) + .response + }); + + let note_reply = self + .app + .note_cache_mut() + .cached_note_or_insert_mut(note_key, self.note) + .reply + .borrow(self.note.tags()); + + if note_reply.reply().is_some() { + ui.horizontal(|ui| { + reply_desc(ui, txn, &note_reply, self.app); + }); + } + }); }); - } - let response = ui - .with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { + let resp = ui.add(NoteContents::new( + self.app, + txn, + self.note, + note_key, + self.options(), + )); + + if self.options().has_actionbar() { + note_action = render_note_actionbar(ui, note_key).inner; + } + + resp + } else { + // main design + ui.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { self.pfp(note_key, &profile, ui); ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { + NoteView::note_header(ui, self.app, self.note, &profile); + ui.horizontal(|ui| { ui.spacing_mut().item_spacing.x = 2.0; - ui.add( - ui::Username::new(profile.as_ref().ok(), self.note.pubkey()) - .abbreviated(20), - ); - let cached_note = self + let note_reply = self .app .note_cache_mut() - .cached_note_or_insert_mut(note_key, self.note); - render_reltime(ui, cached_note, true); - }); + .cached_note_or_insert_mut(note_key, self.note) + .reply + .borrow(self.note.tags()); - ui.horizontal(|ui| { - ui.spacing_mut().item_spacing.x = 2.0; - reply_desc(ui, txn, self.app, note_key, self.note); + if note_reply.reply().is_some() { + reply_desc(ui, txn, &note_reply, self.app); + } }); ui.add(NoteContents::new( @@ -313,7 +358,8 @@ impl<'a> NoteView<'a> { } }); }) - .response; + .response + }; NoteResponse { response, diff --git a/src/ui/note/options.rs b/src/ui/note/options.rs @@ -1,3 +1,4 @@ +use crate::ui::ProfilePic; use bitflags::bitflags; bitflags! { @@ -34,12 +35,31 @@ impl NoteOptions { (self & NoteOptions::medium_pfp) == NoteOptions::medium_pfp } + pub fn pfp_size(&self) -> f32 { + if self.has_small_pfp() { + ProfilePic::small_size() + } else if self.has_medium_pfp() { + ProfilePic::medium_size() + } else { + ProfilePic::default_size() + } + } + #[inline] pub fn has_wide(self) -> bool { (self & NoteOptions::wide) == NoteOptions::wide } #[inline] + pub fn set_wide(&mut self, enable: bool) { + if enable { + *self |= NoteOptions::wide; + } else { + *self &= !NoteOptions::wide; + } + } + + #[inline] pub fn set_small_pfp(&mut self, enable: bool) { if enable { *self |= NoteOptions::small_pfp;