notedeck

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

commit 2edba9942ca1de00ca0945b613f38a841afb0f49
parent 2f6f92e62c9e51e027b1f4d681cb20e8c92383ea
Author: William Casarin <jb55@jb55.com>
Date:   Sun, 21 Apr 2024 15:00:25 -0700

ui: add banners to profile previews

profile previews still need lots of work, but this was a challenge to
get an aspectRatio: fill mechanism for images which the banner takes
advantage of.

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

Diffstat:
Msrc/ui/note/contents.rs | 1+
Msrc/ui/profile/preview.rs | 75++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
2 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/src/ui/note/contents.rs b/src/ui/note/contents.rs @@ -139,6 +139,7 @@ fn render_note_contents( if let Some(rec) = profile.as_ref() { resp.on_hover_ui_at_pointer(|ui| { egui::Frame::default().show(ui, |ui| { + ui.set_max_width(300.0); ui.add(ui::ProfilePreview::new(rec)); }); }); diff --git a/src/ui/profile/preview.rs b/src/ui/profile/preview.rs @@ -1,25 +1,82 @@ +use crate::app_style::NotedeckTextStyle; +use crate::images; +use egui::load::TexturePoll; +use egui::{RichText, Sense}; +use egui_extras::Size; use nostrdb::ProfileRecord; pub struct ProfilePreview<'a> { profile: &'a ProfileRecord<'a>, + banner_height: Size, } impl<'a> ProfilePreview<'a> { pub fn new(profile: &'a ProfileRecord<'a>) -> Self { - ProfilePreview { profile } + let banner_height = Size::exact(80.0); + ProfilePreview { + profile, + banner_height, + } + } + + pub fn banner_height(&mut self, size: Size) { + self.banner_height = size; + } + + fn banner_texture( + ui: &mut egui::Ui, + profile: &ProfileRecord<'_>, + ) -> Option<egui::load::SizedTexture> { + // TODO: cache banner + let banner = profile.record().profile().and_then(|p| p.banner()); + + if let Some(banner) = banner { + let texture_load_res = + egui::Image::new(banner).load_for_size(ui.ctx(), ui.available_size()); + if let Ok(texture_poll) = texture_load_res { + match texture_poll { + TexturePoll::Pending { .. } => {} + TexturePoll::Ready { texture, .. } => return Some(texture), + } + } + } + + None + } + + fn banner(ui: &mut egui::Ui, profile: &ProfileRecord<'_>) -> egui::Response { + if let Some(texture) = Self::banner_texture(ui, profile) { + images::aspect_fill( + ui, + Sense::hover(), + texture.id, + texture.size.x / texture.size.y, + ) + } else { + // TODO: default banner texture + ui.label("") + } + } + + fn body(ui: &mut egui::Ui, profile: &ProfileRecord<'_>) -> egui::Response { + let name = if let Some(name) = crate::profile::get_profile_name(profile) { + name + } else { + "nostrich" + }; + + ui.label(RichText::new(name).text_style(NotedeckTextStyle::Heading3.text_style())) } } impl<'a> egui::Widget for ProfilePreview<'a> { fn ui(self, ui: &mut egui::Ui) -> egui::Response { - ui.horizontal(|ui| { - ui.label("Profile"); - let name = if let Some(name) = crate::profile::get_profile_name(self.profile) { - name - } else { - "nostrich" - }; - ui.label(name); + ui.vertical(|ui| { + ui.add_sized([ui.available_size().x, 80.0], |ui: &mut egui::Ui| { + ProfilePreview::banner(ui, self.profile) + }); + + ProfilePreview::body(ui, self.profile); }) .response }