small inline preview pfps

Signed-off-by: William Casarin <jb55@jb55.com>
This commit is contained in:
William Casarin
2024-06-11 17:44:35 -07:00
parent 0dd33c90e7
commit 24d400d5aa
6 changed files with 110 additions and 67 deletions

View File

@@ -651,7 +651,7 @@ impl Damus {
is_mobile = Some(true); is_mobile = Some(true);
} else if arg == "--filter" { } else if arg == "--filter" {
let next_args = &args[1 + i + 1..]; let next_args = &args[1 + i + 1..];
if next_args.len() == 0 { if next_args.is_empty() {
continue; continue;
} }
let filter = &next_args[0]; let filter = &next_args[0];
@@ -663,7 +663,7 @@ impl Damus {
} }
} else if arg == "--filter-file" || arg == "-f" { } else if arg == "--filter-file" || arg == "-f" {
let next_args = &args[1 + i + 1..]; let next_args = &args[1 + i + 1..];
if next_args.len() == 0 { if next_args.is_empty() {
continue; continue;
} }
let filter_file = &next_args[0]; let filter_file = &next_args[0];

View File

@@ -200,7 +200,6 @@ fn selected_widget() -> impl egui::Widget {
mod preview { mod preview {
use super::*; use super::*;
use crate::test_data::get_account_manager_test_app; use crate::test_data::get_account_manager_test_app;

View File

@@ -89,11 +89,11 @@ fn render_note_preview(
ui.visuals().noninteractive().bg_stroke.color, ui.visuals().noninteractive().bg_stroke.color,
)) ))
.show(ui, |ui| { .show(ui, |ui| {
ui.add( ui::Note::new(app, &note)
ui::Note::new(app, &note) .actionbar(false)
.actionbar(false) .small_pfp(true)
.note_previews(false), .note_previews(false)
) .show(ui);
}) })
.response .response
} }

View File

@@ -4,7 +4,7 @@ pub mod options;
pub use contents::NoteContents; pub use contents::NoteContents;
pub use options::NoteOptions; 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 egui::{Label, RichText, Sense};
use nostrdb::{NoteKey, Transaction}; use nostrdb::{NoteKey, Transaction};
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
@@ -20,12 +20,12 @@ pub struct NoteResponse {
pub action: Option<BarAction>, pub action: Option<BarAction>,
} }
impl<'a> egui::Widget for Note<'a> { impl<'a> View for Note<'a> {
fn ui(self, ui: &mut egui::Ui) -> egui::Response { fn ui(&mut self, ui: &mut egui::Ui) {
if self.app.textmode { if self.app.textmode {
self.textmode_ui(ui) self.textmode_ui(ui);
} else { } else {
self.show(ui).response self.show(ui);
} }
} }
} }
@@ -140,6 +140,11 @@ impl<'a> Note<'a> {
self 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 { pub fn note_previews(mut self, enable: bool) -> Self {
self.options_mut().set_note_previews(enable); self.options_mut().set_note_previews(enable);
self self
@@ -153,7 +158,7 @@ impl<'a> Note<'a> {
&mut self.flags &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 note_key = self.note.key().expect("todo: implement non-db notes");
let txn = self.note.txn().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 .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")] #[cfg(feature = "profiling")]
puffin::profile_function!(); puffin::profile_function!();
let note_key = self.note.key().expect("todo: support non-db notes"); let note_key = self.note.key().expect("todo: support non-db notes");
let txn = self.note.txn().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 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 let response = ui
.with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| { .with_layout(egui::Layout::left_to_right(egui::Align::TOP), |ui| {
ui.spacing_mut().item_spacing.x = 16.0; self.pfp(note_key, &profile, ui);
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(),
));
}
}
ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| { ui.with_layout(egui::Layout::top_down(egui::Align::LEFT), |ui| {
ui.horizontal(|ui| { ui.horizontal(|ui| {

View File

@@ -7,6 +7,8 @@ bitflags! {
pub struct NoteOptions: u32 { pub struct NoteOptions: u32 {
const actionbar = 0b00000001; const actionbar = 0b00000001;
const note_previews = 0b00000010; const note_previews = 0b00000010;
const small_pfp = 0b00000100;
const wide = 0b00001000;
} }
} }
@@ -21,6 +23,24 @@ impl NoteOptions {
(self & NoteOptions::note_previews) == NoteOptions::note_previews (self & NoteOptions::note_previews) == NoteOptions::note_previews
} }
#[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] #[inline]
pub fn set_note_previews(&mut self, enable: bool) { pub fn set_note_previews(&mut self, enable: bool) {
if enable { if enable {

View File

@@ -120,7 +120,6 @@ fn add_column_button(dark_mode: bool) -> egui::Button<'static> {
mod preview { mod preview {
use crate::{ use crate::{
test_data, test_data,
ui::{Preview, PreviewConfig}, ui::{Preview, PreviewConfig},