notedeck

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

commit 24d400d5aa327a27ef50efd9a4d62784c4e1d1cc
parent 0dd33c90e7664d934f0530cf8499d6bc193c436a
Author: William Casarin <jb55@jb55.com>
Date:   Tue, 11 Jun 2024 17:44:35 -0700

small inline preview pfps

Signed-off-by: William Casarin <jb55@jb55.com>

Diffstat:
Msrc/app.rs | 4++--
Msrc/ui/account_management.rs | 1-
Msrc/ui/note/contents.rs | 10+++++-----
Msrc/ui/note/mod.rs | 141++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Msrc/ui/note/options.rs | 20++++++++++++++++++++
Msrc/ui/side_panel.rs | 1-
6 files changed, 110 insertions(+), 67 deletions(-)

diff --git a/src/app.rs b/src/app.rs @@ -651,7 +651,7 @@ impl Damus { is_mobile = Some(true); } else if arg == "--filter" { let next_args = &args[1 + i + 1..]; - if next_args.len() == 0 { + if next_args.is_empty() { continue; } let filter = &next_args[0]; @@ -663,7 +663,7 @@ impl Damus { } } else if arg == "--filter-file" || arg == "-f" { let next_args = &args[1 + i + 1..]; - if next_args.len() == 0 { + if next_args.is_empty() { continue; } let filter_file = &next_args[0]; diff --git a/src/ui/account_management.rs b/src/ui/account_management.rs @@ -199,7 +199,6 @@ fn selected_widget() -> impl egui::Widget { // PREVIEWS mod preview { - use super::*; use crate::test_data::get_account_manager_test_app; diff --git a/src/ui/note/contents.rs b/src/ui/note/contents.rs @@ -89,11 +89,11 @@ fn render_note_preview( ui.visuals().noninteractive().bg_stroke.color, )) .show(ui, |ui| { - ui.add( - ui::Note::new(app, &note) - .actionbar(false) - .note_previews(false), - ) + ui::Note::new(app, &note) + .actionbar(false) + .small_pfp(true) + .note_previews(false) + .show(ui); }) .response } diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs @@ -4,7 +4,7 @@ pub mod options; pub use contents::NoteContents; pub use options::NoteOptions; -use crate::{colors, notecache::CachedNote, ui, Damus}; +use crate::{colors, notecache::CachedNote, ui, ui::View, Damus}; use egui::{Label, RichText, Sense}; use nostrdb::{NoteKey, Transaction}; use std::hash::{Hash, Hasher}; @@ -20,12 +20,12 @@ pub struct NoteResponse { pub action: Option<BarAction>, } -impl<'a> egui::Widget for Note<'a> { - fn ui(self, ui: &mut egui::Ui) -> egui::Response { +impl<'a> View for Note<'a> { + fn ui(&mut self, ui: &mut egui::Ui) { if self.app.textmode { - self.textmode_ui(ui) + self.textmode_ui(ui); } else { - self.show(ui).response + self.show(ui); } } } @@ -140,6 +140,11 @@ impl<'a> Note<'a> { self } + pub fn small_pfp(mut self, enable: bool) -> Self { + self.options_mut().set_small_pfp(enable); + self + } + pub fn note_previews(mut self, enable: bool) -> Self { self.options_mut().set_note_previews(enable); self @@ -153,7 +158,7 @@ impl<'a> Note<'a> { &mut self.flags } - fn textmode_ui(self, ui: &mut egui::Ui) -> egui::Response { + fn textmode_ui(&mut self, ui: &mut egui::Ui) -> egui::Response { let note_key = self.note.key().expect("todo: implement non-db notes"); let txn = self.note.txn().expect("todo: implement non-db notes"); @@ -191,66 +196,86 @@ impl<'a> Note<'a> { .response } - pub fn show(self, ui: &mut egui::Ui) -> NoteResponse { + fn pfp( + &mut self, + note_key: NoteKey, + 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() { + 24.0 + } else { + ui::ProfilePic::default_size() + }; + + match profile + .as_ref() + .ok() + .and_then(|p| p.record().profile()?.picture()) + { + // these have different lifetimes and types, + // so the calls must be separate + Some(pic) => { + let expand_size = 5.0; + let anim_speed = 0.05; + let profile_key = profile.as_ref().unwrap().record().note_key(); + let note_key = note_key.as_u64(); + + if self.app.is_mobile() { + ui.add(ui::ProfilePic::new(&mut self.app.img_cache, pic)); + } else { + let (rect, size) = ui::anim::hover_expand( + ui, + egui::Id::new(ProfileAnimId { + profile_key, + note_key, + }), + pfp_size, + expand_size, + anim_speed, + ); + + ui.put( + rect, + ui::ProfilePic::new(&mut self.app.img_cache, pic).size(size), + ) + .on_hover_ui_at_pointer(|ui| { + ui.set_max_width(300.0); + ui.add(ui::ProfilePreview::new( + profile.as_ref().unwrap(), + &mut self.app.img_cache, + )); + }); + } + } + None => { + ui.add( + ui::ProfilePic::new(&mut self.app.img_cache, ui::ProfilePic::no_pfp_url()) + .size(pfp_size), + ); + } + } + } + + pub fn show(&mut self, ui: &mut egui::Ui) -> NoteResponse { #[cfg(feature = "profiling")] puffin::profile_function!(); let note_key = self.note.key().expect("todo: support non-db notes"); let txn = self.note.txn().expect("todo: support non-db notes"); 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| { + self.pfp(note_key, &profile, ui); + }); + } let response = ui .with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { - ui.spacing_mut().item_spacing.x = 16.0; - - let profile = self.app.ndb.get_profile_by_pubkey(txn, self.note.pubkey()); - - match profile - .as_ref() - .ok() - .and_then(|p| p.record().profile()?.picture()) - { - // these have different lifetimes and types, - // so the calls must be separate - Some(pic) => { - let expand_size = 5.0; - let anim_speed = 0.05; - let profile_key = profile.as_ref().unwrap().record().note_key(); - let note_key = note_key.as_u64(); - - if self.app.is_mobile() { - ui.add(ui::ProfilePic::new(&mut self.app.img_cache, pic)); - } else { - let (rect, size) = ui::anim::hover_expand( - ui, - egui::Id::new(ProfileAnimId { - profile_key, - note_key, - }), - ui::ProfilePic::default_size(), - expand_size, - anim_speed, - ); - - ui.put( - rect, - ui::ProfilePic::new(&mut self.app.img_cache, pic).size(size), - ) - .on_hover_ui_at_pointer(|ui| { - ui.set_max_width(300.0); - ui.add(ui::ProfilePreview::new( - profile.as_ref().unwrap(), - &mut self.app.img_cache, - )); - }); - } - } - None => { - ui.add(ui::ProfilePic::new( - &mut self.app.img_cache, - ui::ProfilePic::no_pfp_url(), - )); - } - } + self.pfp(note_key, &profile, ui); ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { ui.horizontal(|ui| { diff --git a/src/ui/note/options.rs b/src/ui/note/options.rs @@ -7,6 +7,8 @@ bitflags! { pub struct NoteOptions: u32 { const actionbar = 0b00000001; const note_previews = 0b00000010; + const small_pfp = 0b00000100; + const wide = 0b00001000; } } @@ -22,6 +24,24 @@ impl NoteOptions { } #[inline] + pub fn has_small_pfp(self) -> bool { + (self & NoteOptions::small_pfp) == NoteOptions::small_pfp + } + + #[inline] + pub fn has_wide(self) -> bool { + (self & NoteOptions::wide) == NoteOptions::wide + } + + #[inline] + pub fn set_small_pfp(&mut self, enable: bool) { + if enable { + *self |= NoteOptions::small_pfp; + } else { + *self &= !NoteOptions::small_pfp; + } + } + #[inline] pub fn set_note_previews(&mut self, enable: bool) { if enable { *self |= NoteOptions::note_previews; diff --git a/src/ui/side_panel.rs b/src/ui/side_panel.rs @@ -119,7 +119,6 @@ fn add_column_button(dark_mode: bool) -> egui::Button<'static> { } mod preview { - use crate::{ test_data,