notedeck

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

ui.rs (4113B)


      1 use crate::event::ConnectionState;
      2 use crate::event::LoadingState;
      3 use egui::Color32;
      4 use egui::Label;
      5 use egui::RichText;
      6 use egui::Widget;
      7 use notedeck::AppContext;
      8 use std::collections::HashMap;
      9 
     10 pub fn note_hover_ui(
     11     ui: &mut egui::Ui,
     12     label: &str,
     13     ctx: &mut AppContext,
     14     invoice_notes: &HashMap<String, [u8; 32]>,
     15 ) -> Option<notedeck::NoteAction> {
     16     let zap_req_id = invoice_notes.get(label)?;
     17 
     18     let Ok(txn) = nostrdb::Transaction::new(ctx.ndb) else {
     19         return None;
     20     };
     21 
     22     let Ok(zapreq_note) = ctx.ndb.get_note_by_id(&txn, zap_req_id) else {
     23         return None;
     24     };
     25 
     26     for tag in zapreq_note.tags() {
     27         let Some("e") = tag.get_str(0) else {
     28             continue;
     29         };
     30 
     31         let Some(target_id) = tag.get_id(1) else {
     32             continue;
     33         };
     34 
     35         let Ok(note) = ctx.ndb.get_note_by_id(&txn, target_id) else {
     36             return None;
     37         };
     38 
     39         let author = ctx
     40             .ndb
     41             .get_profile_by_pubkey(&txn, zapreq_note.pubkey())
     42             .ok();
     43 
     44         // TODO(jb55): make this less horrible
     45         let mut note_context = notedeck::NoteContext {
     46             ndb: ctx.ndb,
     47             accounts: ctx.accounts,
     48             img_cache: ctx.img_cache,
     49             note_cache: ctx.note_cache,
     50             zaps: ctx.zaps,
     51             pool: ctx.pool,
     52             jobs: ctx.media_jobs.sender(),
     53             unknown_ids: ctx.unknown_ids,
     54             clipboard: ctx.clipboard,
     55             i18n: ctx.i18n,
     56             global_wallet: ctx.global_wallet,
     57         };
     58 
     59         let options = notedeck_ui::NoteOptions::default();
     60 
     61         notedeck_ui::ProfilePic::from_profile_or_default(
     62             note_context.img_cache,
     63             note_context.jobs,
     64             author.as_ref(),
     65         )
     66         .ui(ui);
     67 
     68         let nostr_name = notedeck::name::get_display_name(author.as_ref());
     69         ui.label(format!("{} zapped you", nostr_name.name()));
     70 
     71         return notedeck_ui::NoteView::new(&mut note_context, &note, options)
     72             .preview_style()
     73             .hide_media(true)
     74             .show(ui)
     75             .action;
     76     }
     77 
     78     None
     79 }
     80 
     81 pub fn get_info_ui(ui: &mut egui::Ui, info: &LoadingState<String, lnsocket::Error>) {
     82     ui.horizontal_wrapped(|ui| match info {
     83         LoadingState::Loading => {}
     84         LoadingState::Failed(err) => {
     85             ui.label(format!("failed to fetch node info: {err}"));
     86         }
     87         LoadingState::Loaded(info) => {
     88             ui.add(Label::new(info).wrap_mode(egui::TextWrapMode::Wrap));
     89         }
     90     });
     91 }
     92 
     93 pub fn connection_state_ui(ui: &mut egui::Ui, state: &ConnectionState) {
     94     match state {
     95         ConnectionState::Active => {
     96             ui.add(Label::new(RichText::new("Connected").color(Color32::GREEN)));
     97         }
     98 
     99         ConnectionState::Connecting => {
    100             ui.add(Label::new(
    101                 RichText::new("Connecting").color(Color32::YELLOW),
    102             ));
    103         }
    104 
    105         ConnectionState::Dead(reason) => {
    106             ui.add(Label::new(
    107                 RichText::new(format!("Disconnected: {reason}")).color(Color32::RED),
    108             ));
    109         }
    110     }
    111 }
    112 
    113 // ---------- helper ----------
    114 pub fn human_sat(msat: i64) -> String {
    115     let sats = msat / 1000;
    116     if sats >= 1_000_000 {
    117         format!("{:.1}M", sats as f64 / 1_000_000.0)
    118     } else if sats >= 1_000 {
    119         format!("{:.1}k", sats as f64 / 1_000.0)
    120     } else {
    121         sats.to_string()
    122     }
    123 }
    124 
    125 pub fn human_verbose_sat(msat: i64) -> String {
    126     if msat < 1_000 {
    127         // less than 1 sat
    128         format!("{msat} msat")
    129     } else {
    130         let sats = msat / 1_000;
    131         if sats < 100_000_000 {
    132             // less than 1 BTC
    133             format!("{sats} sat")
    134         } else {
    135             let btc = sats / 100_000_000;
    136             format!("{btc} BTC")
    137         }
    138     }
    139 }
    140 
    141 pub fn delta_str(new: i64, old: i64) -> String {
    142     let d = new - old;
    143     match d.cmp(&0) {
    144         std::cmp::Ordering::Greater => format!("↑ {}", human_sat(d)),
    145         std::cmp::Ordering::Less => format!("↓ {}", human_sat(-d)),
    146         std::cmp::Ordering::Equal => "·".into(),
    147     }
    148 }