notedeck

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

mod.rs (4660B)


      1 use nostrdb::ProfileRecord;
      2 
      3 pub mod name;
      4 pub mod picture;
      5 pub mod preview;
      6 
      7 pub use picture::ProfilePic;
      8 pub use preview::ProfilePreview;
      9 
     10 use egui::{load::TexturePoll, Label, RichText};
     11 use notedeck::{IsFollowing, NostrName, NotedeckTextStyle};
     12 
     13 use crate::{app_images, colors, widgets::styled_button_toggleable};
     14 
     15 pub fn display_name_widget<'a>(
     16     name: &'a NostrName<'a>,
     17     add_placeholder_space: bool,
     18 ) -> impl egui::Widget + 'a {
     19     move |ui: &mut egui::Ui| -> egui::Response {
     20         let disp_resp = name.display_name.map(|disp_name| {
     21             ui.add(
     22                 Label::new(
     23                     RichText::new(disp_name).text_style(NotedeckTextStyle::Heading3.text_style()),
     24                 )
     25                 .selectable(false),
     26             )
     27         });
     28 
     29         let (username_resp, nip05_resp) = ui
     30             .horizontal_wrapped(|ui| {
     31                 let username_resp = name.username.map(|username| {
     32                     ui.add(
     33                         Label::new(
     34                             RichText::new(format!("@{username}"))
     35                                 .size(16.0)
     36                                 .color(crate::colors::MID_GRAY),
     37                         )
     38                         .selectable(false),
     39                     )
     40                 });
     41 
     42                 if name.username.is_some() && name.nip05.is_some() {
     43                     ui.end_row();
     44                 }
     45 
     46                 let nip05_resp = name.nip05.map(|nip05| {
     47                     ui.horizontal(|ui| {
     48                         ui.spacing_mut().item_spacing.x = 2.0;
     49 
     50                         ui.add(app_images::verified_image());
     51 
     52                         ui.label(RichText::new(nip05).size(16.0).color(crate::colors::TEAL))
     53                             .on_hover_text(nip05)
     54                     })
     55                     .inner
     56                 });
     57 
     58                 (username_resp, nip05_resp)
     59             })
     60             .inner;
     61 
     62         let resp = match (disp_resp, username_resp, nip05_resp) {
     63             (Some(disp), Some(username), Some(nip05)) => disp.union(username).union(nip05),
     64             (Some(disp), Some(username), None) => disp.union(username),
     65             (Some(disp), None, None) => disp,
     66             (None, Some(username), Some(nip05)) => username.union(nip05),
     67             (None, Some(username), None) => username,
     68             _ => ui.add(Label::new(RichText::new(name.name()))),
     69         };
     70 
     71         if add_placeholder_space {
     72             ui.add_space(16.0);
     73         }
     74 
     75         resp
     76     }
     77 }
     78 
     79 pub fn about_section_widget<'a>(profile: Option<&'a ProfileRecord<'a>>) -> impl egui::Widget + 'a {
     80     move |ui: &mut egui::Ui| {
     81         if let Some(about) = profile
     82             .map(|p| p.record().profile())
     83             .and_then(|p| p.and_then(|p| p.about()))
     84         {
     85             let resp = ui.label(about);
     86             ui.add_space(8.0);
     87             resp
     88         } else {
     89             // need any Response so we dont need an Option
     90             ui.allocate_response(egui::Vec2::ZERO, egui::Sense::hover())
     91         }
     92     }
     93 }
     94 
     95 pub fn banner_texture(ui: &mut egui::Ui, banner_url: &str) -> Option<egui::load::SizedTexture> {
     96     // TODO: cache banner
     97     if !banner_url.is_empty() {
     98         let texture_load_res =
     99             egui::Image::new(banner_url).load_for_size(ui.ctx(), ui.available_size());
    100         if let Ok(texture_poll) = texture_load_res {
    101             match texture_poll {
    102                 TexturePoll::Pending { .. } => {}
    103                 TexturePoll::Ready { texture, .. } => return Some(texture),
    104             }
    105         }
    106     }
    107 
    108     None
    109 }
    110 
    111 pub fn banner(ui: &mut egui::Ui, banner_url: Option<&str>, height: f32) -> egui::Response {
    112     ui.add_sized([ui.available_size().x, height], |ui: &mut egui::Ui| {
    113         banner_url
    114             .and_then(|url| banner_texture(ui, url))
    115             .map(|texture| {
    116                 crate::images::aspect_fill(
    117                     ui,
    118                     egui::Sense::hover(),
    119                     texture.id,
    120                     texture.size.x / texture.size.y,
    121                 )
    122             })
    123             .unwrap_or_else(|| ui.label(""))
    124     })
    125 }
    126 
    127 pub fn follow_button(following: IsFollowing) -> impl egui::Widget + 'static {
    128     move |ui: &mut egui::Ui| -> egui::Response {
    129         let (bg_color, text) = match following {
    130             IsFollowing::Unknown => (ui.visuals().noninteractive().bg_fill, "Unknown"),
    131             IsFollowing::Yes => (ui.visuals().widgets.inactive.bg_fill, "Unfollow"),
    132             IsFollowing::No => (colors::PINK, "Follow"),
    133         };
    134 
    135         let enabled = following != IsFollowing::Unknown;
    136         ui.add(styled_button_toggleable(text, bg_color, enabled))
    137     }
    138 }