notedeck

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

edit.rs (7579B)


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