From 45d07cc432e0b7a365c72ffeebb8b01e196eefe8 Mon Sep 17 00:00:00 2001 From: kernelkind Date: Wed, 1 Jan 2025 22:45:28 -0500 Subject: [PATCH] profile view improvements Signed-off-by: kernelkind --- assets/icons/key_4x.png | Bin 0 -> 1446 bytes assets/icons/links_4x.png | Bin 0 -> 1332 bytes assets/icons/verified_4x.png | Bin 0 -> 3376 bytes assets/icons/zap_4x.png | Bin 0 -> 1122 bytes crates/notedeck_columns/src/colors.rs | 1 + crates/notedeck_columns/src/ui/profile/mod.rs | 167 ++++++++++++++---- 6 files changed, 138 insertions(+), 30 deletions(-) create mode 100644 assets/icons/key_4x.png create mode 100644 assets/icons/links_4x.png create mode 100644 assets/icons/verified_4x.png create mode 100644 assets/icons/zap_4x.png diff --git a/assets/icons/key_4x.png b/assets/icons/key_4x.png new file mode 100644 index 0000000000000000000000000000000000000000..6c4f9d70ff39191f876d5c9c55b6d422806f3ce6 GIT binary patch literal 1446 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�IfDgX$Mg%vR7X&NFGU&twEFBF=f~&DGjws2k ztALE)z7Qn5AzY_2y(8#zCbe_P$wHJOQk6`g<;W`OiFWtx=>dQ}q1_=2m6qarm1 z;IT})s{l@rRg1_#erlTcieRJqZWM4Digb=IYC$uNB5|+0cKTqhQ$ci9T9N_G4#kzr zC87y}x@(n8U5Z@M0s_4SXoq z_y)h0OPhJAhpgUGMN4n*dYsUJYv86qfIhx&MATZ4fW0UbT`W@n305C+=!l-jp#>)X zCjDQ~V>gR|`B}-Ha$TCzX(VGeXyZ6;muN*b5ov3NJ4D4ErlNs22TEO!%WiG-?pFnv%Rgpgl>EYvF)$#h~}a=8@YbzIclT3W!Q&k@=_! z!#f$Cm+(9;>OngaH=3u%;>{-dw3konLhkZ>T5R~;?cJpOpOKE`I z6ecP|NUA8*vnP8!^oyHrXqT8OfKiI$>sGdf{!Fe5GpF@kV0AsmC9?yIOZhchmXI%1 z9!e=vy(Y>t(F9a`atsDlUsG42r`9>Y4f+Pc8sol@mpbQLz`ur=O57-GLw1iv!`GH0 z2l;&k$PW|x^V+JmOn)5bzLb-Bds*X9%~*Xmx#&P0o(jNz=RC|mxutn>{C8rw5iVQ z%{R5-GRIH=SI?V*c?RY&C+azQCaw2`IpQ%b4aViCw|sUUh8#l!jG-iK zHlILo;|HmfRLTdrlLJ-zzb}SCH772OWikQ601Z8X0gEug8108Zy_LOHL7L+jNifDN zDUE&k=Oa+vFPd3e?ts>s1~l|TR)$v3kpaGR$6W^lakG}`3|C{0b zTj6xCI3UVuDN>X6B=aT3$%D^qxpg;;IED@r{o~t54z?apl%Aw?s^uZVxo2-39bBRXK7euGkpoi~pfTNWa4#@n|7s8{ zyl~s+7B6T1%p0%m@G&KHxJi=DL&06o&tD=-`DlC?#(x1uQD=_bhjml{0000@~0drDELIAGL9O(c600d`2O+f$vv5yPg7|Gd)nm(a{K2Vk;{fCR_)TU%R)E1$)7);R!^MSz&&*H?JZ-YLg1 z%>kIs0;D*;u)O7@w$?cS)29xkI6h2oRxd}O4#G%(vW;Vos5_p2Qq~pMHo@TdKeT#w ze3+iNws(7bJ4gKvmFEJ}Zvr9IOY2%wAeQ3?#~(M;JF;OE{7I#?0BbnDgd;l+uCA_j zw93{3v~_%iSbbJ-P6M@$TCk?$OPtXwA=w0Dt2)8)r<8uY!Qy8djJrAfaB=B zTvZ>nj!6=ri{qCj7&4#Rd!@+*(rfkZGdcyjI(|u3?mx8Pd7p98bc`zU1vwnQ7??ub zF;1yoZn8GsUN;JW;7_Q#;}-#)a}t^Nhn+IPhFjKu@X*h6_r^kA;$)ML6?T=UT0QC} zFyy3_XjOpl(83AXF@ae{Px|`$`T)YKp49egw9)4SY8=NJ@Tf%aO{wjyP4J8=fc4@e zMbhI$$3LQ$r~*LAJG{)u4&PLn!|^2=rvNJov%4e%nifNHIle^Wf=EzwgcF!PJUlpj zk)!T>A>n=kLVKxkaC|kjmui2`f&?8?O?ZxC(45 z<$m=;3CEW(7XU$tE{@*x%lD-mU&34fzIBz#u_fl0?@Kwpg!w~Kr1a|2#Y;NAcs#Pj zDdnDjr8s_@dxjLO1rU3ma{vp+m#}_JP9547jxW(^XJ`$aR2bPL$>#VH)>B}+W&5m- zFJUTxmIG+yc6{+W$Pg_DkSO8!5|)q3syRTNQjRZSIRac_yJC(nVJSdL?-zA^2{Qqj za)3Z_$Cr3DQ^3OU#qT8}nl6D>jxS**04{;z(6)4Z2{QpO#5qX6TE+{mmX0rB`k$k` o(u2j0ad;-+XUa~{8*h~5FYJw7dx4G>CIA2c07*qoM6N<$f{PdjN&o-= literal 0 HcmV?d00001 diff --git a/crates/notedeck_columns/src/colors.rs b/crates/notedeck_columns/src/colors.rs index ef3b1d86..36f507bf 100644 --- a/crates/notedeck_columns/src/colors.rs +++ b/crates/notedeck_columns/src/colors.rs @@ -3,3 +3,4 @@ use egui::Color32; pub const ALMOST_WHITE: Color32 = Color32::from_rgb(0xFA, 0xFA, 0xFA); pub const MID_GRAY: Color32 = Color32::from_rgb(0xbd, 0xbd, 0xbd); pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9); +pub const TEAL: Color32 = Color32::from_rgb(0x77, 0xDC, 0xE1); diff --git a/crates/notedeck_columns/src/ui/profile/mod.rs b/crates/notedeck_columns/src/ui/profile/mod.rs index 6632aa3d..51070f02 100644 --- a/crates/notedeck_columns/src/ui/profile/mod.rs +++ b/crates/notedeck_columns/src/ui/profile/mod.rs @@ -6,7 +6,7 @@ use crate::ui::note::NoteOptions; use crate::{colors, images}; use crate::{notes_holder::NotesHolder, NostrName}; use egui::load::TexturePoll; -use egui::{Label, RichText, ScrollArea, Sense}; +use egui::{Label, RichText, Rounding, ScrollArea, Sense, Stroke}; use enostr::Pubkey; use nostrdb::{Ndb, ProfileRecord, Transaction}; pub use picture::ProfilePic; @@ -112,26 +112,116 @@ impl<'a> ProfileView<'a> { pfp_rect, ProfilePic::new(self.img_cache, get_profile_url(Some(&profile))).size(size), ); + + if ui.add(copy_key_widget(&pfp_rect)).clicked() { + ui.output_mut(|w| { + w.copied_text = if let Some(bech) = self.pubkey.to_bech() { + bech + } else { + error!("Could not convert Pubkey to bech"); + String::new() + } + }); + } + + ui.add_space(18.0); + ui.add(display_name_widget(get_display_name(Some(&profile)), false)); + + ui.add_space(8.0); + ui.add(about_section_widget(&profile)); - if let Some(website_url) = profile.record().profile().and_then(|p| p.website()) { - if ui - .label(RichText::new(website_url).color(colors::PINK)) - .on_hover_cursor(egui::CursorIcon::PointingHand) - .interact(Sense::click()) - .clicked() + ui.horizontal_wrapped(|ui| { + if let Some(website_url) = profile + .record() + .profile() + .and_then(|p| p.website()) + .filter(|s| !s.is_empty()) { - if let Err(e) = open::that(website_url) { - error!("Failed to open URL {} because: {}", website_url, e); - }; + handle_link(ui, website_url); } - } + + if let Some(lud16) = profile + .record() + .profile() + .and_then(|p| p.lud16()) + .filter(|s| !s.is_empty()) + { + handle_lud16(ui, lud16); + } + }); }); }); } } +fn handle_link(ui: &mut egui::Ui, website_url: &str) { + ui.image(egui::include_image!( + "../../../../../assets/icons/links_4x.png" + )); + if ui + .label(RichText::new(website_url).color(colors::PINK)) + .on_hover_cursor(egui::CursorIcon::PointingHand) + .interact(Sense::click()) + .clicked() + { + if let Err(e) = open::that(website_url) { + error!("Failed to open URL {} because: {}", website_url, e); + }; + } +} + +fn handle_lud16(ui: &mut egui::Ui, lud16: &str) { + ui.image(egui::include_image!( + "../../../../../assets/icons/zap_4x.png" + )); + + let _ = ui.label(RichText::new(lud16).color(colors::PINK)); +} + +fn copy_key_widget(pfp_rect: &egui::Rect) -> impl egui::Widget + '_ { + |ui: &mut egui::Ui| -> egui::Response { + let painter = ui.painter(); + let copy_key_rect = painter.round_rect_to_pixels(egui::Rect::from_center_size( + pfp_rect.center_bottom(), + egui::vec2(48.0, 28.0), + )); + let resp = ui.interact( + copy_key_rect, + ui.id().with("custom_painter"), + Sense::click(), + ); + + let copy_key_rounding = Rounding::same(100.0); + let fill_color = if resp.hovered() { + ui.visuals().widgets.inactive.weak_bg_fill + } else { + ui.visuals().noninteractive().bg_stroke.color + }; + painter.rect_filled(copy_key_rect, copy_key_rounding, fill_color); + + let stroke_color = ui.visuals().widgets.inactive.weak_bg_fill; + painter.rect_stroke( + copy_key_rect.shrink(1.0), + copy_key_rounding, + Stroke::new(1.0, stroke_color), + ); + egui::Image::new(egui::include_image!( + "../../../../../assets/icons/key_4x.png" + )) + .paint_at( + ui, + painter.round_rect_to_pixels(egui::Rect::from_center_size( + copy_key_rect.center(), + egui::vec2(16.0, 16.0), + )), + ); + + resp + } +} + fn display_name_widget(name: NostrName<'_>, add_placeholder_space: bool) -> impl egui::Widget + '_ { move |ui: &mut egui::Ui| -> egui::Response { let disp_resp = name.display_name.map(|disp_name| { @@ -142,25 +232,40 @@ fn display_name_widget(name: NostrName<'_>, add_placeholder_space: bool) -> impl .selectable(false), ) }); - let username_resp = name.username.map(|username| { - ui.add( - Label::new( - RichText::new(format!("@{}", username)) - .size(16.0) - .color(colors::MID_GRAY), - ) - .selectable(false), - ) - }); - let resp = if let Some(disp_resp) = disp_resp { - if let Some(username_resp) = username_resp { - username_resp - } else { - disp_resp - } - } else { - ui.add(Label::new(RichText::new(name.name()))) + let (username_resp, nip05_resp) = ui + .horizontal(|ui| { + let username_resp = name.username.map(|username| { + ui.add( + Label::new( + RichText::new(format!("@{}", username)) + .size(16.0) + .color(colors::MID_GRAY), + ) + .selectable(false), + ) + }); + + let nip05_resp = name.nip05.map(|nip05| { + ui.image(egui::include_image!( + "../../../../../assets/icons/verified_4x.png" + )); + ui.add(Label::new( + RichText::new(nip05).size(16.0).color(colors::TEAL), + )) + }); + + (username_resp, nip05_resp) + }) + .inner; + + let resp = match (disp_resp, username_resp, nip05_resp) { + (Some(disp), Some(username), Some(nip05)) => disp.union(username).union(nip05), + (Some(disp), Some(username), None) => disp.union(username), + (Some(disp), None, None) => disp, + (None, Some(username), Some(nip05)) => username.union(nip05), + (None, Some(username), None) => username, + _ => ui.add(Label::new(RichText::new(name.name()))), }; if add_placeholder_space { @@ -185,7 +290,9 @@ where { move |ui: &mut egui::Ui| { if let Some(about) = profile.record().profile().and_then(|p| p.about()) { - ui.label(about) + let resp = ui.label(about); + ui.add_space(8.0); + resp } else { // need any Response so we dont need an Option ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover())