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, ¬e, 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 }