Files
notedeck/crates/notedeck_columns/src/ui/profile/edit.rs
kernelkind 7d2112b472 make Widget impl ProfilePic mutably
Signed-off-by: kernelkind <kernelkind@gmail.com>
2025-05-04 12:57:54 -04:00

211 lines
6.3 KiB
Rust

use core::f32;
use crate::profile_state::ProfileState;
use egui::{vec2, Button, CornerRadius, Layout, Margin, RichText, ScrollArea, TextEdit};
use notedeck::{profile::unwrap_profile_url, Images, NotedeckTextStyle};
use notedeck_ui::{profile::banner, ProfilePic};
pub struct EditProfileView<'a> {
state: &'a mut ProfileState,
img_cache: &'a mut Images,
}
impl<'a> EditProfileView<'a> {
pub fn new(state: &'a mut ProfileState, img_cache: &'a mut Images) -> Self {
Self { state, img_cache }
}
// return true to save
pub fn ui(&mut self, ui: &mut egui::Ui) -> bool {
ScrollArea::vertical()
.show(ui, |ui| {
banner(ui, Some(&self.state.banner), 188.0);
let padding = 24.0;
notedeck_ui::padding(padding, ui, |ui| {
self.inner(ui, padding);
});
ui.separator();
let mut save = false;
notedeck_ui::padding(padding, ui, |ui| {
ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
if ui
.add(button("Save changes", 119.0).fill(notedeck_ui::colors::PINK))
.clicked()
{
save = true;
}
});
});
save
})
.inner
}
fn inner(&mut self, ui: &mut egui::Ui, padding: f32) {
ui.spacing_mut().item_spacing = egui::vec2(0.0, 16.0);
let mut pfp_rect = ui.available_rect_before_wrap();
let size = 80.0;
pfp_rect.set_width(size);
pfp_rect.set_height(size);
let pfp_rect = pfp_rect.translate(egui::vec2(0.0, -(padding + 2.0 + (size / 2.0))));
let pfp_url = unwrap_profile_url(if self.state.picture.is_empty() {
None
} else {
Some(&self.state.picture)
});
ui.put(
pfp_rect,
&mut ProfilePic::new(self.img_cache, pfp_url)
.size(size)
.border(ProfilePic::border_stroke(ui)),
);
in_frame(ui, |ui| {
ui.add(label("Display name"));
ui.add(singleline_textedit(&mut self.state.display_name));
});
in_frame(ui, |ui| {
ui.add(label("Username"));
ui.add(singleline_textedit(&mut self.state.name));
});
in_frame(ui, |ui| {
ui.add(label("Profile picture"));
ui.add(multiline_textedit(&mut self.state.picture));
});
in_frame(ui, |ui| {
ui.add(label("Banner"));
ui.add(multiline_textedit(&mut self.state.banner));
});
in_frame(ui, |ui| {
ui.add(label("About"));
ui.add(multiline_textedit(&mut self.state.about));
});
in_frame(ui, |ui| {
ui.add(label("Website"));
ui.add(singleline_textedit(&mut self.state.website));
});
in_frame(ui, |ui| {
ui.add(label("Lightning network address (lud16)"));
ui.add(multiline_textedit(&mut self.state.lud16));
});
in_frame(ui, |ui| {
ui.add(label("Nostr address (NIP-05 identity)"));
ui.add(singleline_textedit(&mut self.state.nip05));
let split = &mut self.state.nip05.split('@');
let prefix = split.next();
let suffix = split.next();
if let Some(prefix) = prefix {
if let Some(suffix) = suffix {
let use_domain = if let Some(f) = prefix.chars().next() {
f == '_'
} else {
false
};
ui.colored_label(
ui.visuals().noninteractive().fg_stroke.color,
RichText::new(if use_domain {
format!("\"{}\" will be used for identification", suffix)
} else {
format!(
"\"{}\" at \"{}\" will be used for identification",
prefix, suffix
)
}),
);
}
}
});
}
}
fn label(text: &str) -> impl egui::Widget + '_ {
move |ui: &mut egui::Ui| -> egui::Response {
ui.label(RichText::new(text).font(NotedeckTextStyle::Body.get_bolded_font(ui.ctx())))
}
}
fn singleline_textedit(data: &mut String) -> impl egui::Widget + '_ {
TextEdit::singleline(data)
.min_size(vec2(0.0, 40.0))
.vertical_align(egui::Align::Center)
.margin(Margin::symmetric(12, 10))
.desired_width(f32::INFINITY)
}
fn multiline_textedit(data: &mut String) -> impl egui::Widget + '_ {
TextEdit::multiline(data)
// .min_size(vec2(0.0, 40.0))
.vertical_align(egui::Align::TOP)
.margin(Margin::symmetric(12, 10))
.desired_width(f32::INFINITY)
.desired_rows(1)
}
fn in_frame(ui: &mut egui::Ui, contents: impl FnOnce(&mut egui::Ui)) {
egui::Frame::new().show(ui, |ui| {
ui.spacing_mut().item_spacing = egui::vec2(0.0, 8.0);
contents(ui);
});
}
fn button(text: &str, width: f32) -> egui::Button<'static> {
Button::new(text)
.corner_radius(CornerRadius::same(8))
.min_size(vec2(width, 40.0))
}
mod preview {
use notedeck::{App, AppAction};
use crate::{
profile_state::ProfileState,
test_data,
ui::{Preview, PreviewConfig},
};
use super::EditProfileView;
pub struct EditProfilePreivew {
state: ProfileState,
}
impl Default for EditProfilePreivew {
fn default() -> Self {
Self {
state: ProfileState::from_profile(&test_data::test_profile_record()),
}
}
}
impl App for EditProfilePreivew {
fn update(
&mut self,
ctx: &mut notedeck::AppContext<'_>,
ui: &mut egui::Ui,
) -> Option<AppAction> {
EditProfileView::new(&mut self.state, ctx.img_cache).ui(ui);
None
}
}
impl Preview for EditProfileView<'_> {
type Prev = EditProfilePreivew;
fn preview(_cfg: PreviewConfig) -> Self::Prev {
EditProfilePreivew::default()
}
}
}