notedeck

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

edit.rs (6284B)


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