commit 24633b84bb1e1067c6367c04fdc061927c2143e5
parent 863ccd866b90c59328e392e3729f43cc6588d62e
Author: William Casarin <jb55@jb55.com>
Date: Sun, 21 Apr 2024 16:49:49 -0700
ui: introduce profile picture widget
We are starting to use profile pics in different places, let's make it a
widget. We'll also probably need to have adjustable sizes and such soon.
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
4 files changed, 98 insertions(+), 72 deletions(-)
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
@@ -6,7 +6,7 @@ pub mod username;
pub use note::Note;
pub use preview::{Preview, PreviewApp};
-pub use profile::ProfilePreview;
+pub use profile::{ProfilePic, ProfilePreview};
pub use relay::RelayView;
pub use username::Username;
diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs
@@ -4,9 +4,8 @@ pub mod options;
pub use contents::NoteContents;
pub use options::NoteOptions;
-use crate::imgcache::ImageCache;
use crate::{colors, ui, Damus};
-use egui::{Label, RichText, Sense, TextureHandle, Vec2};
+use egui::{Label, RichText, Sense};
pub struct Note<'a> {
app: &'a mut Damus,
@@ -102,8 +101,15 @@ impl<'a> Note<'a> {
{
// these have different lifetimes and types,
// so the calls must be separate
- Some(pic) => render_pfp(ui, &mut self.app.img_cache, pic),
- None => render_pfp(ui, &mut self.app.img_cache, no_pfp_url()),
+ Some(pic) => {
+ ui.add(ui::ProfilePic::new(&mut self.app.img_cache, pic));
+ }
+ 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| {
@@ -161,73 +167,6 @@ fn render_note_actionbar(ui: &mut egui::Ui) -> egui::InnerResponse<()> {
})
}
-// TODO: move to widget
-fn render_pfp(ui: &mut egui::Ui, img_cache: &mut ImageCache, url: &str) {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
- let ui_size = 30.0;
-
- // We will want to downsample these so it's not blurry on hi res displays
- let img_size = (ui_size * 2.0) as u32;
-
- let m_cached_promise = img_cache.map().get(url);
- if m_cached_promise.is_none() {
- let res = crate::images::fetch_img(&img_cache, ui.ctx(), url, img_size);
- img_cache.map_mut().insert(url.to_owned(), res);
- }
-
- match img_cache.map()[url].ready() {
- None => {
- ui.add(egui::Spinner::new().size(ui_size));
- }
-
- // Failed to fetch profile!
- Some(Err(_err)) => {
- let m_failed_promise = img_cache.map().get(url);
- if m_failed_promise.is_none() {
- let no_pfp = crate::images::fetch_img(&img_cache, ui.ctx(), no_pfp_url(), img_size);
- img_cache.map_mut().insert(url.to_owned(), no_pfp);
- }
-
- match img_cache.map().get(url).unwrap().ready() {
- None => {
- paint_circle(ui, ui_size);
- }
- Some(Err(_e)) => {
- //error!("Image load error: {:?}", e);
- paint_circle(ui, ui_size);
- }
- Some(Ok(img)) => {
- pfp_image(ui, img, ui_size);
- }
- }
- }
- Some(Ok(img)) => {
- pfp_image(ui, img, ui_size);
- }
- }
-}
-
-fn pfp_image(ui: &mut egui::Ui, img: &TextureHandle, size: f32) -> egui::Response {
- #[cfg(feature = "profiling")]
- puffin::profile_function!();
-
- //img.show_max_size(ui, egui::vec2(size, size))
- ui.add(egui::Image::new(img).max_width(size))
- //.with_options()
-}
-
-fn no_pfp_url() -> &'static str {
- "https://damus.io/img/no-profile.svg"
-}
-
-fn paint_circle(ui: &mut egui::Ui, size: f32) {
- let (rect, _response) = ui.allocate_at_least(Vec2::new(size, size), Sense::hover());
- ui.painter()
- .circle_filled(rect.center(), size / 2.0, ui.visuals().weak_text_color());
-}
-
fn render_reltime(
ui: &mut egui::Ui,
note_cache: &mut crate::notecache::NoteCache,
diff --git a/src/ui/profile/mod.rs b/src/ui/profile/mod.rs
@@ -1,3 +1,5 @@
+pub mod picture;
pub mod preview;
+pub use picture::ProfilePic;
pub use preview::ProfilePreview;
diff --git a/src/ui/profile/picture.rs b/src/ui/profile/picture.rs
@@ -0,0 +1,85 @@
+use crate::imgcache::ImageCache;
+
+use egui::{vec2, Sense, TextureHandle};
+
+pub struct ProfilePic<'cache, 'url> {
+ cache: &'cache mut ImageCache,
+ url: &'url str,
+}
+
+impl<'cache, 'url> egui::Widget for ProfilePic<'cache, 'url> {
+ fn ui(self, ui: &mut egui::Ui) -> egui::Response {
+ render_pfp(ui, self.cache, self.url)
+ }
+}
+
+impl<'cache, 'url> ProfilePic<'cache, 'url> {
+ pub fn new(cache: &'cache mut ImageCache, url: &'url str) -> Self {
+ ProfilePic { cache, url }
+ }
+
+ pub fn no_pfp_url() -> &'static str {
+ "https://damus.io/img/no-profile.svg"
+ }
+}
+
+fn render_pfp(ui: &mut egui::Ui, img_cache: &mut ImageCache, url: &str) -> egui::Response {
+ #[cfg(feature = "profiling")]
+ puffin::profile_function!();
+
+ let ui_size = 30.0;
+
+ // We will want to downsample these so it's not blurry on hi res displays
+ let img_size = (ui_size * 2.0) as u32;
+
+ let m_cached_promise = img_cache.map().get(url);
+ if m_cached_promise.is_none() {
+ let res = crate::images::fetch_img(img_cache, ui.ctx(), url, img_size);
+ img_cache.map_mut().insert(url.to_owned(), res);
+ }
+
+ match img_cache.map()[url].ready() {
+ None => ui.add(egui::Spinner::new().size(ui_size)),
+
+ // Failed to fetch profile!
+ Some(Err(_err)) => {
+ let m_failed_promise = img_cache.map().get(url);
+ if m_failed_promise.is_none() {
+ let no_pfp = crate::images::fetch_img(
+ img_cache,
+ ui.ctx(),
+ ProfilePic::no_pfp_url(),
+ img_size,
+ );
+ img_cache.map_mut().insert(url.to_owned(), no_pfp);
+ }
+
+ match img_cache.map().get(url).unwrap().ready() {
+ None => paint_circle(ui, ui_size),
+ Some(Err(_e)) => {
+ //error!("Image load error: {:?}", e);
+ paint_circle(ui, ui_size)
+ }
+ Some(Ok(img)) => pfp_image(ui, img, ui_size),
+ }
+ }
+ Some(Ok(img)) => pfp_image(ui, img, ui_size),
+ }
+}
+
+fn pfp_image(ui: &mut egui::Ui, img: &TextureHandle, size: f32) -> egui::Response {
+ #[cfg(feature = "profiling")]
+ puffin::profile_function!();
+
+ //img.show_max_size(ui, egui::vec2(size, size))
+ ui.add(egui::Image::new(img).max_width(size))
+ //.with_options()
+}
+
+fn paint_circle(ui: &mut egui::Ui, size: f32) -> egui::Response {
+ let (rect, response) = ui.allocate_at_least(vec2(size, size), Sense::hover());
+ ui.painter()
+ .circle_filled(rect.center(), size / 2.0, ui.visuals().weak_text_color());
+
+ response
+}