commit e8168b0004fb994b27b9f8a9cab368229f9132ec
parent 61deeb03e1aa15ebe3198033b135acea37e80d8c
Author: William Casarin <jb55@jb55.com>
Date: Tue, 23 Apr 2024 18:20:20 -0700
ui: add profile picture hover animation
I wanted to practice doing animation in egui, so here is a simple
profile picture hover affect. When you mouse over a profile picture, it
get slightly bigger.
Signed-off-by: William Casarin <jb55@jb55.com>
Diffstat:
6 files changed, 69 insertions(+), 4 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -2557,7 +2557,7 @@ dependencies = [
[[package]]
name = "nostrdb"
version = "0.3.2"
-source = "git+https://github.com/damus-io/nostrdb-rs?rev=b6c5d8fb9f3f79f14d69dd2d6eca2712e0f0a42d#b6c5d8fb9f3f79f14d69dd2d6eca2712e0f0a42d"
+source = "git+https://github.com/damus-io/nostrdb-rs?rev=01d8bee4fea6e2e8f6bc3e4e6e3c989e43defe4b#01d8bee4fea6e2e8f6bc3e4e6e3c989e43defe4b"
dependencies = [
"bindgen",
"cc",
diff --git a/Cargo.toml b/Cargo.toml
@@ -31,7 +31,7 @@ serde_json = "1.0.89"
env_logger = "0.10.0"
puffin_egui = { version = "0.27.0", optional = true }
puffin = { version = "0.19.0", optional = true }
-nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "b6c5d8fb9f3f79f14d69dd2d6eca2712e0f0a42d" }
+nostrdb = { git = "https://github.com/damus-io/nostrdb-rs", rev = "01d8bee4fea6e2e8f6bc3e4e6e3c989e43defe4b" }
#nostrdb = "0.3.2"
hex = "0.4.3"
base32 = "0.4.0"
diff --git a/src/ui/anim.rs b/src/ui/anim.rs
@@ -0,0 +1,19 @@
+pub fn hover_expand(
+ ui: &mut egui::Ui,
+ id: egui::Id,
+ size: f32,
+ expand_size: f32,
+ anim_speed: f32,
+) -> (egui::Rect, f32) {
+ // Allocate space for the profile picture with a fixed size
+ let default_size = size + expand_size;
+ let (rect, response) =
+ ui.allocate_exact_size(egui::vec2(default_size, default_size), egui::Sense::hover());
+
+ let val = ui
+ .ctx()
+ .animate_bool_with_time(id, response.hovered(), anim_speed);
+
+ let size = size + val * expand_size;
+ (rect, size)
+}
diff --git a/src/ui/mod.rs b/src/ui/mod.rs
@@ -1,3 +1,4 @@
+pub mod anim;
pub mod note;
pub mod preview;
pub mod profile;
diff --git a/src/ui/note/mod.rs b/src/ui/note/mod.rs
@@ -6,6 +6,7 @@ pub use options::NoteOptions;
use crate::{colors, ui, Damus};
use egui::{Label, RichText, Sense};
+use std::hash::{Hash, Hasher};
pub struct Note<'a> {
app: &'a mut Damus,
@@ -23,6 +24,20 @@ impl<'a> egui::Widget for Note<'a> {
}
}
+#[derive(Eq, PartialEq, Debug, Clone, Copy)]
+struct ProfileAnimId {
+ profile_key: u64,
+ note_key: u64,
+}
+
+impl Hash for ProfileAnimId {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ state.write_u8(0x12);
+ self.profile_key.hash(state);
+ self.note_key.hash(state);
+ }
+}
+
impl<'a> Note<'a> {
pub fn new(app: &'a mut Damus, note: &'a nostrdb::Note<'a>) -> Self {
let flags = NoteOptions::actionbar | NoteOptions::note_previews;
@@ -104,7 +119,33 @@ impl<'a> Note<'a> {
// these have different lifetimes and types,
// so the calls must be separate
Some(pic) => {
- ui.add(ui::ProfilePic::new(&mut self.app.img_cache, 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();
+
+ 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(
diff --git a/src/ui/profile/picture.rs b/src/ui/profile/picture.rs
@@ -16,10 +16,14 @@ impl<'cache, 'url> egui::Widget for ProfilePic<'cache, 'url> {
impl<'cache, 'url> ProfilePic<'cache, 'url> {
pub fn new(cache: &'cache mut ImageCache, url: &'url str) -> Self {
- let size = 32.0;
+ let size = Self::default_size();
ProfilePic { cache, url, size }
}
+ pub fn default_size() -> f32 {
+ 32.0
+ }
+
pub fn no_pfp_url() -> &'static str {
"https://damus.io/img/no-profile.svg"
}