profile view improvements
Signed-off-by: kernelkind <kernelkind@gmail.com>
This commit is contained in:
BIN
assets/icons/key_4x.png
Normal file
BIN
assets/icons/key_4x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 KiB |
BIN
assets/icons/links_4x.png
Normal file
BIN
assets/icons/links_4x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/icons/verified_4x.png
Normal file
BIN
assets/icons/verified_4x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.3 KiB |
BIN
assets/icons/zap_4x.png
Normal file
BIN
assets/icons/zap_4x.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 KiB |
@@ -3,3 +3,4 @@ use egui::Color32;
|
|||||||
pub const ALMOST_WHITE: Color32 = Color32::from_rgb(0xFA, 0xFA, 0xFA);
|
pub const ALMOST_WHITE: Color32 = Color32::from_rgb(0xFA, 0xFA, 0xFA);
|
||||||
pub const MID_GRAY: Color32 = Color32::from_rgb(0xbd, 0xbd, 0xbd);
|
pub const MID_GRAY: Color32 = Color32::from_rgb(0xbd, 0xbd, 0xbd);
|
||||||
pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
|
pub const PINK: Color32 = Color32::from_rgb(0xE4, 0x5A, 0xC9);
|
||||||
|
pub const TEAL: Color32 = Color32::from_rgb(0x77, 0xDC, 0xE1);
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use crate::ui::note::NoteOptions;
|
|||||||
use crate::{colors, images};
|
use crate::{colors, images};
|
||||||
use crate::{notes_holder::NotesHolder, NostrName};
|
use crate::{notes_holder::NotesHolder, NostrName};
|
||||||
use egui::load::TexturePoll;
|
use egui::load::TexturePoll;
|
||||||
use egui::{Label, RichText, ScrollArea, Sense};
|
use egui::{Label, RichText, Rounding, ScrollArea, Sense, Stroke};
|
||||||
use enostr::Pubkey;
|
use enostr::Pubkey;
|
||||||
use nostrdb::{Ndb, ProfileRecord, Transaction};
|
use nostrdb::{Ndb, ProfileRecord, Transaction};
|
||||||
pub use picture::ProfilePic;
|
pub use picture::ProfilePic;
|
||||||
@@ -112,26 +112,116 @@ impl<'a> ProfileView<'a> {
|
|||||||
pfp_rect,
|
pfp_rect,
|
||||||
ProfilePic::new(self.img_cache, get_profile_url(Some(&profile))).size(size),
|
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(display_name_widget(get_display_name(Some(&profile)), false));
|
||||||
|
|
||||||
|
ui.add_space(8.0);
|
||||||
|
|
||||||
ui.add(about_section_widget(&profile));
|
ui.add(about_section_widget(&profile));
|
||||||
|
|
||||||
if let Some(website_url) = profile.record().profile().and_then(|p| p.website()) {
|
ui.horizontal_wrapped(|ui| {
|
||||||
if ui
|
if let Some(website_url) = profile
|
||||||
.label(RichText::new(website_url).color(colors::PINK))
|
.record()
|
||||||
.on_hover_cursor(egui::CursorIcon::PointingHand)
|
.profile()
|
||||||
.interact(Sense::click())
|
.and_then(|p| p.website())
|
||||||
.clicked()
|
.filter(|s| !s.is_empty())
|
||||||
{
|
{
|
||||||
if let Err(e) = open::that(website_url) {
|
handle_link(ui, website_url);
|
||||||
error!("Failed to open URL {} because: {}", website_url, e);
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
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 + '_ {
|
fn display_name_widget(name: NostrName<'_>, add_placeholder_space: bool) -> impl egui::Widget + '_ {
|
||||||
move |ui: &mut egui::Ui| -> egui::Response {
|
move |ui: &mut egui::Ui| -> egui::Response {
|
||||||
let disp_resp = name.display_name.map(|disp_name| {
|
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),
|
.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 {
|
let (username_resp, nip05_resp) = ui
|
||||||
if let Some(username_resp) = username_resp {
|
.horizontal(|ui| {
|
||||||
username_resp
|
let username_resp = name.username.map(|username| {
|
||||||
} else {
|
ui.add(
|
||||||
disp_resp
|
Label::new(
|
||||||
}
|
RichText::new(format!("@{}", username))
|
||||||
} else {
|
.size(16.0)
|
||||||
ui.add(Label::new(RichText::new(name.name())))
|
.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 {
|
if add_placeholder_space {
|
||||||
@@ -185,7 +290,9 @@ where
|
|||||||
{
|
{
|
||||||
move |ui: &mut egui::Ui| {
|
move |ui: &mut egui::Ui| {
|
||||||
if let Some(about) = profile.record().profile().and_then(|p| p.about()) {
|
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 {
|
} else {
|
||||||
// need any Response so we dont need an Option
|
// need any Response so we dont need an Option
|
||||||
ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover())
|
ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover())
|
||||||
|
|||||||
Reference in New Issue
Block a user