notedeck

One damus client to rule them all
git clone git://jb55.com/notedeck
Log | Files | Refs | README | LICENSE

edit.rs (7446B)


      1 use core::f32;
      2 
      3 use egui::{vec2, Button, CornerRadius, Layout, Margin, RichText, ScrollArea, TextEdit};
      4 use enostr::ProfileState;
      5 use notedeck::{profile::unwrap_profile_url, tr, Images, Localization, NotedeckTextStyle};
      6 use notedeck_ui::{profile::banner, ProfilePic};
      7 
      8 pub struct EditProfileView<'a> {
      9     state: &'a mut ProfileState,
     10     img_cache: &'a mut Images,
     11     i18n: &'a mut Localization,
     12 }
     13 
     14 impl<'a> EditProfileView<'a> {
     15     pub fn new(
     16         i18n: &'a mut Localization,
     17         state: &'a mut ProfileState,
     18         img_cache: &'a mut Images,
     19     ) -> Self {
     20         Self {
     21             i18n,
     22             state,
     23             img_cache,
     24         }
     25     }
     26 
     27     // return true to save
     28     pub fn ui(&mut self, ui: &mut egui::Ui) -> bool {
     29         ScrollArea::vertical()
     30             .show(ui, |ui| {
     31                 banner(ui, self.state.banner(), 188.0);
     32 
     33                 let padding = 24.0;
     34                 notedeck_ui::padding(padding, ui, |ui| {
     35                     self.inner(ui, padding);
     36                 });
     37 
     38                 ui.separator();
     39 
     40                 let mut save = false;
     41                 notedeck_ui::padding(padding, ui, |ui| {
     42                     ui.with_layout(Layout::right_to_left(egui::Align::Center), |ui| {
     43                         if ui
     44                             .add(
     45                                 button(
     46                                     tr!(
     47                                         self.i18n,
     48                                         "Save changes",
     49                                         "Button label to save profile changes"
     50                                     )
     51                                     .as_str(),
     52                                     119.0,
     53                                 )
     54                                 .fill(notedeck_ui::colors::PINK),
     55                             )
     56                             .clicked()
     57                         {
     58                             save = true;
     59                         }
     60                     });
     61                 });
     62 
     63                 save
     64             })
     65             .inner
     66     }
     67 
     68     fn inner(&mut self, ui: &mut egui::Ui, padding: f32) {
     69         ui.spacing_mut().item_spacing = egui::vec2(0.0, 16.0);
     70         let mut pfp_rect = ui.available_rect_before_wrap();
     71         let size = 80.0;
     72         pfp_rect.set_width(size);
     73         pfp_rect.set_height(size);
     74         let pfp_rect = pfp_rect.translate(egui::vec2(0.0, -(padding + 2.0 + (size / 2.0))));
     75 
     76         let pfp_url = unwrap_profile_url(self.state.picture());
     77         ui.put(
     78             pfp_rect,
     79             &mut ProfilePic::new(self.img_cache, pfp_url)
     80                 .size(size)
     81                 .border(ProfilePic::border_stroke(ui)),
     82         );
     83 
     84         in_frame(ui, |ui| {
     85             ui.add(label(
     86                 tr!(
     87                     self.i18n,
     88                     "Display name",
     89                     "Profile display name field label"
     90                 )
     91                 .as_str(),
     92             ));
     93             ui.add(singleline_textedit(self.state.str_mut("display_name")));
     94         });
     95 
     96         in_frame(ui, |ui| {
     97             ui.add(label(
     98                 tr!(self.i18n, "Username", "Profile username field label").as_str(),
     99             ));
    100             ui.add(singleline_textedit(self.state.str_mut("name")));
    101         });
    102 
    103         in_frame(ui, |ui| {
    104             ui.add(label(
    105                 tr!(
    106                     self.i18n,
    107                     "Profile picture",
    108                     "Profile picture URL field label"
    109                 )
    110                 .as_str(),
    111             ));
    112             ui.add(multiline_textedit(self.state.str_mut("picture")));
    113         });
    114 
    115         in_frame(ui, |ui| {
    116             ui.add(label(
    117                 tr!(self.i18n, "Banner", "Profile banner URL field label").as_str(),
    118             ));
    119             ui.add(multiline_textedit(self.state.str_mut("banner")));
    120         });
    121 
    122         in_frame(ui, |ui| {
    123             ui.add(label(
    124                 tr!(self.i18n, "About", "Profile about/bio field label").as_str(),
    125             ));
    126             ui.add(multiline_textedit(self.state.str_mut("about")));
    127         });
    128 
    129         in_frame(ui, |ui| {
    130             ui.add(label(
    131                 tr!(self.i18n, "Website", "Profile website field label").as_str(),
    132             ));
    133             ui.add(singleline_textedit(self.state.str_mut("website")));
    134         });
    135 
    136         in_frame(ui, |ui| {
    137             ui.add(label(
    138                 tr!(
    139                     self.i18n,
    140                     "Lightning network address (lud16)",
    141                     "Bitcoin Lightning network address field label"
    142                 )
    143                 .as_str(),
    144             ));
    145             ui.add(multiline_textedit(self.state.str_mut("lud16")));
    146         });
    147 
    148         in_frame(ui, |ui| {
    149             ui.add(label(
    150                 tr!(
    151                     self.i18n,
    152                     "Nostr address (NIP-05 identity)",
    153                     "NIP-05 identity field label"
    154                 )
    155                 .as_str(),
    156             ));
    157             ui.add(singleline_textedit(self.state.str_mut("nip05")));
    158 
    159             let Some(nip05) = self.state.nip05() else {
    160                 return;
    161             };
    162 
    163             let mut split = nip05.split('@');
    164 
    165             let Some(prefix) = split.next() else {
    166                 return;
    167             };
    168             let Some(suffix) = split.next() else {
    169                 return;
    170             };
    171 
    172             let use_domain = if let Some(f) = prefix.chars().next() {
    173                 f == '_'
    174             } else {
    175                 false
    176             };
    177             ui.colored_label(
    178                 ui.visuals().noninteractive().fg_stroke.color,
    179                 RichText::new(if use_domain {
    180                     tr!(
    181                         self.i18n,
    182                         "\"{domain}\" will be used for identification",
    183                         "Domain identification message",
    184                         domain = suffix
    185                     )
    186                 } else {
    187                     tr!(
    188                         self.i18n,
    189                         "\"{username}\" at \"{domain}\" will be used for identification",
    190                         "Username and domain identification message",
    191                         username = prefix,
    192                         domain = suffix
    193                     )
    194                 }),
    195             );
    196         });
    197     }
    198 }
    199 
    200 fn label(text: &str) -> impl egui::Widget + '_ {
    201     move |ui: &mut egui::Ui| -> egui::Response {
    202         ui.label(RichText::new(text).font(NotedeckTextStyle::Body.get_bolded_font(ui.ctx())))
    203     }
    204 }
    205 
    206 fn singleline_textedit(data: &mut String) -> impl egui::Widget + '_ {
    207     TextEdit::singleline(data)
    208         .min_size(vec2(0.0, 40.0))
    209         .vertical_align(egui::Align::Center)
    210         .margin(Margin::symmetric(12, 10))
    211         .desired_width(f32::INFINITY)
    212 }
    213 
    214 fn multiline_textedit(data: &mut String) -> impl egui::Widget + '_ {
    215     TextEdit::multiline(data)
    216         // .min_size(vec2(0.0, 40.0))
    217         .vertical_align(egui::Align::TOP)
    218         .margin(Margin::symmetric(12, 10))
    219         .desired_width(f32::INFINITY)
    220         .desired_rows(1)
    221 }
    222 
    223 fn in_frame(ui: &mut egui::Ui, contents: impl FnOnce(&mut egui::Ui)) {
    224     egui::Frame::new().show(ui, |ui| {
    225         ui.spacing_mut().item_spacing = egui::vec2(0.0, 8.0);
    226         contents(ui);
    227     });
    228 }
    229 
    230 fn button(text: &str, width: f32) -> egui::Button<'static> {
    231     Button::new(text)
    232         .corner_radius(CornerRadius::same(8))
    233         .min_size(vec2(width, 40.0))
    234 }